Skip to content

Commit

Permalink
feat(frontend): align frontend sso code with refactors (datahub-proje…
Browse files Browse the repository at this point in the history
  • Loading branch information
RyanHolstien authored Dec 26, 2023
1 parent 1e64a75 commit 651998d
Show file tree
Hide file tree
Showing 14 changed files with 768 additions and 144 deletions.
110 changes: 49 additions & 61 deletions datahub-frontend/app/auth/AuthModule.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
package auth;

import static auth.AuthUtils.*;
import static auth.sso.oidc.OidcConfigs.*;
import static utils.ConfigUtil.*;

import auth.sso.SsoConfigs;
import auth.sso.SsoManager;
import auth.sso.oidc.OidcConfigs;
import auth.sso.oidc.OidcProvider;
import client.AuthServiceClient;
import com.datahub.authentication.Actor;
import com.datahub.authentication.ActorType;
Expand All @@ -23,14 +19,11 @@
import config.ConfigurationProvider;
import controllers.SsoCallbackController;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.pac4j.core.client.Client;
import org.pac4j.core.client.Clients;
import org.pac4j.core.config.Config;
import org.pac4j.core.context.session.SessionStore;
import org.pac4j.play.LogoutController;
Expand All @@ -45,6 +38,7 @@
import utils.ConfigUtil;

/** Responsible for configuring, validating, and providing authentication related components. */
@Slf4j
public class AuthModule extends AbstractModule {

/**
Expand All @@ -58,6 +52,7 @@ public class AuthModule extends AbstractModule {
private static final String PAC4J_SESSIONSTORE_PROVIDER_CONF = "pac4j.sessionStore.provider";
private static final String ENTITY_CLIENT_RETRY_INTERVAL = "entityClient.retryInterval";
private static final String ENTITY_CLIENT_NUM_RETRIES = "entityClient.numRetries";
private static final String GET_SSO_SETTINGS_ENDPOINT = "auth/getSsoSettings";

private final com.typesafe.config.Config _configs;

Expand Down Expand Up @@ -111,6 +106,7 @@ protected void configure() {
Authentication.class,
SystemEntityClient.class,
AuthServiceClient.class,
org.pac4j.core.config.Config.class,
com.typesafe.config.Config.class));
} catch (NoSuchMethodException | SecurityException e) {
throw new RuntimeException(
Expand All @@ -124,34 +120,20 @@ protected void configure() {

@Provides
@Singleton
protected Config provideConfig(SsoManager ssoManager) {
if (ssoManager.isSsoEnabled()) {
final Clients clients = new Clients();
final List<Client> clientList = new ArrayList<>();
clientList.add(ssoManager.getSsoProvider().client());
clients.setClients(clientList);
final Config config = new Config(clients);
config.setHttpActionAdapter(new PlayHttpActionAdapter());
return config;
}
return new Config();
protected Config provideConfig() {
Config config = new Config();
config.setHttpActionAdapter(new PlayHttpActionAdapter());
return config;
}

@Provides
@Singleton
protected SsoManager provideSsoManager() {
SsoManager manager = new SsoManager();
// Seed the SSO manager with a default SSO provider.
if (isSsoEnabled(_configs)) {
SsoConfigs ssoConfigs = new SsoConfigs(_configs);
if (ssoConfigs.isOidcEnabled()) {
// Register OIDC Provider, add to list of managers.
OidcConfigs oidcConfigs = new OidcConfigs(_configs);
OidcProvider oidcProvider = new OidcProvider(oidcConfigs);
// Set the default SSO provider to this OIDC client.
manager.setSsoProvider(oidcProvider);
}
}
protected SsoManager provideSsoManager(
Authentication systemAuthentication, CloseableHttpClient httpClient) {
SsoManager manager =
new SsoManager(
_configs, systemAuthentication, getSsoSettingsRequestUrl(_configs), httpClient);
manager.initializeSsoProvider();
return manager;
}

Expand Down Expand Up @@ -191,33 +173,16 @@ protected SystemEntityClient provideEntityClient(
configurationProvider.getCache().getClient().getEntityClient());
}

@Provides
@Singleton
protected CloseableHttpClient provideHttpClient() {
return HttpClients.createDefault();
}

@Provides
@Singleton
protected AuthServiceClient provideAuthClient(
Authentication systemAuthentication, CloseableHttpClient httpClient) {
// Init a GMS auth client
final String metadataServiceHost =
_configs.hasPath(METADATA_SERVICE_HOST_CONFIG_PATH)
? _configs.getString(METADATA_SERVICE_HOST_CONFIG_PATH)
: Configuration.getEnvironmentVariable(GMS_HOST_ENV_VAR, DEFAULT_GMS_HOST);
final String metadataServiceHost = getMetadataServiceHost(_configs);

final int metadataServicePort =
_configs.hasPath(METADATA_SERVICE_PORT_CONFIG_PATH)
? _configs.getInt(METADATA_SERVICE_PORT_CONFIG_PATH)
: Integer.parseInt(
Configuration.getEnvironmentVariable(GMS_PORT_ENV_VAR, DEFAULT_GMS_PORT));
final int metadataServicePort = getMetadataServicePort(_configs);

final Boolean metadataServiceUseSsl =
_configs.hasPath(METADATA_SERVICE_USE_SSL_CONFIG_PATH)
? _configs.getBoolean(METADATA_SERVICE_USE_SSL_CONFIG_PATH)
: Boolean.parseBoolean(
Configuration.getEnvironmentVariable(GMS_USE_SSL_ENV_VAR, DEFAULT_GMS_USE_SSL));
final boolean metadataServiceUseSsl = doesMetadataServiceUseSsl(_configs);

return new AuthServiceClient(
metadataServiceHost,
Expand All @@ -227,6 +192,12 @@ protected AuthServiceClient provideAuthClient(
httpClient);
}

@Provides
@Singleton
protected CloseableHttpClient provideHttpClient() {
return HttpClients.createDefault();
}

private com.linkedin.restli.client.Client buildRestliClient() {
final String metadataServiceHost =
utils.ConfigUtil.getString(
Expand Down Expand Up @@ -255,16 +226,33 @@ private com.linkedin.restli.client.Client buildRestliClient() {
metadataServiceSslProtocol);
}

protected boolean isSsoEnabled(com.typesafe.config.Config configs) {
// If OIDC is enabled, we infer SSO to be enabled.
return configs.hasPath(OIDC_ENABLED_CONFIG_PATH)
&& Boolean.TRUE.equals(Boolean.parseBoolean(configs.getString(OIDC_ENABLED_CONFIG_PATH)));
protected boolean doesMetadataServiceUseSsl(com.typesafe.config.Config configs) {
return configs.hasPath(METADATA_SERVICE_USE_SSL_CONFIG_PATH)
? configs.getBoolean(METADATA_SERVICE_USE_SSL_CONFIG_PATH)
: Boolean.parseBoolean(
Configuration.getEnvironmentVariable(GMS_USE_SSL_ENV_VAR, DEFAULT_GMS_USE_SSL));
}

protected boolean isMetadataServiceAuthEnabled(com.typesafe.config.Config configs) {
// If OIDC is enabled, we infer SSO to be enabled.
return configs.hasPath(METADATA_SERVICE_AUTH_ENABLED_CONFIG_PATH)
&& Boolean.TRUE.equals(
Boolean.parseBoolean(configs.getString(METADATA_SERVICE_AUTH_ENABLED_CONFIG_PATH)));
protected String getMetadataServiceHost(com.typesafe.config.Config configs) {
return configs.hasPath(METADATA_SERVICE_HOST_CONFIG_PATH)
? configs.getString(METADATA_SERVICE_HOST_CONFIG_PATH)
: Configuration.getEnvironmentVariable(GMS_HOST_ENV_VAR, DEFAULT_GMS_HOST);
}

protected Integer getMetadataServicePort(com.typesafe.config.Config configs) {
return configs.hasPath(METADATA_SERVICE_PORT_CONFIG_PATH)
? configs.getInt(METADATA_SERVICE_PORT_CONFIG_PATH)
: Integer.parseInt(
Configuration.getEnvironmentVariable(GMS_PORT_ENV_VAR, DEFAULT_GMS_PORT));
}

protected String getSsoSettingsRequestUrl(com.typesafe.config.Config configs) {
final String protocol = doesMetadataServiceUseSsl(configs) ? "https" : "http";
final String metadataServiceHost = getMetadataServiceHost(configs);
final Integer metadataServicePort = getMetadataServicePort(configs);

return String.format(
"%s://%s:%s/%s",
protocol, metadataServiceHost, metadataServicePort, GET_SSO_SETTINGS_ENDPOINT);
}
}
20 changes: 20 additions & 0 deletions datahub-frontend/app/auth/AuthUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,26 @@ public class AuthUtils {
public static final String TITLE = "title";
public static final String INVITE_TOKEN = "inviteToken";
public static final String RESET_TOKEN = "resetToken";
public static final String BASE_URL = "baseUrl";
public static final String OIDC_ENABLED = "oidcEnabled";
public static final String CLIENT_ID = "clientId";
public static final String CLIENT_SECRET = "clientSecret";
public static final String DISCOVERY_URI = "discoveryUri";

public static final String USER_NAME_CLAIM = "userNameClaim";
public static final String USER_NAME_CLAIM_REGEX = "userNameClaimRegex";
public static final String SCOPE = "scope";
public static final String CLIENT_NAME = "clientName";
public static final String CLIENT_AUTHENTICATION_METHOD = "clientAuthenticationMethod";
public static final String JIT_PROVISIONING_ENABLED = "jitProvisioningEnabled";
public static final String PRE_PROVISIONING_REQUIRED = "preProvisioningRequired";
public static final String EXTRACT_GROUPS_ENABLED = "extractGroupsEnabled";
public static final String GROUPS_CLAIM = "groupsClaim";
public static final String RESPONSE_TYPE = "responseType";
public static final String RESPONSE_MODE = "responseMode";
public static final String USE_NONCE = "useNonce";
public static final String READ_TIMEOUT = "readTimeout";
public static final String EXTRACT_JWT_ACCESS_TOKEN_CLAIMS = "extractJwtAccessTokenClaims";

/**
* Determines whether the inbound request should be forward to downstream Metadata Service. Today,
Expand Down
75 changes: 63 additions & 12 deletions datahub-frontend/app/auth/sso/SsoConfigs.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
package auth.sso;

import static auth.ConfigUtil.*;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

/** Class responsible for extracting and validating top-level SSO related configurations. */
import static auth.AuthUtils.*;


/**
* Class responsible for extracting and validating top-level SSO related configurations. TODO:
* Refactor SsoConfigs to have OidcConfigs and other identity provider specific configs as instance
* variables. SSoManager should ideally not know about identity provider specific configs.
*/
public class SsoConfigs {

/** Required configs */
Expand All @@ -22,16 +30,11 @@ public class SsoConfigs {
private final String _authSuccessRedirectPath;
private final Boolean _oidcEnabled;

public SsoConfigs(final com.typesafe.config.Config configs) {
_authBaseUrl = getRequired(configs, AUTH_BASE_URL_CONFIG_PATH);
_authBaseCallbackPath =
getOptional(configs, AUTH_BASE_CALLBACK_PATH_CONFIG_PATH, DEFAULT_BASE_CALLBACK_PATH);
_authSuccessRedirectPath =
getOptional(configs, AUTH_SUCCESS_REDIRECT_PATH_CONFIG_PATH, DEFAULT_SUCCESS_REDIRECT_PATH);
_oidcEnabled =
configs.hasPath(OIDC_ENABLED_CONFIG_PATH)
&& Boolean.TRUE.equals(
Boolean.parseBoolean(configs.getString(OIDC_ENABLED_CONFIG_PATH)));
public SsoConfigs(Builder<?> builder) {
_authBaseUrl = builder._authBaseUrl;
_authBaseCallbackPath = builder._authBaseCallbackPath;
_authSuccessRedirectPath = builder._authSuccessRedirectPath;
_oidcEnabled = builder._oidcEnabled;
}

public String getAuthBaseUrl() {
Expand All @@ -49,4 +52,52 @@ public String getAuthSuccessRedirectPath() {
public Boolean isOidcEnabled() {
return _oidcEnabled;
}

public static class Builder<T extends Builder<T>> {
protected String _authBaseUrl = null;
private String _authBaseCallbackPath = DEFAULT_BASE_CALLBACK_PATH;
private String _authSuccessRedirectPath = DEFAULT_SUCCESS_REDIRECT_PATH;
protected Boolean _oidcEnabled = false;
private final ObjectMapper _objectMapper = new ObjectMapper();
protected JsonNode jsonNode = null;

// No need to check if changes are made since this method is only called at start-up.
public Builder from(final com.typesafe.config.Config configs) {
if (configs.hasPath(AUTH_BASE_URL_CONFIG_PATH)) {
_authBaseUrl = configs.getString(AUTH_BASE_URL_CONFIG_PATH);
}
if (configs.hasPath(AUTH_BASE_CALLBACK_PATH_CONFIG_PATH)) {
_authBaseCallbackPath = configs.getString(AUTH_BASE_CALLBACK_PATH_CONFIG_PATH);
}
if (configs.hasPath(OIDC_ENABLED_CONFIG_PATH)) {
_oidcEnabled =
Boolean.TRUE.equals(Boolean.parseBoolean(configs.getString(OIDC_ENABLED_CONFIG_PATH)));
}
if (configs.hasPath(AUTH_SUCCESS_REDIRECT_PATH_CONFIG_PATH)) {
_authSuccessRedirectPath = configs.getString(AUTH_SUCCESS_REDIRECT_PATH_CONFIG_PATH);
}
return this;
}

public Builder from(String ssoSettingsJsonStr) {
try {
jsonNode = _objectMapper.readTree(ssoSettingsJsonStr);
} catch (Exception e) {
throw new RuntimeException(
String.format("Failed to parse ssoSettingsJsonStr %s into JSON", ssoSettingsJsonStr));
}
if (jsonNode.has(BASE_URL)) {
_authBaseUrl = jsonNode.get(BASE_URL).asText();
}
if (jsonNode.has(OIDC_ENABLED)) {
_oidcEnabled = jsonNode.get(OIDC_ENABLED).asBoolean();
}

return this;
}

public SsoConfigs build() {
return new SsoConfigs(this);
}
}
}
Loading

0 comments on commit 651998d

Please sign in to comment.