Search in sources :

Example 1 with ChallengeFailedException

use of io.trino.server.security.oauth2.ChallengeFailedException in project trino by trinodb.

the class OAuth2Service method finishOAuth2Challenge.

public Response finishOAuth2Challenge(String state, String code, URI callbackUri, Optional<String> nonce) {
    Optional<String> handlerState;
    try {
        Claims stateClaims = parseState(state);
        handlerState = Optional.ofNullable(stateClaims.get(HANDLER_STATE_CLAIM, String.class));
    } catch (ChallengeFailedException | RuntimeException e) {
        LOG.debug(e, "Authentication response could not be verified invalid state: state=%s", state);
        return Response.status(BAD_REQUEST).entity(getInternalFailureHtml("Authentication response could not be verified")).cookie(NonceCookie.delete()).build();
    }
    // Note: the Web UI may be disabled, so REST requests can not redirect to a success or error page inside of the Web UI
    try {
        // fetch access token
        OAuth2Response oauth2Response = client.getOAuth2Response(code, callbackUri);
        Claims parsedToken = validateAndParseOAuth2Response(oauth2Response, nonce).orElseThrow(() -> new ChallengeFailedException("invalid access token"));
        // determine expiration
        Instant validUntil = determineExpiration(oauth2Response.getValidUntil(), parsedToken.getExpiration());
        if (handlerState.isEmpty()) {
            return Response.seeOther(URI.create(UI_LOCATION)).cookie(OAuthWebUiCookie.create(oauth2Response.getAccessToken(), validUntil), NonceCookie.delete()).build();
        }
        tokenHandler.setAccessToken(handlerState.get(), oauth2Response.getAccessToken());
        Response.ResponseBuilder builder = Response.ok(getSuccessHtml());
        if (webUiOAuthEnabled) {
            builder.cookie(OAuthWebUiCookie.create(oauth2Response.getAccessToken(), validUntil));
        }
        return builder.cookie(NonceCookie.delete()).build();
    } catch (ChallengeFailedException | RuntimeException e) {
        LOG.debug(e, "Authentication response could not be verified: state=%s", state);
        handlerState.ifPresent(value -> tokenHandler.setTokenExchangeError(value, format("Authentication response could not be verified: state=%s", value)));
        return Response.status(BAD_REQUEST).cookie(NonceCookie.delete()).entity(getInternalFailureHtml("Authentication response could not be verified")).build();
    }
}
Also used : OAuth2Response(io.trino.server.security.oauth2.OAuth2Client.OAuth2Response) OAuth2Response(io.trino.server.security.oauth2.OAuth2Client.OAuth2Response) Response(javax.ws.rs.core.Response) JsonResponseHandler(io.airlift.http.client.JsonResponseHandler) GET(javax.ws.rs.HttpMethod.GET) Date(java.util.Date) AUTHORIZATION(com.google.common.net.HttpHeaders.AUTHORIZATION) JwtParser(io.jsonwebtoken.JwtParser) Random(java.util.Random) SecureRandom(java.security.SecureRandom) Duration(java.time.Duration) Map(java.util.Map) UriBuilder(javax.ws.rs.core.UriBuilder) URI(java.net.URI) OAuth2Response(io.trino.server.security.oauth2.OAuth2Client.OAuth2Response) BAD_REQUEST(javax.ws.rs.core.Response.Status.BAD_REQUEST) ImmutableSet(com.google.common.collect.ImmutableSet) Collection(java.util.Collection) Set(java.util.Set) Instant(java.time.Instant) AUDIENCE(io.jsonwebtoken.Claims.AUDIENCE) String.format(java.lang.String.format) Key(java.security.Key) Response(javax.ws.rs.core.Response) SigningKeyResolver(io.jsonwebtoken.SigningKeyResolver) OAuthWebUiCookie(io.trino.server.ui.OAuthWebUiCookie) Optional(java.util.Optional) JsonResponseHandler.createJsonResponseHandler(io.airlift.http.client.JsonResponseHandler.createJsonResponseHandler) OAuth2WebUiInstalled(io.trino.server.ui.OAuth2WebUiInstalled) HttpClient(io.airlift.http.client.HttpClient) Instant.now(java.time.Instant.now) Logger(io.airlift.log.Logger) Strings.nullToEmpty(com.google.common.base.Strings.nullToEmpty) JwtUtil.newJwtBuilder(io.trino.server.security.jwt.JwtUtil.newJwtBuilder) Claims(io.jsonwebtoken.Claims) Inject(javax.inject.Inject) Verify.verify(com.google.common.base.Verify.verify) DefaultClaims(io.jsonwebtoken.impl.DefaultClaims) Objects.requireNonNull(java.util.Objects.requireNonNull) Request(io.airlift.http.client.Request) TemporalAmount(java.time.temporal.TemporalAmount) UI_LOCATION(io.trino.server.ui.FormWebUiAuthenticationFilter.UI_LOCATION) JwtUtil.newJwtParserBuilder(io.trino.server.security.jwt.JwtUtil.newJwtParserBuilder) Keys.hmacShaKeyFor(io.jsonwebtoken.security.Keys.hmacShaKeyFor) BaseEncoding(com.google.common.io.BaseEncoding) Resources(com.google.common.io.Resources) JsonCodec.mapJsonCodec(io.airlift.json.JsonCodec.mapJsonCodec) UTF_8(java.nio.charset.StandardCharsets.UTF_8) IOException(java.io.IOException) Hashing.sha256(com.google.common.hash.Hashing.sha256) Ordering(com.google.common.collect.Ordering) VisibleForTesting(com.google.common.annotations.VisibleForTesting) Claims(io.jsonwebtoken.Claims) DefaultClaims(io.jsonwebtoken.impl.DefaultClaims) Instant(java.time.Instant)

