| 
									
										
										
										
											2021-08-20 10:58:07 -07:00
										 |  |  | package controllers;
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-22 18:26:42 -07:00
										 |  |  | import auth.AuthUtils;
 | 
					
						
							| 
									
										
										
										
											2023-02-14 13:36:47 -05:00
										 |  |  | import auth.CookieConfigs;
 | 
					
						
							| 
									
										
										
										
											2022-09-22 18:26:42 -07:00
										 |  |  | import auth.JAASConfigs;
 | 
					
						
							|  |  |  | import auth.NativeAuthenticationConfigs;
 | 
					
						
							|  |  |  | import auth.sso.SsoManager;
 | 
					
						
							| 
									
										
										
										
											2021-11-22 16:33:14 -08:00
										 |  |  | import client.AuthServiceClient;
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  | import com.fasterxml.jackson.databind.JsonNode;
 | 
					
						
							|  |  |  | import com.fasterxml.jackson.databind.node.ObjectNode;
 | 
					
						
							|  |  |  | import com.linkedin.common.urn.CorpuserUrn;
 | 
					
						
							| 
									
										
										
										
											2021-11-22 16:33:14 -08:00
										 |  |  | import com.linkedin.common.urn.Urn;
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  | import com.typesafe.config.Config;
 | 
					
						
							| 
									
										
										
										
											2021-08-04 11:55:03 -07:00
										 |  |  | import java.net.URLEncoder;
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  | import java.nio.charset.StandardCharsets;
 | 
					
						
							| 
									
										
										
										
											2021-08-04 11:55:03 -07:00
										 |  |  | import java.util.Optional;
 | 
					
						
							| 
									
										
										
										
											2022-09-22 18:26:42 -07:00
										 |  |  | import javax.annotation.Nonnull;
 | 
					
						
							|  |  |  | import javax.inject.Inject;
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  | import org.apache.commons.lang3.StringUtils;
 | 
					
						
							|  |  |  | import org.pac4j.core.client.Client;
 | 
					
						
							| 
									
										
										
										
											2023-01-11 10:45:18 -08:00
										 |  |  | import org.pac4j.core.exception.http.FoundAction;
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  | import org.pac4j.core.exception.http.RedirectionAction;
 | 
					
						
							| 
									
										
										
										
											2023-01-11 10:45:18 -08:00
										 |  |  | import org.pac4j.core.util.Pac4jConstants;
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  | import org.pac4j.play.PlayWebContext;
 | 
					
						
							|  |  |  | import org.pac4j.play.http.PlayHttpActionAdapter;
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  | import org.pac4j.play.store.PlaySessionStore;
 | 
					
						
							| 
									
										
										
										
											2021-06-25 10:56:45 -07:00
										 |  |  | import org.slf4j.Logger;
 | 
					
						
							|  |  |  | import org.slf4j.LoggerFactory;
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  | import play.libs.Json;
 | 
					
						
							|  |  |  | import play.mvc.Controller;
 | 
					
						
							|  |  |  | import play.mvc.Http;
 | 
					
						
							|  |  |  | import play.mvc.Result;
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  | import play.mvc.Results;
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  | import security.AuthenticationManager;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  | import static auth.AuthUtils.DEFAULT_ACTOR_URN;
 | 
					
						
							|  |  |  | import static auth.AuthUtils.EMAIL;
 | 
					
						
							|  |  |  | import static auth.AuthUtils.FULL_NAME;
 | 
					
						
							|  |  |  | import static auth.AuthUtils.INVITE_TOKEN;
 | 
					
						
							|  |  |  | import static auth.AuthUtils.LOGIN_ROUTE;
 | 
					
						
							|  |  |  | import static auth.AuthUtils.PASSWORD;
 | 
					
						
							|  |  |  | import static auth.AuthUtils.RESET_TOKEN;
 | 
					
						
							|  |  |  | import static auth.AuthUtils.TITLE;
 | 
					
						
							|  |  |  | import static auth.AuthUtils.USER_NAME;
 | 
					
						
							|  |  |  | import static auth.AuthUtils.createActorCookie;
 | 
					
						
							| 
									
										
										
										
											2022-12-22 16:12:51 -06:00
										 |  |  | import static auth.AuthUtils.createSessionMap;
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  | import static org.pac4j.core.client.IndirectClient.ATTEMPTED_AUTHENTICATION_SUFFIX;
 | 
					
						
							| 
									
										
										
										
											2022-03-08 14:27:19 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  | // TODO add logging.
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  | public class AuthenticationController extends Controller {
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-04 11:55:03 -07:00
										 |  |  |     private static final String AUTH_REDIRECT_URI_PARAM = "redirect_uri";
 | 
					
						
							| 
									
										
										
										
											2022-10-31 16:39:26 -07:00
										 |  |  |     private static final String ERROR_MESSAGE_URI_PARAM = "error_msg";
 | 
					
						
							|  |  |  |     private static final String SSO_DISABLED_ERROR_MESSAGE = "SSO is not configured";
 | 
					
						
							| 
									
										
										
										
											2021-08-04 11:55:03 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |     private static final String SSO_NO_REDIRECT_MESSAGE = "SSO is configured, however missing redirect from idp";
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-25 10:56:45 -07:00
										 |  |  |     private final Logger _logger = LoggerFactory.getLogger(AuthenticationController.class.getName());
 | 
					
						
							| 
									
										
										
										
											2023-02-14 13:36:47 -05:00
										 |  |  |     private final CookieConfigs _cookieConfigs;
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  |     private final JAASConfigs _jaasConfigs;
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |     private final NativeAuthenticationConfigs _nativeAuthenticationConfigs;
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @Inject
 | 
					
						
							|  |  |  |     private org.pac4j.core.config.Config _ssoConfig;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @Inject
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |     private PlaySessionStore _playSessionStore;
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  |     @Inject
 | 
					
						
							|  |  |  |     private SsoManager _ssoManager;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-22 16:33:14 -08:00
										 |  |  |     @Inject
 | 
					
						
							|  |  |  |     AuthServiceClient _authClient;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  |     @Inject
 | 
					
						
							|  |  |  |     public AuthenticationController(@Nonnull Config configs) {
 | 
					
						
							| 
									
										
										
										
											2023-02-14 13:36:47 -05:00
										 |  |  |         _cookieConfigs = new CookieConfigs(configs);
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  |         _jaasConfigs = new JAASConfigs(configs);
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |         _nativeAuthenticationConfigs = new NativeAuthenticationConfigs(configs);
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Route used to perform authentication, or redirect to log in if authentication fails.
 | 
					
						
							|  |  |  |      *
 | 
					
						
							|  |  |  |      * If indirect SSO (eg. oidc) is configured, this route will redirect to the identity provider (Indirect auth).
 | 
					
						
							| 
									
										
										
										
											2022-09-22 18:26:42 -07:00
										 |  |  |      * If not, we will fall back to the default username / password login experience (Direct auth).
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  |      */
 | 
					
						
							|  |  |  |     @Nonnull
 | 
					
						
							| 
									
										
										
										
											2022-09-22 18:26:42 -07:00
										 |  |  |     public Result authenticate(Http.Request request) {
 | 
					
						
							| 
									
										
										
										
											2021-08-04 11:55:03 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-22 16:33:14 -08:00
										 |  |  |         // TODO: Call getAuthenticatedUser and then generate a session cookie for the UI if the user is authenticated.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-22 18:26:42 -07:00
										 |  |  |         final Optional<String> maybeRedirectPath = Optional.ofNullable(request.getQueryString(AUTH_REDIRECT_URI_PARAM));
 | 
					
						
							| 
									
										
										
										
											2021-08-04 11:55:03 -07:00
										 |  |  |         final String redirectPath = maybeRedirectPath.orElse("/");
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |         if (AuthUtils.hasValidSessionCookie(request)) {
 | 
					
						
							|  |  |  |             return Results.redirect(redirectPath);
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  |         // 1. If SSO is enabled, redirect to IdP if not authenticated.
 | 
					
						
							|  |  |  |         if (_ssoManager.isSsoEnabled()) {
 | 
					
						
							| 
									
										
										
										
											2023-01-11 10:45:18 -08:00
										 |  |  |             return redirectToIdentityProvider(request, redirectPath).orElse(
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |                     Results.redirect(LOGIN_ROUTE + String.format("?%s=%s", ERROR_MESSAGE_URI_PARAM, SSO_NO_REDIRECT_MESSAGE))
 | 
					
						
							|  |  |  |             );
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |         // 2. If either JAAS auth or Native auth is enabled, fallback to it
 | 
					
						
							|  |  |  |         if (_jaasConfigs.isJAASEnabled() || _nativeAuthenticationConfigs.isNativeAuthenticationEnabled()) {
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |             return Results.redirect(
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |                 LOGIN_ROUTE + String.format("?%s=%s", AUTH_REDIRECT_URI_PARAM, encodeRedirectUri(redirectPath)));
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // 3. If no auth enabled, fallback to using default user account & redirect.
 | 
					
						
							| 
									
										
										
										
											2021-11-22 16:33:14 -08:00
										 |  |  |         // Generate GMS session token, TODO:
 | 
					
						
							|  |  |  |         final String accessToken = _authClient.generateSessionTokenForUser(DEFAULT_ACTOR_URN.getId());
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |         return Results.redirect(redirectPath).withSession(createSessionMap(DEFAULT_ACTOR_URN.toString(), accessToken))
 | 
					
						
							| 
									
										
										
										
											2023-02-14 13:36:47 -05:00
										 |  |  |             .withCookies(
 | 
					
						
							|  |  |  |                 createActorCookie(
 | 
					
						
							|  |  |  |                     DEFAULT_ACTOR_URN.toString(),
 | 
					
						
							|  |  |  |                     _cookieConfigs.getTtlInHours(),
 | 
					
						
							|  |  |  |                     _cookieConfigs.getAuthCookieSameSite(),
 | 
					
						
							|  |  |  |                     _cookieConfigs.getAuthCookieSecure()
 | 
					
						
							|  |  |  |                 )
 | 
					
						
							|  |  |  |             );
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-31 16:39:26 -07:00
										 |  |  |     /**
 | 
					
						
							|  |  |  |      * Redirect to the identity provider for authentication.
 | 
					
						
							|  |  |  |      */
 | 
					
						
							|  |  |  |     @Nonnull
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |     public Result sso(Http.Request request) {
 | 
					
						
							| 
									
										
										
										
											2022-10-31 16:39:26 -07:00
										 |  |  |         if (_ssoManager.isSsoEnabled()) {
 | 
					
						
							| 
									
										
										
										
											2023-01-11 10:45:18 -08:00
										 |  |  |             return redirectToIdentityProvider(request, "/").orElse(
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |                 Results.redirect(LOGIN_ROUTE + String.format("?%s=%s", ERROR_MESSAGE_URI_PARAM, SSO_NO_REDIRECT_MESSAGE))
 | 
					
						
							|  |  |  |             );
 | 
					
						
							| 
									
										
										
										
											2022-10-31 16:39:26 -07:00
										 |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |         return Results.redirect(LOGIN_ROUTE + String.format("?%s=%s", ERROR_MESSAGE_URI_PARAM, SSO_DISABLED_ERROR_MESSAGE));
 | 
					
						
							| 
									
										
										
										
											2022-10-31 16:39:26 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  |     /**
 | 
					
						
							|  |  |  |      * Log in a user based on a username + password.
 | 
					
						
							|  |  |  |      *
 | 
					
						
							|  |  |  |      * TODO: Implement built-in support for LDAP auth. Currently dummy jaas authentication is the default.
 | 
					
						
							|  |  |  |      */
 | 
					
						
							|  |  |  |     @Nonnull
 | 
					
						
							| 
									
										
										
										
											2022-09-22 18:26:42 -07:00
										 |  |  |     public Result logIn(Http.Request request) {
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |         boolean jaasEnabled = _jaasConfigs.isJAASEnabled();
 | 
					
						
							|  |  |  |         _logger.debug(String.format("Jaas authentication enabled: %b", jaasEnabled));
 | 
					
						
							|  |  |  |         boolean nativeAuthenticationEnabled = _nativeAuthenticationConfigs.isNativeAuthenticationEnabled();
 | 
					
						
							|  |  |  |         _logger.debug(String.format("Native authentication enabled: %b", nativeAuthenticationEnabled));
 | 
					
						
							|  |  |  |         boolean noAuthEnabled = !jaasEnabled && !nativeAuthenticationEnabled;
 | 
					
						
							|  |  |  |         if (noAuthEnabled) {
 | 
					
						
							|  |  |  |             String message = "Neither JAAS nor native authentication is enabled on the server.";
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  |             final ObjectNode error = Json.newObject();
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |             error.put("message", message);
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |             return Results.badRequest(error);
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-22 18:26:42 -07:00
										 |  |  |         final JsonNode json = request.body().asJson();
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  |         final String username = json.findPath(USER_NAME).textValue();
 | 
					
						
							|  |  |  |         final String password = json.findPath(PASSWORD).textValue();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (StringUtils.isBlank(username)) {
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |             JsonNode invalidCredsJson = Json.newObject().put("message", "User name must not be empty.");
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |             return Results.badRequest(invalidCredsJson);
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |         JsonNode invalidCredsJson = Json.newObject().put("message", "Invalid Credentials");
 | 
					
						
							|  |  |  |         boolean loginSucceeded = tryLogin(username, password);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!loginSucceeded) {
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |             return Results.badRequest(invalidCredsJson);
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-22 16:33:14 -08:00
										 |  |  |         final Urn actorUrn = new CorpuserUrn(username);
 | 
					
						
							|  |  |  |         final String accessToken = _authClient.generateSessionTokenForUser(actorUrn.getId());
 | 
					
						
							| 
									
										
										
										
											2022-10-07 14:08:43 -07:00
										 |  |  |         return createSession(actorUrn.toString(), accessToken);
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2021-08-04 11:55:03 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |     /**
 | 
					
						
							| 
									
										
										
										
											2022-09-23 16:48:23 -07:00
										 |  |  |      * Sign up a native user based on a name, email, title, and password. The invite token must match an existing invite token.
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |      *
 | 
					
						
							|  |  |  |      */
 | 
					
						
							|  |  |  |     @Nonnull
 | 
					
						
							| 
									
										
										
										
											2022-09-22 18:26:42 -07:00
										 |  |  |     public Result signUp(Http.Request request) {
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |         boolean nativeAuthenticationEnabled = _nativeAuthenticationConfigs.isNativeAuthenticationEnabled();
 | 
					
						
							|  |  |  |         _logger.debug(String.format("Native authentication enabled: %b", nativeAuthenticationEnabled));
 | 
					
						
							|  |  |  |         if (!nativeAuthenticationEnabled) {
 | 
					
						
							|  |  |  |             String message = "Native authentication is not enabled on the server.";
 | 
					
						
							|  |  |  |             final ObjectNode error = Json.newObject();
 | 
					
						
							|  |  |  |             error.put("message", message);
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |             return Results.badRequest(error);
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-22 18:26:42 -07:00
										 |  |  |         final JsonNode json = request.body().asJson();
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |         final String fullName = json.findPath(FULL_NAME).textValue();
 | 
					
						
							|  |  |  |         final String email = json.findPath(EMAIL).textValue();
 | 
					
						
							|  |  |  |         final String title = json.findPath(TITLE).textValue();
 | 
					
						
							|  |  |  |         final String password = json.findPath(PASSWORD).textValue();
 | 
					
						
							|  |  |  |         final String inviteToken = json.findPath(INVITE_TOKEN).textValue();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (StringUtils.isBlank(fullName)) {
 | 
					
						
							|  |  |  |             JsonNode invalidCredsJson = Json.newObject().put("message", "Full name must not be empty.");
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |             return Results.badRequest(invalidCredsJson);
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (StringUtils.isBlank(email)) {
 | 
					
						
							|  |  |  |             JsonNode invalidCredsJson = Json.newObject().put("message", "Email must not be empty.");
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |             return Results.badRequest(invalidCredsJson);
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (StringUtils.isBlank(password)) {
 | 
					
						
							|  |  |  |             JsonNode invalidCredsJson = Json.newObject().put("message", "Password must not be empty.");
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |             return Results.badRequest(invalidCredsJson);
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (StringUtils.isBlank(title)) {
 | 
					
						
							|  |  |  |             JsonNode invalidCredsJson = Json.newObject().put("message", "Title must not be empty.");
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |             return Results.badRequest(invalidCredsJson);
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (StringUtils.isBlank(inviteToken)) {
 | 
					
						
							|  |  |  |             JsonNode invalidCredsJson = Json.newObject().put("message", "Invite token must not be empty.");
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |             return Results.badRequest(invalidCredsJson);
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         final Urn userUrn = new CorpuserUrn(email);
 | 
					
						
							|  |  |  |         final String userUrnString = userUrn.toString();
 | 
					
						
							| 
									
										
										
										
											2022-09-23 16:48:23 -07:00
										 |  |  |         _authClient.signUp(userUrnString, fullName, email, title, password, inviteToken);
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |         final String accessToken = _authClient.generateSessionTokenForUser(userUrn.getId());
 | 
					
						
							| 
									
										
										
										
											2022-10-07 14:08:43 -07:00
										 |  |  |         return createSession(userUrnString, accessToken);
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							| 
									
										
										
										
											2022-09-23 16:48:23 -07:00
										 |  |  |      * Reset a native user's credentials based on a username, old password, and new password.
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |      *
 | 
					
						
							|  |  |  |      */
 | 
					
						
							|  |  |  |     @Nonnull
 | 
					
						
							| 
									
										
										
										
											2022-09-22 18:26:42 -07:00
										 |  |  |     public Result resetNativeUserCredentials(Http.Request request) {
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |         boolean nativeAuthenticationEnabled = _nativeAuthenticationConfigs.isNativeAuthenticationEnabled();
 | 
					
						
							|  |  |  |         _logger.debug(String.format("Native authentication enabled: %b", nativeAuthenticationEnabled));
 | 
					
						
							|  |  |  |         if (!nativeAuthenticationEnabled) {
 | 
					
						
							|  |  |  |             String message = "Native authentication is not enabled on the server.";
 | 
					
						
							|  |  |  |             final ObjectNode error = Json.newObject();
 | 
					
						
							|  |  |  |             error.put("message", message);
 | 
					
						
							|  |  |  |             return badRequest(error);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-22 18:26:42 -07:00
										 |  |  |         final JsonNode json = request.body().asJson();
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |         final String email = json.findPath(EMAIL).textValue();
 | 
					
						
							|  |  |  |         final String password = json.findPath(PASSWORD).textValue();
 | 
					
						
							|  |  |  |         final String resetToken = json.findPath(RESET_TOKEN).textValue();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (StringUtils.isBlank(email)) {
 | 
					
						
							|  |  |  |             JsonNode invalidCredsJson = Json.newObject().put("message", "Email must not be empty.");
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |             return Results.badRequest(invalidCredsJson);
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (StringUtils.isBlank(password)) {
 | 
					
						
							|  |  |  |             JsonNode invalidCredsJson = Json.newObject().put("message", "Password must not be empty.");
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |             return Results.badRequest(invalidCredsJson);
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (StringUtils.isBlank(resetToken)) {
 | 
					
						
							|  |  |  |             JsonNode invalidCredsJson = Json.newObject().put("message", "Reset token must not be empty.");
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |             return Results.badRequest(invalidCredsJson);
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         final Urn userUrn = new CorpuserUrn(email);
 | 
					
						
							|  |  |  |         final String userUrnString = userUrn.toString();
 | 
					
						
							| 
									
										
										
										
											2022-09-23 16:48:23 -07:00
										 |  |  |         _authClient.resetNativeUserCredentials(userUrnString, password, resetToken);
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |         final String accessToken = _authClient.generateSessionTokenForUser(userUrn.getId());
 | 
					
						
							| 
									
										
										
										
											2022-10-07 14:08:43 -07:00
										 |  |  |         return createSession(userUrnString, accessToken);
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-11 10:45:18 -08:00
										 |  |  |     private Optional<Result> redirectToIdentityProvider(Http.RequestHeader request, String redirectPath) {
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |         final PlayWebContext playWebContext = new PlayWebContext(request, _playSessionStore);
 | 
					
						
							|  |  |  |         final Client client = _ssoManager.getSsoProvider().client();
 | 
					
						
							| 
									
										
										
										
											2023-01-11 10:45:18 -08:00
										 |  |  |         configurePac4jSessionStore(playWebContext, client, redirectPath);
 | 
					
						
							| 
									
										
										
										
											2022-08-23 09:54:34 -07:00
										 |  |  |         try {
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |             final Optional<RedirectionAction> action = client.getRedirectionAction(playWebContext);
 | 
					
						
							|  |  |  |             return action.map(act -> new PlayHttpActionAdapter().adapt(act, playWebContext));
 | 
					
						
							| 
									
										
										
										
											2022-08-23 09:54:34 -07:00
										 |  |  |         } catch (Exception e) {
 | 
					
						
							|  |  |  |             _logger.error("Caught exception while attempting to redirect to SSO identity provider! It's likely that SSO integration is mis-configured", e);
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |             return Optional.of(Results.redirect(
 | 
					
						
							| 
									
										
										
										
											2022-08-23 09:54:34 -07:00
										 |  |  |                 String.format("/login?error_msg=%s",
 | 
					
						
							|  |  |  |                 URLEncoder.encode("Failed to redirect to Single Sign-On provider. Please contact your DataHub Administrator, "
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |                     + "or refer to server logs for more information.", StandardCharsets.UTF_8))));
 | 
					
						
							| 
									
										
										
										
											2022-08-23 09:54:34 -07:00
										 |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2021-08-20 07:42:18 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-11 10:45:18 -08:00
										 |  |  |     private void configurePac4jSessionStore(PlayWebContext context, Client client, String redirectPath) {
 | 
					
						
							|  |  |  |         // Set the originally requested path for post-auth redirection.
 | 
					
						
							|  |  |  |         _playSessionStore.set(context, Pac4jConstants.REQUESTED_URL, new FoundAction(redirectPath));
 | 
					
						
							|  |  |  |         // This is to prevent previous login attempts from being cached.
 | 
					
						
							|  |  |  |         // We replicate the logic here, which is buried in the Pac4j client.
 | 
					
						
							|  |  |  |         if (_playSessionStore.get(context, client.getName() + ATTEMPTED_AUTHENTICATION_SUFFIX) != null) {
 | 
					
						
							|  |  |  |             _logger.debug("Found previous login attempt. Removing it manually to prevent unexpected errors.");
 | 
					
						
							|  |  |  |             _playSessionStore.set(context, client.getName() + ATTEMPTED_AUTHENTICATION_SUFFIX, "");
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-04 11:55:03 -07:00
										 |  |  |     private String encodeRedirectUri(final String redirectUri) {
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |         return URLEncoder.encode(redirectUri, StandardCharsets.UTF_8);
 | 
					
						
							| 
									
										
										
										
											2021-08-04 11:55:03 -07:00
										 |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private boolean tryLogin(String username, String password) {
 | 
					
						
							|  |  |  |         boolean loginSucceeded = false;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // First try jaas login, if enabled
 | 
					
						
							|  |  |  |         if (_jaasConfigs.isJAASEnabled()) {
 | 
					
						
							|  |  |  |             try {
 | 
					
						
							|  |  |  |                 _logger.debug("Attempting jaas authentication");
 | 
					
						
							|  |  |  |                 AuthenticationManager.authenticateJaasUser(username, password);
 | 
					
						
							| 
									
										
										
										
											2022-09-21 14:21:55 -07:00
										 |  |  |                 _logger.debug("Jaas authentication successful. Login succeeded");
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |                 loginSucceeded = true;
 | 
					
						
							|  |  |  |             } catch (Exception e) {
 | 
					
						
							| 
									
										
										
										
											2022-09-21 14:21:55 -07:00
										 |  |  |                 _logger.debug("Jaas authentication error. Login failed", e);
 | 
					
						
							| 
									
										
										
										
											2022-06-08 21:13:22 -04:00
										 |  |  |             }
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // If jaas login fails or is disabled, try native auth login
 | 
					
						
							|  |  |  |         if (_nativeAuthenticationConfigs.isNativeAuthenticationEnabled() && !loginSucceeded) {
 | 
					
						
							|  |  |  |             final Urn userUrn = new CorpuserUrn(username);
 | 
					
						
							|  |  |  |             final String userUrnString = userUrn.toString();
 | 
					
						
							|  |  |  |             loginSucceeded = loginSucceeded || _authClient.verifyNativeUserCredentials(userUrnString, password);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return loginSucceeded;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2022-09-22 18:26:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-07 14:08:43 -07:00
										 |  |  |     private Result createSession(String userUrnString, String accessToken) {
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:27:51 -06:00
										 |  |  |         return Results.ok().withSession(createSessionMap(userUrnString, accessToken))
 | 
					
						
							| 
									
										
										
										
											2023-02-14 13:36:47 -05:00
										 |  |  |             .withCookies(
 | 
					
						
							|  |  |  |                 createActorCookie(
 | 
					
						
							|  |  |  |                     userUrnString,
 | 
					
						
							|  |  |  |                     _cookieConfigs.getTtlInHours(),
 | 
					
						
							|  |  |  |                     _cookieConfigs.getAuthCookieSameSite(),
 | 
					
						
							|  |  |  |                     _cookieConfigs.getAuthCookieSecure()
 | 
					
						
							|  |  |  |                 )
 | 
					
						
							|  |  |  |             );
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-07 14:08:43 -07:00
										 |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2021-03-11 13:38:35 -08:00
										 |  |  | }
 |