mirror of
				https://github.com/open-metadata/OpenMetadata.git
				synced 2025-11-04 12:36:23 +00:00 
			
		
		
		
	Backend: Enforce principal domain in the JWT filter (#5155)
This commit is contained in:
		
							parent
							
								
									c1fa31eacc
								
							
						
					
					
						commit
						059acfc529
					
				@ -210,15 +210,15 @@ public class CatalogApplication extends Application<CatalogApplicationConfig> {
 | 
			
		||||
        filter =
 | 
			
		||||
            Class.forName(filterClazzName)
 | 
			
		||||
                .asSubclass(ContainerRequestFilter.class)
 | 
			
		||||
                .getConstructor(AuthenticationConfiguration.class)
 | 
			
		||||
                .newInstance(authenticationConfiguration);
 | 
			
		||||
                .getConstructor(AuthenticationConfiguration.class, AuthorizerConfiguration.class)
 | 
			
		||||
                .newInstance(authenticationConfiguration, authorizerConf);
 | 
			
		||||
        LOG.info("Registering ContainerRequestFilter: {}", filter.getClass().getCanonicalName());
 | 
			
		||||
        environment.jersey().register(filter);
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      LOG.info("Authorizer config not set, setting noop authorizer");
 | 
			
		||||
      authorizer = new NoopAuthorizer();
 | 
			
		||||
      ContainerRequestFilter filter = new NoopFilter(authenticationConfiguration);
 | 
			
		||||
      ContainerRequestFilter filter = new NoopFilter(authenticationConfiguration, null);
 | 
			
		||||
      environment.jersey().register(filter);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -31,7 +31,7 @@ public class AuthenticationConfiguration {
 | 
			
		||||
  @Getter @Setter private String authority;
 | 
			
		||||
  @Getter @Setter private String clientId;
 | 
			
		||||
  @Getter @Setter private String callbackUrl;
 | 
			
		||||
  @Getter @Setter private List<String> jwtPrincipalClaims = List.of("email", "preferred_username", "sub");
 | 
			
		||||
  @Getter @Setter private List<String> jwtPrincipalClaims;
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public String toString() {
 | 
			
		||||
 | 
			
		||||
@ -24,6 +24,7 @@ public class AuthorizerConfiguration {
 | 
			
		||||
  @NotEmpty @Getter @Setter private Set<String> adminPrincipals;
 | 
			
		||||
  @NotEmpty @Getter @Setter private Set<String> botPrincipals;
 | 
			
		||||
  @NotEmpty @Getter @Setter private String principalDomain;
 | 
			
		||||
  @NotEmpty @Getter @Setter private Boolean enforcePrincipalDomain;
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public String toString() {
 | 
			
		||||
 | 
			
		||||
@ -32,7 +32,7 @@ public class CatalogOpenIdAuthorizationRequestFilter implements ContainerRequest
 | 
			
		||||
  @SuppressWarnings("unused")
 | 
			
		||||
  private CatalogOpenIdAuthorizationRequestFilter() {}
 | 
			
		||||
 | 
			
		||||
  public CatalogOpenIdAuthorizationRequestFilter(AuthenticationConfiguration config) {}
 | 
			
		||||
  public CatalogOpenIdAuthorizationRequestFilter(AuthenticationConfiguration config, AuthorizerConfiguration conf) {}
 | 
			
		||||
 | 
			
		||||
  public void filter(ContainerRequestContext containerRequestContext) {
 | 
			
		||||
    if (isHealthEndpoint(containerRequestContext)) {
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@
 | 
			
		||||
package org.openmetadata.catalog.security;
 | 
			
		||||
 | 
			
		||||
import static org.openmetadata.catalog.Entity.FIELD_OWNER;
 | 
			
		||||
import static org.openmetadata.catalog.security.SecurityUtil.DEFAULT_PRINCIPAL_DOMAIN;
 | 
			
		||||
import static org.openmetadata.common.utils.CommonUtil.listOrEmpty;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
@ -68,11 +69,12 @@ public class DefaultAuthorizer implements Authorizer {
 | 
			
		||||
        }
 | 
			
		||||
        addOrUpdateUser(user);
 | 
			
		||||
      } catch (EntityNotFoundException | IOException ex) {
 | 
			
		||||
        String domain = principalDomain.isEmpty() ? DEFAULT_PRINCIPAL_DOMAIN : principalDomain;
 | 
			
		||||
        User user =
 | 
			
		||||
            new User()
 | 
			
		||||
                .withId(UUID.randomUUID())
 | 
			
		||||
                .withName(adminUser)
 | 
			
		||||
                .withEmail(adminUser + "@" + principalDomain)
 | 
			
		||||
                .withEmail(adminUser + "@" + domain)
 | 
			
		||||
                .withIsAdmin(true)
 | 
			
		||||
                .withUpdatedBy(adminUser)
 | 
			
		||||
                .withUpdatedAt(System.currentTimeMillis());
 | 
			
		||||
@ -92,11 +94,12 @@ public class DefaultAuthorizer implements Authorizer {
 | 
			
		||||
        }
 | 
			
		||||
        addOrUpdateUser(user);
 | 
			
		||||
      } catch (EntityNotFoundException | IOException ex) {
 | 
			
		||||
        String domain = principalDomain.isEmpty() ? DEFAULT_PRINCIPAL_DOMAIN : principalDomain;
 | 
			
		||||
        User user =
 | 
			
		||||
            new User()
 | 
			
		||||
                .withId(UUID.randomUUID())
 | 
			
		||||
                .withName(botUser)
 | 
			
		||||
                .withEmail(botUser + "@" + principalDomain)
 | 
			
		||||
                .withEmail(botUser + "@" + domain)
 | 
			
		||||
                .withIsBot(true)
 | 
			
		||||
                .withUpdatedBy(botUser)
 | 
			
		||||
                .withUpdatedAt(System.currentTimeMillis());
 | 
			
		||||
 | 
			
		||||
@ -18,6 +18,7 @@ import com.auth0.jwk.JwkProvider;
 | 
			
		||||
import com.auth0.jwt.JWT;
 | 
			
		||||
import com.auth0.jwt.algorithms.Algorithm;
 | 
			
		||||
import com.auth0.jwt.exceptions.JWTDecodeException;
 | 
			
		||||
import com.auth0.jwt.interfaces.Claim;
 | 
			
		||||
import com.auth0.jwt.interfaces.DecodedJWT;
 | 
			
		||||
import com.fasterxml.jackson.databind.node.TextNode;
 | 
			
		||||
import com.google.common.annotations.VisibleForTesting;
 | 
			
		||||
@ -28,7 +29,9 @@ import java.net.URL;
 | 
			
		||||
import java.security.interfaces.RSAPublicKey;
 | 
			
		||||
import java.util.Calendar;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.TimeZone;
 | 
			
		||||
import java.util.TreeMap;
 | 
			
		||||
import javax.ws.rs.container.ContainerRequestContext;
 | 
			
		||||
import javax.ws.rs.container.ContainerRequestFilter;
 | 
			
		||||
import javax.ws.rs.core.MultivaluedMap;
 | 
			
		||||
@ -37,6 +40,7 @@ import javax.ws.rs.core.UriInfo;
 | 
			
		||||
import javax.ws.rs.ext.Provider;
 | 
			
		||||
import lombok.SneakyThrows;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.apache.commons.lang.StringUtils;
 | 
			
		||||
import org.openmetadata.catalog.Entity;
 | 
			
		||||
import org.openmetadata.catalog.entity.teams.AuthenticationMechanism;
 | 
			
		||||
import org.openmetadata.catalog.entity.teams.User;
 | 
			
		||||
@ -55,12 +59,15 @@ public class JwtFilter implements ContainerRequestFilter {
 | 
			
		||||
 | 
			
		||||
  private List<String> jwtPrincipalClaims;
 | 
			
		||||
  private JwkProvider jwkProvider;
 | 
			
		||||
  private String principalDomain;
 | 
			
		||||
  private boolean enforcePrincipalDomain;
 | 
			
		||||
 | 
			
		||||
  @SuppressWarnings("unused")
 | 
			
		||||
  private JwtFilter() {}
 | 
			
		||||
 | 
			
		||||
  @SneakyThrows
 | 
			
		||||
  public JwtFilter(AuthenticationConfiguration authenticationConfiguration) {
 | 
			
		||||
  public JwtFilter(
 | 
			
		||||
      AuthenticationConfiguration authenticationConfiguration, AuthorizerConfiguration authorizerConfiguration) {
 | 
			
		||||
    this.jwtPrincipalClaims = authenticationConfiguration.getJwtPrincipalClaims();
 | 
			
		||||
 | 
			
		||||
    ImmutableList.Builder<URL> publicKeyUrlsBuilder = ImmutableList.builder();
 | 
			
		||||
@ -68,12 +75,20 @@ public class JwtFilter implements ContainerRequestFilter {
 | 
			
		||||
      publicKeyUrlsBuilder.add(new URL(publicKeyUrlStr));
 | 
			
		||||
    }
 | 
			
		||||
    this.jwkProvider = new MultiUrlJwkProvider(publicKeyUrlsBuilder.build());
 | 
			
		||||
    this.principalDomain = authorizerConfiguration.getPrincipalDomain();
 | 
			
		||||
    this.enforcePrincipalDomain = authorizerConfiguration.getEnforcePrincipalDomain();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @VisibleForTesting
 | 
			
		||||
  JwtFilter(JwkProvider jwkProvider, List<String> jwtPrincipalClaims) {
 | 
			
		||||
  JwtFilter(
 | 
			
		||||
      JwkProvider jwkProvider,
 | 
			
		||||
      List<String> jwtPrincipalClaims,
 | 
			
		||||
      String principalDomain,
 | 
			
		||||
      boolean enforcePrincipalDomain) {
 | 
			
		||||
    this.jwkProvider = jwkProvider;
 | 
			
		||||
    this.jwtPrincipalClaims = jwtPrincipalClaims;
 | 
			
		||||
    this.principalDomain = principalDomain;
 | 
			
		||||
    this.enforcePrincipalDomain = enforcePrincipalDomain;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @SneakyThrows
 | 
			
		||||
@ -114,26 +129,38 @@ public class JwtFilter implements ContainerRequestFilter {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Get username from JWT token
 | 
			
		||||
    String userName =
 | 
			
		||||
    Map<String, Claim> claims = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
 | 
			
		||||
    claims.putAll(jwt.getClaims());
 | 
			
		||||
    String jwtClaim =
 | 
			
		||||
        jwtPrincipalClaims.stream()
 | 
			
		||||
            .filter(jwt.getClaims()::containsKey)
 | 
			
		||||
            .filter(claims::containsKey)
 | 
			
		||||
            .findFirst()
 | 
			
		||||
            .map(jwt::getClaim)
 | 
			
		||||
            .map(claims::get)
 | 
			
		||||
            .map(claim -> claim.as(TextNode.class).asText())
 | 
			
		||||
            .map(
 | 
			
		||||
                authorizedClaim -> {
 | 
			
		||||
                  if (authorizedClaim.contains("@")) {
 | 
			
		||||
                    return authorizedClaim.split("@")[0];
 | 
			
		||||
                  } else {
 | 
			
		||||
                    return authorizedClaim;
 | 
			
		||||
                  }
 | 
			
		||||
                })
 | 
			
		||||
            .orElseThrow(
 | 
			
		||||
                () ->
 | 
			
		||||
                    new AuthenticationException(
 | 
			
		||||
                        "Invalid JWT token, none of the following claims are present " + jwtPrincipalClaims));
 | 
			
		||||
    String userName;
 | 
			
		||||
    String domain;
 | 
			
		||||
    if (jwtClaim.contains("@")) {
 | 
			
		||||
      userName = jwtClaim.split("@")[0];
 | 
			
		||||
      domain = jwtClaim.split("@")[1];
 | 
			
		||||
    } else {
 | 
			
		||||
      userName = jwtClaim;
 | 
			
		||||
      domain = StringUtils.EMPTY;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // validate principal domain
 | 
			
		||||
    if (enforcePrincipalDomain) {
 | 
			
		||||
      if (!domain.equals(principalDomain)) {
 | 
			
		||||
        throw new AuthenticationException(
 | 
			
		||||
            String.format("Not Authorized! Email does not match the principal domain %s", principalDomain));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // validate bot token
 | 
			
		||||
    if (jwt.getClaims().containsKey(BOT_CLAIM) && jwt.getClaims().get(BOT_CLAIM).asBoolean()) {
 | 
			
		||||
    if (claims.containsKey(BOT_CLAIM) && claims.get(BOT_CLAIM).asBoolean()) {
 | 
			
		||||
      validateBotToken(tokenFromHeader, userName);
 | 
			
		||||
    }
 | 
			
		||||
    // Setting Security Context
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,8 @@ import org.openmetadata.catalog.security.auth.CatalogSecurityContext;
 | 
			
		||||
public class NoopFilter implements ContainerRequestFilter {
 | 
			
		||||
  @Context private UriInfo uriInfo;
 | 
			
		||||
 | 
			
		||||
  public NoopFilter(AuthenticationConfiguration authenticationConfiguration) {}
 | 
			
		||||
  public NoopFilter(
 | 
			
		||||
      AuthenticationConfiguration authenticationConfiguration, AuthorizerConfiguration authorizerConfiguration) {}
 | 
			
		||||
 | 
			
		||||
  public void filter(ContainerRequestContext containerRequestContext) {
 | 
			
		||||
    CatalogPrincipal catalogPrincipal = new CatalogPrincipal("anonymous");
 | 
			
		||||
 | 
			
		||||
@ -34,6 +34,7 @@ public final class SecurityUtil {
 | 
			
		||||
  public static final int BOT = 2;
 | 
			
		||||
  public static final int OWNER = 4;
 | 
			
		||||
  public static final int PERMISSIONS = 8;
 | 
			
		||||
  public static final String DEFAULT_PRINCIPAL_DOMAIN = "openmetadata.org";
 | 
			
		||||
 | 
			
		||||
  private SecurityUtil() {}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -49,6 +49,7 @@ import org.mockito.ArgumentCaptor;
 | 
			
		||||
class JwtFilterTest {
 | 
			
		||||
 | 
			
		||||
  private static JwtFilter jwtFilter;
 | 
			
		||||
  private static JwkProvider jwkProvider;
 | 
			
		||||
 | 
			
		||||
  private static Algorithm algorithm;
 | 
			
		||||
  private static UriInfo mockRequestURIInfo;
 | 
			
		||||
@ -65,7 +66,7 @@ class JwtFilterTest {
 | 
			
		||||
    // This is used to verify the JWT
 | 
			
		||||
    Jwk mockJwk = mock(Jwk.class);
 | 
			
		||||
    when(mockJwk.getPublicKey()).thenReturn(keyPair.getPublic());
 | 
			
		||||
    JwkProvider jwkProvider = mock(JwkProvider.class);
 | 
			
		||||
    jwkProvider = mock(JwkProvider.class);
 | 
			
		||||
    when(jwkProvider.get(algorithm.getSigningKeyId())).thenReturn(mockJwk);
 | 
			
		||||
 | 
			
		||||
    // This is needed by JwtFilter for some metadata, not very important
 | 
			
		||||
@ -75,7 +76,44 @@ class JwtFilterTest {
 | 
			
		||||
    when(mockRequestURIInfo.getRequestUri()).thenReturn(uri);
 | 
			
		||||
 | 
			
		||||
    List<String> principalClaims = List.of("sub", "email");
 | 
			
		||||
    jwtFilter = new JwtFilter(jwkProvider, principalClaims);
 | 
			
		||||
    String domain = "openmetadata.org";
 | 
			
		||||
    boolean enforcePrincipalDomain = false;
 | 
			
		||||
    jwtFilter = new JwtFilter(jwkProvider, principalClaims, domain, enforcePrincipalDomain);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  void testPrincipalDomainEnforcement() {
 | 
			
		||||
    List<String> principalClaims = List.of("EMAIL", "sub");
 | 
			
		||||
    String domain = "openmetadata.org";
 | 
			
		||||
    boolean enforcePrincipalDomain = true;
 | 
			
		||||
    jwtFilter = new JwtFilter(jwkProvider, principalClaims, domain, enforcePrincipalDomain);
 | 
			
		||||
 | 
			
		||||
    // success case
 | 
			
		||||
    String jwt =
 | 
			
		||||
        JWT.create()
 | 
			
		||||
            .withExpiresAt(Date.from(Instant.now().plus(1, ChronoUnit.DAYS)))
 | 
			
		||||
            .withClaim("email", "sam@openmetadata.org")
 | 
			
		||||
            .sign(algorithm);
 | 
			
		||||
 | 
			
		||||
    ContainerRequestContext context = createRequestContextWithJwt(jwt);
 | 
			
		||||
 | 
			
		||||
    jwtFilter.filter(context);
 | 
			
		||||
 | 
			
		||||
    ArgumentCaptor<SecurityContext> securityContextArgument = ArgumentCaptor.forClass(SecurityContext.class);
 | 
			
		||||
    verify(context, times(1)).setSecurityContext(securityContextArgument.capture());
 | 
			
		||||
 | 
			
		||||
    assertEquals("sam", securityContextArgument.getValue().getUserPrincipal().getName());
 | 
			
		||||
 | 
			
		||||
    // error case
 | 
			
		||||
    jwt =
 | 
			
		||||
        JWT.create()
 | 
			
		||||
            .withExpiresAt(Date.from(Instant.now().plus(1, ChronoUnit.DAYS)))
 | 
			
		||||
            .withClaim("email", "sam@gmail.com")
 | 
			
		||||
            .sign(algorithm);
 | 
			
		||||
    ContainerRequestContext newContext = createRequestContextWithJwt(jwt);
 | 
			
		||||
 | 
			
		||||
    Exception exception = assertThrows(AuthenticationException.class, () -> jwtFilter.filter(newContext));
 | 
			
		||||
    assertTrue(exception.getMessage().toLowerCase(Locale.ROOT).contains("email does not match the principal domain"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
 | 
			
		||||
@ -131,7 +131,8 @@ authorizerConfiguration:
 | 
			
		||||
  containerRequestFilter: ${AUTHORIZER_REQUEST_FILTER:-org.openmetadata.catalog.security.NoopFilter}
 | 
			
		||||
  adminPrincipals: ${AUTHORIZER_ADMIN_PRINCIPALS:-[admin]}
 | 
			
		||||
  botPrincipals: ${AUTHORIZER_INGESTION_PRINCIPALS:-[ingestion-bot]}
 | 
			
		||||
  principalDomain: ${AUTHORIZER_PRINCIPAL_DOMAIN:-""}
 | 
			
		||||
  principalDomain: ${AUTHORIZER_PRINCIPAL_DOMAIN:-"openmetadata.org"}
 | 
			
		||||
  enforcePrincipalDomain: ${AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN:-false}
 | 
			
		||||
 | 
			
		||||
authenticationConfiguration:
 | 
			
		||||
  provider: ${AUTHENTICATION_PROVIDER:-no-auth}
 | 
			
		||||
@ -141,6 +142,7 @@ authenticationConfiguration:
 | 
			
		||||
  authority: ${AUTHENTICATION_AUTHORITY:-https://accounts.google.com}
 | 
			
		||||
  clientId: ${AUTHENTICATION_CLIENT_ID:-""}
 | 
			
		||||
  callbackUrl: ${AUTHENTICATION_CALLBACK_URL:-""}
 | 
			
		||||
  jwtPrincipalClaims: ${AUTHENTICATION_JWT_PRINCIPAL_CLAIMS:-[email,preferred_username,sub]}
 | 
			
		||||
 | 
			
		||||
jwtTokenConfiguration:
 | 
			
		||||
  rsapublicKeyFilePath: ${RSA_PUBLIC_KEY_FILE_PATH:-""}
 | 
			
		||||
 | 
			
		||||
@ -64,12 +64,14 @@ services:
 | 
			
		||||
      AUTHORIZER_ADMIN_PRINCIPALS: ${AUTHORIZER_ADMIN_PRINCIPALS:-[admin]}
 | 
			
		||||
      AUTHORIZER_INGESTION_PRINCIPALS: ${AUTHORIZER_INGESTION_PRINCIPALS:-[ingestion-bot]}
 | 
			
		||||
      AUTHORIZER_PRINCIPAL_DOMAIN: ${AUTHORIZER_PRINCIPAL_DOMAIN:-""}
 | 
			
		||||
      AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN: ${AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN:-false}
 | 
			
		||||
      AUTHENTICATION_PROVIDER: ${AUTHENTICATION_PROVIDER:-no-auth}
 | 
			
		||||
      CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME: ${CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME:-""}
 | 
			
		||||
      AUTHENTICATION_PUBLIC_KEYS: ${AUTHENTICATION_PUBLIC_KEY:-[https://www.googleapis.com/oauth2/v3/certs]}
 | 
			
		||||
      AUTHENTICATION_AUTHORITY: ${AUTHENTICATION_AUTHORITY:-https://accounts.google.com}
 | 
			
		||||
      AUTHENTICATION_CLIENT_ID: ${AUTHENTICATION_CLIENT_ID:-""}
 | 
			
		||||
      AUTHENTICATION_CALLBACK_URL: ${AUTHENTICATION_CALLBACK_URL:-""}
 | 
			
		||||
      AUTHENTICATION_JWT_PRINCIPAL_CLAIMS: ${AUTHENTICATION_JWT_PRINCIPAL_CLAIMS:-[email,preferred_username,sub]}
 | 
			
		||||
      # OpenMetadata Server Airflow Configuration
 | 
			
		||||
      AIRFLOW_HOST: ${AIRFLOW_HOST:-http://ingestion:8080}
 | 
			
		||||
      SERVER_HOST_API_URL: ${SERVER_HOST_API_URL:-http://localhost:8585/api}
 | 
			
		||||
 | 
			
		||||
@ -53,12 +53,14 @@ services:
 | 
			
		||||
      AUTHORIZER_ADMIN_PRINCIPALS: ${AUTHORIZER_ADMIN_PRINCIPALS:-[admin]}
 | 
			
		||||
      AUTHORIZER_INGESTION_PRINCIPALS: ${AUTHORIZER_INGESTION_PRINCIPAL:-[ingestion-bot]}
 | 
			
		||||
      AUTHORIZER_PRINCIPAL_DOMAIN: ${AUTHORIZER_PRINCIPAL_DOMAIN:-""}
 | 
			
		||||
      AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN: ${AUTHORIZER_ENFORCE_PRINCIPAL_DOMAIN:-false}
 | 
			
		||||
      AUTHENTICATION_PROVIDER: ${AUTHENTICATION_PROVIDER:-no-auth}
 | 
			
		||||
      CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME: ${CUSTOM_OIDC_AUTHENTICATION_PROVIDER_NAME:-""}
 | 
			
		||||
      AUTHENTICATION_PUBLIC_KEYS: ${AUTHENTICATION_PUBLIC_KEY:-[https://www.googleapis.com/oauth2/v3/certs]}
 | 
			
		||||
      AUTHENTICATION_AUTHORITY: ${AUTHENTICATION_AUTHORITY:-https://accounts.google.com}
 | 
			
		||||
      AUTHENTICATION_CLIENT_ID: ${AUTHENTICATION_CLIENT_ID:-""}
 | 
			
		||||
      AUTHENTICATION_CALLBACK_URL: ${AUTHENTICATION_CALLBACK_URL:-""}
 | 
			
		||||
      AUTHENTICATION_JWT_PRINCIPAL_CLAIMS: ${AUTHENTICATION_JWT_PRINCIPAL_CLAIMS:-[email,preferred_username,sub]}
 | 
			
		||||
      # OpenMetadata Server Airflow Configuration
 | 
			
		||||
      AIRFLOW_HOST: ${AIRFLOW_HOST:-http://ingestion:8080}
 | 
			
		||||
      SERVER_HOST_API_URL: ${SERVER_HOST_API_URL:-http://localhost:8585/api}
 | 
			
		||||
 | 
			
		||||
@ -316,6 +316,7 @@ export const AuthProvider = ({
 | 
			
		||||
        if (error.response) {
 | 
			
		||||
          const { status } = error.response;
 | 
			
		||||
          if (status === ClientErrors.UNAUTHORIZED) {
 | 
			
		||||
            showErrorToast(error);
 | 
			
		||||
            resetUserDetails(true);
 | 
			
		||||
          } else if (status === ClientErrors.FORBIDDEN) {
 | 
			
		||||
            showErrorToast(jsonData['api-error-messages']['forbidden-error']);
 | 
			
		||||
 | 
			
		||||
@ -12,11 +12,25 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import { AxiosError } from 'axios';
 | 
			
		||||
import { isString } from 'lodash';
 | 
			
		||||
import { isEmpty, isString } from 'lodash';
 | 
			
		||||
import { toast } from 'react-toastify';
 | 
			
		||||
import jsonData from '../jsons/en';
 | 
			
		||||
import { getErrorText } from './StringsUtils';
 | 
			
		||||
 | 
			
		||||
export const hashCode = (str: string) => {
 | 
			
		||||
  let hash = 0,
 | 
			
		||||
    i,
 | 
			
		||||
    chr;
 | 
			
		||||
  if (isEmpty(str)) return hash;
 | 
			
		||||
  for (i = 0; i < str.length; i++) {
 | 
			
		||||
    chr = str.charCodeAt(i);
 | 
			
		||||
    hash = (hash << 5) - hash + chr;
 | 
			
		||||
    hash |= 0; // Convert to 32bit integer
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return hash;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Display an error toast message.
 | 
			
		||||
 * @param error error text or AxiosError object
 | 
			
		||||
@ -39,11 +53,17 @@ export const showErrorToast = (
 | 
			
		||||
    errorMessage = getErrorText(error, fallback);
 | 
			
		||||
    // do not show error toasts for 401
 | 
			
		||||
    // since they will be intercepted and the user will be redirected to the signin page
 | 
			
		||||
    if (error && error.response?.status === 401) {
 | 
			
		||||
    // except for principal domain mismatch errors
 | 
			
		||||
    if (
 | 
			
		||||
      error &&
 | 
			
		||||
      error.response?.status === 401 &&
 | 
			
		||||
      !errorMessage.includes('principal domain')
 | 
			
		||||
    ) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  toast.error(errorMessage, {
 | 
			
		||||
    toastId: hashCode(errorMessage),
 | 
			
		||||
    autoClose: autoCloseTimer,
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user