AuthController.java

  1. package no.nav.data.common.security;


  2. import io.swagger.v3.oas.annotations.Operation;
  3. import io.swagger.v3.oas.annotations.responses.ApiResponse;
  4. import io.swagger.v3.oas.annotations.responses.ApiResponses;
  5. import io.swagger.v3.oas.annotations.tags.Tag;
  6. import jakarta.servlet.http.Cookie;
  7. import jakarta.servlet.http.HttpServletRequest;
  8. import jakarta.servlet.http.HttpServletResponse;
  9. import lombok.RequiredArgsConstructor;
  10. import lombok.extern.slf4j.Slf4j;
  11. import no.nav.data.common.exceptions.TechnicalException;
  12. import no.nav.data.common.security.dto.OAuthState;
  13. import no.nav.data.common.security.dto.UserInfo;
  14. import no.nav.data.common.security.dto.UserInfoResponse;
  15. import org.springframework.http.ResponseEntity;
  16. import org.springframework.security.core.Authentication;
  17. import org.springframework.security.core.context.SecurityContextHolder;
  18. import org.springframework.security.web.DefaultRedirectStrategy;
  19. import org.springframework.security.web.RedirectStrategy;
  20. import org.springframework.util.Assert;
  21. import org.springframework.util.StringUtils;
  22. import org.springframework.web.bind.annotation.CrossOrigin;
  23. import org.springframework.web.bind.annotation.GetMapping;
  24. import org.springframework.web.bind.annotation.PostMapping;
  25. import org.springframework.web.bind.annotation.RequestMapping;
  26. import org.springframework.web.bind.annotation.RequestParam;
  27. import org.springframework.web.bind.annotation.RestController;
  28. import org.springframework.web.util.UriComponentsBuilder;

  29. import java.io.IOException;

  30. import static no.nav.data.common.security.SecurityConstants.COOKIE_NAME;
  31. import static no.nav.data.common.utils.Constants.SESSION_LENGTH;
  32. import static org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames.CODE;
  33. import static org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames.ERROR;
  34. import static org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames.ERROR_DESCRIPTION;
  35. import static org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames.ERROR_URI;
  36. import static org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames.REDIRECT_URI;
  37. import static org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames.STATE;
  38. import static org.springframework.security.web.util.UrlUtils.buildFullRequestUrl;

  39. @Slf4j
  40. @RestController
  41. @RequestMapping
  42. @RequiredArgsConstructor
  43. @Tag(name = "Auth")
  44. public class AuthController {

  45.     public static final String OAUTH_2_CALLBACK_URL = "/oauth2/callback";
  46.     private static final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

  47.     private final SecurityProperties securityProperties;
  48.     private final TokenProvider tokenProvider;
  49.     private final Encryptor encryptor;

  50.     @Operation(summary = "Login using sso")
  51.     @ApiResponses(value = {
  52.             @ApiResponse(responseCode = "302", description = "Redirect to sso")
  53.     })
  54.     @GetMapping("/login")
  55.     public void login(HttpServletRequest request, HttpServletResponse response,
  56.             @RequestParam(value = REDIRECT_URI, required = false) String redirectUri,
  57.             @RequestParam(value = ERROR_URI, required = false) String errorUri
  58.     ) throws IOException {
  59.         log.debug("Request to login");
  60.         Assert.isTrue(securityProperties.isValidRedirectUri(redirectUri), "Illegal redirect_uri " + redirectUri);
  61.         Assert.isTrue(securityProperties.isValidRedirectUri(errorUri), "Illegal error_uri " + errorUri);
  62.         var usedRedirect = redirectUri != null ? redirectUri : securityProperties.findBaseUrl();
  63.         String redirectUrl = tokenProvider.createAuthRequestRedirectUrl(usedRedirect, errorUri, callbackRedirectUri(request));
  64.         redirectStrategy.sendRedirect(request, response, redirectUrl);
  65.     }

  66.     @Operation(summary = "oidc callback")
  67.     @ApiResponses(value = {
  68.             @ApiResponse(responseCode = "302", description = "token accepted")
  69.     })
  70.     @CrossOrigin
  71.     @PostMapping(OAUTH_2_CALLBACK_URL)
  72.     public void oidc(HttpServletRequest request, HttpServletResponse response,
  73.                      @RequestParam(value = CODE, required = false) String code,
  74.                      @RequestParam(value = ERROR, required = false) String error,
  75.                      @RequestParam(value = ERROR_DESCRIPTION, required = false) String errorDesc,
  76.                      @RequestParam(STATE) String stateJson
  77.     ) throws IOException {
  78.         log.debug("Request to auth");
  79.         OAuthState state;
  80.         try {
  81.             state = OAuthState.fromJson(stateJson, encryptor);
  82.         } catch (Exception e) {
  83.             throw new TechnicalException("invalid state", e);
  84.         }
  85.         if (StringUtils.hasText(code)) {
  86.             var session = tokenProvider.createSession(state.getSessionId(), code, callbackRedirectUri(request));
  87.             response.addCookie(createCookie(session, (int) SESSION_LENGTH.toSeconds(), request));
  88.             redirectStrategy.sendRedirect(request, response, state.getRedirectUri());
  89.         } else {
  90.             String errorRedirect = state.errorRedirect(error, errorDesc);
  91.             log.warn("error logging in {}", errorRedirect);
  92.             redirectStrategy.sendRedirect(request, response, errorRedirect);
  93.         }
  94.     }

  95.     @Operation(summary = "Logout")
  96.     @ApiResponses(value = {
  97.             @ApiResponse(responseCode = "302", description = "Logged out"),
  98.             @ApiResponse(responseCode = "200", description = "Logged out")
  99.     })
  100.     @GetMapping("/logout")
  101.     public void logout(HttpServletRequest request, HttpServletResponse response,
  102.             @RequestParam(value = REDIRECT_URI, required = false) String redirectUri
  103.     ) throws IOException {
  104.         log.debug("Request to logout");
  105.         Assert.isTrue(securityProperties.isValidRedirectUri(redirectUri), "Illegal redirect_uri " + redirectUri);
  106.         tokenProvider.destroySession();
  107.         response.addCookie(createCookie(null, 0, request));
  108.         if (redirectUri != null) {
  109.             redirectStrategy.sendRedirect(request, response, new OAuthState(redirectUri).getRedirectUri());
  110.         }
  111.     }

  112.     @Operation(summary = "User info")
  113.     @ApiResponse(description = "userinfo returned")
  114.     @GetMapping("/userinfo")
  115.     public ResponseEntity<UserInfoResponse> userinfo() {
  116.         log.debug("Request to userinfo");
  117.         Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
  118.         if (authentication == null || !authentication.isAuthenticated() || "anonymousUser".equals(authentication.getPrincipal())) {
  119.             return ResponseEntity.ok(UserInfoResponse.noUser(securityProperties.isEnabled()));
  120.         }
  121.         return ResponseEntity.ok(((UserInfo) authentication.getDetails()).convertToResponse());
  122.     }

  123.     public static Cookie createCookie(String value, int maxAge, HttpServletRequest request) {
  124.         Cookie cookie = new Cookie(COOKIE_NAME, value);
  125.         cookie.setMaxAge(maxAge);
  126.         cookie.setPath("/");
  127.         cookie.setHttpOnly(true);
  128.         cookie.setSecure(!"localhost".equals(request.getServerName()));
  129.         return cookie;
  130.     }

  131.     private String callbackRedirectUri(HttpServletRequest request) {
  132.         String redirectUri = UriComponentsBuilder.fromHttpUrl(buildFullRequestUrl(request))
  133.                 .replacePath(OAUTH_2_CALLBACK_URL)
  134.                 .replaceQuery(null).build().toUriString();
  135.         Assert.isTrue(securityProperties.isValidRedirectUri(redirectUri), "Invalid redirect uri " + redirectUri);
  136.         return redirectUri;
  137.     }
  138. }