Example 2 with ChallengeFailedException

use of io.trino.server.security.oauth2.ChallengeFailedException in project trino by trinodb.

the class OAuth2Authenticator method createIdentity.

@Override
protected Optional<Identity> createIdentity(String token) throws UserMappingException {
    try {
        Optional<Map<String, Object>> claims = service.convertTokenToClaims(token);
        if (claims.isEmpty()) {
            return Optional.empty();
        }
        String principal = (String) claims.get().get(principalField);
        Identity.Builder builder = Identity.forUser(userMapping.mapUser(principal));
        builder.withPrincipal(new BasicPrincipal(principal));
        groupsField.flatMap(field -> Optional.ofNullable((List<String>) claims.get().get(field))).ifPresent(groups -> builder.withGroups(ImmutableSet.copyOf(groups)));
        return Optional.of(builder.build());
    } catch (ChallengeFailedException e) {
        return Optional.empty();
    }
}
Also used : ImmutableSet(com.google.common.collect.ImmutableSet) UserMapping(io.trino.server.security.UserMapping) UUID(java.util.UUID) UserMapping.createUserMapping(io.trino.server.security.UserMapping.createUserMapping) BasicPrincipal(io.trino.spi.security.BasicPrincipal) String.format(java.lang.String.format) ContainerRequestContext(javax.ws.rs.container.ContainerRequestContext) Inject(javax.inject.Inject) OAuth2TokenExchangeResource.getInitiateUri(io.trino.server.security.oauth2.OAuth2TokenExchangeResource.getInitiateUri) List(java.util.List) AbstractBearerAuthenticator(io.trino.server.security.AbstractBearerAuthenticator) Identity(io.trino.spi.security.Identity) Map(java.util.Map) Objects.requireNonNull(java.util.Objects.requireNonNull) AuthenticationException(io.trino.server.security.AuthenticationException) Optional(java.util.Optional) OAuth2TokenExchangeResource.getTokenUri(io.trino.server.security.oauth2.OAuth2TokenExchangeResource.getTokenUri) URI(java.net.URI) UserMappingException(io.trino.server.security.UserMappingException) BasicPrincipal(io.trino.spi.security.BasicPrincipal) Identity(io.trino.spi.security.Identity) Map(java.util.Map)

Example 3 with ChallengeFailedException

use of io.trino.server.security.oauth2.ChallengeFailedException in project trino by trinodb.

the class OAuth2WebUiAuthenticationFilter method filter.

