diff --git a/conf/openmetadata.yaml b/conf/openmetadata.yaml index 78c357242e8..b0a91094e4e 100644 --- a/conf/openmetadata.yaml +++ b/conf/openmetadata.yaml @@ -177,6 +177,7 @@ authorizerConfiguration: adminPrincipals: ${AUTHORIZER_ADMIN_PRINCIPALS:-[admin]} allowedEmailRegistrationDomains: ${AUTHORIZER_ALLOWED_REGISTRATION_DOMAIN:-["all"]} principalDomain: ${AUTHORIZER_PRINCIPAL_DOMAIN:-"open-metadata.org"} + allowedDomains: ${AUTHORIZER_ALLOWED_DOMAINS:-[]} enforcePrincipalDomain: ${AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN:-false} enableSecureSocketConnection : ${AUTHORIZER_ENABLE_SECURE_SOCKET:-false} useRolesFromProvider: ${AUTHORIZER_USE_ROLES_FROM_PROVIDER:-false} diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/security/AuthenticationException.java b/openmetadata-service/src/main/java/org/openmetadata/service/security/AuthenticationException.java index 746b03d2848..0f81596e1e9 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/security/AuthenticationException.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/security/AuthenticationException.java @@ -58,6 +58,12 @@ public class AuthenticationException extends RuntimeException { return new AuthenticationException(msg); } + public static AuthenticationException invalidEmailMessage(String principalDomain) { + return new AuthenticationException( + String.format( + "Not Authorized! Email does not match the principal domain %s", principalDomain)); + } + private static ErrorResponse convertToErrorResponseMessage(String msg) { return new ErrorResponse(msg); } diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/security/JwtFilter.java b/openmetadata-service/src/main/java/org/openmetadata/service/security/JwtFilter.java index 60f1bb688da..1df0115550d 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/security/JwtFilter.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/security/JwtFilter.java @@ -69,6 +69,7 @@ public class JwtFilter implements ContainerRequestFilter { @Getter private Map jwtPrincipalClaimsMapping; private JwkProvider jwkProvider; private String principalDomain; + private Set allowedDomains; private boolean enforcePrincipalDomain; private AuthProvider providerType; private boolean useRolesFromProvider = false; @@ -123,6 +124,7 @@ public class JwtFilter implements ContainerRequestFilter { this.jwkProvider = new MultiUrlJwkProvider(publicKeyUrlsBuilder.build()); this.principalDomain = authorizerConfiguration.getPrincipalDomain(); + this.allowedDomains = authorizerConfiguration.getAllowedDomains(); this.enforcePrincipalDomain = authorizerConfiguration.getEnforcePrincipalDomain(); this.useRolesFromProvider = authorizerConfiguration.getUseRolesFromProvider(); this.tokenValidationAlgorithm = authenticationConfiguration.getTokenValidationAlgorithm(); @@ -185,6 +187,7 @@ public class JwtFilter implements ContainerRequestFilter { jwtPrincipalClaims, claims, principalDomain, + allowedDomains, enforcePrincipalDomain); // Validate Bot token matches what was created in OM diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/security/SecurityUtil.java b/openmetadata-service/src/main/java/org/openmetadata/service/security/SecurityUtil.java index f17444bf33c..45f8a9cc2bc 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/security/SecurityUtil.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/security/SecurityUtil.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.security.Principal; import java.util.List; import java.util.Map; +import java.util.Set; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.client.Invocation; import javax.ws.rs.client.WebTarget; @@ -188,6 +189,7 @@ public final class SecurityUtil { List jwtPrincipalClaimsOrder, Map claims, String principalDomain, + Set allowedDomains, boolean enforcePrincipalDomain) { String domain = StringUtils.EMPTY; if (!nullOrEmpty(jwtPrincipalClaimsMapping)) { @@ -209,10 +211,21 @@ public final class SecurityUtil { } // Validate - if (!isBot(claims) && (enforcePrincipalDomain && !domain.equals(principalDomain))) { - throw new AuthenticationException( - String.format( - "Not Authorized! Email does not match the principal domain %s", principalDomain)); + if (isBot(claims)) { + // Bots don't need to be validated + return; + } + if (enforcePrincipalDomain) { + if (allowedDomains == null || allowedDomains.isEmpty()) { + // Validate against the principal domain if allowed domains are not supplied + if (!domain.equals(principalDomain)) { + throw AuthenticationException.invalidEmailMessage(principalDomain); + } + } + // Validate against allowed domains if supplied + else if (!allowedDomains.contains(domain)) { + throw AuthenticationException.invalidEmailMessage(domain); + } } } diff --git a/openmetadata-spec/src/main/resources/json/schema/configuration/authorizerConfiguration.json b/openmetadata-spec/src/main/resources/json/schema/configuration/authorizerConfiguration.json index bfa662d2f7c..ebbadfb30e5 100644 --- a/openmetadata-spec/src/main/resources/json/schema/configuration/authorizerConfiguration.json +++ b/openmetadata-spec/src/main/resources/json/schema/configuration/authorizerConfiguration.json @@ -51,6 +51,14 @@ "description": "Principal Domain", "type": "string" }, + "allowedDomains": { + "description": "Allowed Domains to access", + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, "enforcePrincipalDomain": { "description": "Enable Enforce Principal Domain", "type": "boolean" diff --git a/openmetadata-ui/src/main/resources/ui/src/generated/configuration/authorizerConfiguration.ts b/openmetadata-ui/src/main/resources/ui/src/generated/configuration/authorizerConfiguration.ts index b6e533a530f..2562c0f0906 100644 --- a/openmetadata-ui/src/main/resources/ui/src/generated/configuration/authorizerConfiguration.ts +++ b/openmetadata-ui/src/main/resources/ui/src/generated/configuration/authorizerConfiguration.ts @@ -18,6 +18,10 @@ export interface AuthorizerConfiguration { * List of unique admin principals. */ adminPrincipals: string[]; + /** + * Allowed Domains to access + */ + allowedDomains?: string[]; /** * List of unique email domains that are allowed to signup on the platforms */