diff --git a/datahub-frontend/app/auth/AuthModule.java b/datahub-frontend/app/auth/AuthModule.java index 468cfe59ff735e..2390e9e95e8a8c 100644 --- a/datahub-frontend/app/auth/AuthModule.java +++ b/datahub-frontend/app/auth/AuthModule.java @@ -11,6 +11,10 @@ import com.linkedin.metadata.restli.DefaultRestliClientFactory; import com.linkedin.util.Configuration; import com.datahub.authentication.Authentication; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; import java.util.Collections; import org.pac4j.core.client.Client; import org.pac4j.core.client.Clients; @@ -20,6 +24,7 @@ import org.pac4j.play.http.PlayHttpActionAdapter; import org.pac4j.play.store.PlayCookieSessionStore; import org.pac4j.play.store.PlaySessionStore; +import org.pac4j.play.store.ShiroAesDataEncrypter; import play.Environment; import java.util.ArrayList; @@ -41,6 +46,13 @@ */ public class AuthModule extends AbstractModule { + /** + * Pac4j Stores Session State in a browser-side cookie in encrypted fashion. This configuration + * value provides a stable encryption base from which to derive the encryption key. + * + * We hash this value (SHA1), then take the first 16 bytes as the AES key. + */ + private static final String PAC4J_AES_KEY_BASE_CONF = "play.http.secret.key"; private final com.typesafe.config.Config _configs; public AuthModule(final Environment environment, final com.typesafe.config.Config configs) { @@ -49,7 +61,17 @@ public AuthModule(final Environment environment, final com.typesafe.config.Confi @Override protected void configure() { - final PlayCookieSessionStore playCacheCookieStore = new PlayCookieSessionStore(); + PlayCookieSessionStore playCacheCookieStore; + try { + final String aesKeyBase = _configs.getString(PAC4J_AES_KEY_BASE_CONF); + MessageDigest sha = MessageDigest.getInstance("SHA-1"); + byte[] key = sha.digest(aesKeyBase.getBytes(StandardCharsets.UTF_8)); + key = Arrays.copyOf(key, 16); + playCacheCookieStore = new PlayCookieSessionStore( + new ShiroAesDataEncrypter(new String(key))); + } catch (Exception e) { + throw new RuntimeException("Failed to instantiate Pac4j cookie session store!", e); + } bind(SessionStore.class).toInstance(playCacheCookieStore); bind(PlaySessionStore.class).toInstance(playCacheCookieStore); diff --git a/datahub-frontend/app/auth/sso/oidc/custom/CustomOidcClient.java b/datahub-frontend/app/auth/sso/oidc/custom/CustomOidcClient.java index 1264ac11ddad6f..e428e59c257946 100644 --- a/datahub-frontend/app/auth/sso/oidc/custom/CustomOidcClient.java +++ b/datahub-frontend/app/auth/sso/oidc/custom/CustomOidcClient.java @@ -20,7 +20,6 @@ public CustomOidcClient(final OidcConfiguration configuration) { protected void clientInit() { CommonHelper.assertNotNull("configuration", getConfiguration()); getConfiguration().init(); - defaultRedirectActionBuilder(new OidcRedirectActionBuilder(getConfiguration(), this)); defaultCredentialsExtractor(new OidcExtractor(getConfiguration(), this)); defaultAuthenticator(new CustomOidcAuthenticator(getConfiguration(), this)); diff --git a/datahub-frontend/app/controllers/AuthenticationController.java b/datahub-frontend/app/controllers/AuthenticationController.java index e1872abfd64d82..048c8e6ac3cab8 100644 --- a/datahub-frontend/app/controllers/AuthenticationController.java +++ b/datahub-frontend/app/controllers/AuthenticationController.java @@ -34,6 +34,8 @@ import java.time.temporal.ChronoUnit; import static auth.AuthUtils.*; +import static org.pac4j.core.client.IndirectClient.*; + // TODO add logging. public class AuthenticationController extends Controller { @@ -147,7 +149,14 @@ public Result logIn() { private Result redirectToIdentityProvider() { final PlayWebContext playWebContext = new PlayWebContext(ctx(), _playSessionStore); - final Client client = _ssoManager.getSsoProvider().client(); + final Client client = _ssoManager.getSsoProvider().client(); + + // 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(playWebContext, client.getName() + ATTEMPTED_AUTHENTICATION_SUFFIX) != null) { + _logger.debug("Found previous login attempt. Removing it manually to prevent unexpected errors."); + _playSessionStore.set(playWebContext, client.getName() + ATTEMPTED_AUTHENTICATION_SUFFIX, ""); + } final HttpAction action = client.redirect(playWebContext); return new PlayHttpActionAdapter().adapt(action.getCode(), playWebContext); }