@Override
public void filter(ContainerRequestContext request) {
    String path = request.getUriInfo().getRequestUri().getPath();
    if (path.equals(DISABLED_LOCATION)) {
        return;
    }
    // doesn't seem very useful if you have OAuth, and would be very complex.
    if (!request.getSecurityContext().isSecure()) {
        // send 401 to REST api calls and redirect to others
        if (path.startsWith("/ui/api/")) {
            sendWwwAuthenticate(request, "Unauthorized", ImmutableSet.of(TRINO_FORM_LOGIN));
            return;
        }
        request.abortWith(Response.seeOther(DISABLED_LOCATION_URI).build());
        return;
    }
    Optional<Map<String, Object>> claims;
    try {
        claims = getAccessToken(request);
        if (claims.isEmpty()) {
            needAuthentication(request);
            return;
        }
    } catch (ChallengeFailedException e) {
        LOG.debug(e, "Invalid token: %s", e.getMessage());
        sendErrorMessage(request, UNAUTHORIZED, "Unauthorized");
        return;
    }
    try {
        Object principal = claims.get().get(principalField);
        if (!isValidPrincipal(principal)) {
            LOG.debug("Invalid principal field: %s. Expected principal to be non-empty", principalField);
            sendErrorMessage(request, UNAUTHORIZED, "Unauthorized");
            return;
        }
        String principalName = (String) principal;
        Identity.Builder builder = Identity.forUser(userMapping.mapUser(principalName));
        builder.withPrincipal(new BasicPrincipal(principalName));
        groupsField.flatMap(field -> Optional.ofNullable((List<String>) claims.get().get(field))).ifPresent(groups -> builder.withGroups(ImmutableSet.copyOf(groups)));
        setAuthenticatedIdentity(request, builder.build());
    } catch (UserMappingException e) {
        sendErrorMessage(request, UNAUTHORIZED, firstNonNull(e.getMessage(), "Unauthorized"));
    }
}
Also used : Logger(io.airlift.log.Logger) OAuth2Service(io.trino.server.security.oauth2.OAuth2Service) TRINO_FORM_LOGIN(io.trino.server.ui.FormWebUiAuthenticationFilter.TRINO_FORM_LOGIN) CALLBACK_ENDPOINT(io.trino.server.security.oauth2.OAuth2CallbackResource.CALLBACK_ENDPOINT) ServletSecurityUtils.sendWwwAuthenticate(io.trino.server.ServletSecurityUtils.sendWwwAuthenticate) ContainerRequestContext(javax.ws.rs.container.ContainerRequestContext) Inject(javax.inject.Inject) ServletSecurityUtils.sendErrorMessage(io.trino.server.ServletSecurityUtils.sendErrorMessage) ServletSecurityUtils.setAuthenticatedIdentity(io.trino.server.ServletSecurityUtils.setAuthenticatedIdentity) Identity(io.trino.spi.security.Identity) Map(java.util.Map) Objects.requireNonNull(java.util.Objects.requireNonNull) DISABLED_LOCATION(io.trino.server.ui.FormWebUiAuthenticationFilter.DISABLED_LOCATION) UserMappingException(io.trino.server.security.UserMappingException) UNAUTHORIZED(javax.ws.rs.core.Response.Status.UNAUTHORIZED) ImmutableSet(com.google.common.collect.ImmutableSet) UserMapping(io.trino.server.security.UserMapping) DISABLED_LOCATION_URI(io.trino.server.ui.FormWebUiAuthenticationFilter.DISABLED_LOCATION_URI) ChallengeFailedException(io.trino.server.security.oauth2.ChallengeFailedException) BasicPrincipal(io.trino.spi.security.BasicPrincipal) OAuth2Config(io.trino.server.security.oauth2.OAuth2Config) List(java.util.List) Response(javax.ws.rs.core.Response) OAUTH2_COOKIE(io.trino.server.ui.OAuthWebUiCookie.OAUTH2_COOKIE) Optional(java.util.Optional) JwtException(io.jsonwebtoken.JwtException) MoreObjects.firstNonNull(com.google.common.base.MoreObjects.firstNonNull) BasicPrincipal(io.trino.spi.security.BasicPrincipal) ChallengeFailedException(io.trino.server.security.oauth2.ChallengeFailedException) UserMappingException(io.trino.server.security.UserMappingException) ServletSecurityUtils.setAuthenticatedIdentity(io.trino.server.ServletSecurityUtils.setAuthenticatedIdentity) Identity(io.trino.spi.security.Identity) Map(java.util.Map)

Aggregations

ImmutableSet (com.google.common.collect.ImmutableSet)3 Map (java.util.Map)3 Objects.requireNonNull (java.util.Objects.requireNonNull)3 Optional (java.util.Optional)3 Inject (javax.inject.Inject)3 Logger (io.airlift.log.Logger)2 UserMapping (io.trino.server.security.UserMapping)2 UserMappingException (io.trino.server.security.UserMappingException)2 String.format (java.lang.String.format)2 URI (java.net.URI)2 VisibleForTesting (com.google.common.annotations.VisibleForTesting)1 MoreObjects.firstNonNull (com.google.common.base.MoreObjects.firstNonNull)1 Strings.nullToEmpty (com.google.common.base.Strings.nullToEmpty)1 Verify.verify (com.google.common.base.Verify.verify)1 Ordering (com.google.common.collect.Ordering)1 Hashing.sha256 (com.google.common.hash.Hashing.sha256)1 BaseEncoding (com.google.common.io.BaseEncoding)1 Resources (com.google.common.io.Resources)1 AUTHORIZATION (com.google.common.net.HttpHeaders.AUTHORIZATION)1 HttpClient (io.airlift.http.client.HttpClient)1