Search in sources :

Example 1 with UserToken

use of io.gravitee.am.gateway.handler.root.service.user.model.UserToken in project gravitee-access-management by gravitee-io.

the class LogoutCallbackEndpoint method restoreCurrentSession.

/**
 * Restore current session (user and application) to properly sign out the user.
 *
 * @param routingContext the routing context
 * @param handler handler holding the potential current session
 */
private void restoreCurrentSession(RoutingContext routingContext, Handler<AsyncResult<UserToken>> handler) {
    // The OP SHOULD accept ID Tokens when the RP identified by the ID Token's aud claim and/or sid claim has a current session
    // or had a recent session at the OP, even when the exp time has passed.
    final MultiMap originalLogoutQueryParams = routingContext.get(ConstantKeys.PARAM_CONTEXT_KEY);
    if (originalLogoutQueryParams != null && originalLogoutQueryParams.contains(ConstantKeys.ID_TOKEN_HINT_KEY)) {
        final String idToken = originalLogoutQueryParams.get(ConstantKeys.ID_TOKEN_HINT_KEY);
        userService.extractSessionFromIdToken(idToken).map(userToken -> {
            // check if the user ids match
            if (userToken.getUser() != null && routingContext.user() != null) {
                User endUser = ((io.gravitee.am.gateway.handler.common.vertx.web.auth.user.User) routingContext.user().getDelegate()).getUser();
                if (!userToken.getUser().getId().equals(endUser.getId())) {
                    throw new UserNotFoundException(userToken.getUser().getId());
                }
            }
            return userToken;
        }).subscribe(currentSession -> handler.handle(Future.succeededFuture(currentSession)), error -> handler.handle(Future.succeededFuture(new UserToken())));
        return;
    }
    if (routingContext.get(Parameters.CLIENT_ID) == null) {
        logger.error("Unable to restore client for logout callback");
        handler.handle(Future.failedFuture(new InvalidRequestException("Invalid state")));
        return;
    }
    final User endUser = routingContext.user() != null ? ((io.gravitee.am.gateway.handler.common.vertx.web.auth.user.User) routingContext.user().getDelegate()).getUser() : null;
    final String clientId = routingContext.get(Parameters.CLIENT_ID);
    clientSyncService.findByClientId(clientId).subscribe(client -> handler.handle(Future.succeededFuture(new UserToken(endUser, client))), ex -> {
        logger.error("An error has occurred when getting client {}", clientId, ex);
        handler.handle(Future.failedFuture(new BadClientCredentialsException()));
    }, () -> {
        logger.error("Unknown client {}", clientId);
        handler.handle(Future.failedFuture(new BadClientCredentialsException()));
    });
}
Also used : BadClientCredentialsException(io.gravitee.am.common.exception.oauth2.BadClientCredentialsException) AuthenticationFlowContextService(io.gravitee.am.service.AuthenticationFlowContextService) RequestUtils(io.gravitee.am.gateway.handler.common.vertx.utils.RequestUtils) Logger(org.slf4j.Logger) HttpServerRequest(io.vertx.reactivex.core.http.HttpServerRequest) Client(io.gravitee.am.model.oidc.Client) CertificateManager(io.gravitee.am.gateway.handler.common.certificate.CertificateManager) LoggerFactory(org.slf4j.LoggerFactory) UserService(io.gravitee.am.gateway.handler.root.service.user.UserService) ConstantKeys(io.gravitee.am.common.utils.ConstantKeys) Domain(io.gravitee.am.model.Domain) Future(io.vertx.core.Future) RoutingContext(io.vertx.reactivex.ext.web.RoutingContext) UserNotFoundException(io.gravitee.am.service.exception.UserNotFoundException) MultiMap(io.vertx.reactivex.core.MultiMap) InvalidRequestException(io.gravitee.am.common.exception.oauth2.InvalidRequestException) UserToken(io.gravitee.am.gateway.handler.root.service.user.model.UserToken) JWTService(io.gravitee.am.gateway.handler.common.jwt.JWTService) ClientSyncService(io.gravitee.am.gateway.handler.common.client.ClientSyncService) AsyncResult(io.vertx.core.AsyncResult) User(io.gravitee.am.model.User) Handler(io.vertx.core.Handler) Parameters(io.gravitee.am.common.oauth2.Parameters) StringUtils(org.springframework.util.StringUtils) UserNotFoundException(io.gravitee.am.service.exception.UserNotFoundException) User(io.gravitee.am.model.User) MultiMap(io.vertx.reactivex.core.MultiMap) BadClientCredentialsException(io.gravitee.am.common.exception.oauth2.BadClientCredentialsException) InvalidRequestException(io.gravitee.am.common.exception.oauth2.InvalidRequestException) UserToken(io.gravitee.am.gateway.handler.root.service.user.model.UserToken)

Example 2 with UserToken

use of io.gravitee.am.gateway.handler.root.service.user.model.UserToken in project gravitee-access-management by gravitee-io.

the class LogoutEndpoint method restoreCurrentSession.

/**
 * Restore current session (user and application) to properly sign out the user.
 *
 * @param routingContext the routing context
 * @param handler handler holding the potential current session
 */
private void restoreCurrentSession(RoutingContext routingContext, Handler<AsyncResult<UserToken>> handler) {
    // The OP SHOULD accept ID Tokens when the RP identified by the ID Token's aud claim and/or sid claim has a current session
    // or had a recent session at the OP, even when the exp time has passed.
    final String idToken = routingContext.request().getParam(Parameters.ID_TOKEN_HINT);
    if (!StringUtils.isEmpty(idToken)) {
        userService.extractSessionFromIdToken(idToken).map(userToken -> {
            // check if the user ids match
            if (userToken.getUser() != null && routingContext.user() != null) {
                User endUser = ((io.gravitee.am.gateway.handler.common.vertx.web.auth.user.User) routingContext.user().getDelegate()).getUser();
                if (!userToken.getUser().getId().equals(endUser.getId())) {
                    throw new UserNotFoundException(userToken.getUser().getId());
                }
            }
            return userToken;
        }).subscribe(currentSession -> handler.handle(Future.succeededFuture(currentSession)), error -> handler.handle(Future.succeededFuture(new UserToken())));
        return;
    }
    // if no user, continue
    if (routingContext.user() == null) {
        handler.handle(Future.succeededFuture(new UserToken()));
        return;
    }
    // get client from the user's last application
    final io.gravitee.am.model.User endUser = ((io.gravitee.am.gateway.handler.common.vertx.web.auth.user.User) routingContext.user().getDelegate()).getUser();
    // whatever is the client search result, we have to return a UserToken with
    // at least the user to manage properly the user's logout information
    clientSyncService.findById(endUser.getClient()).switchIfEmpty(Maybe.defer(() -> clientSyncService.findByClientId(endUser.getClient()))).subscribe(client -> handler.handle(Future.succeededFuture(new UserToken(endUser, client, null))), error -> handler.handle(Future.succeededFuture(new UserToken(endUser, null, null))), () -> handler.handle(Future.succeededFuture(new UserToken(endUser, null, null))));
}
Also used : Client(io.gravitee.am.model.oidc.Client) Authentication(io.gravitee.am.identityprovider.api.Authentication) Maybe(io.reactivex.Maybe) LoggerFactory(org.slf4j.LoggerFactory) IdentityProviderManager(io.gravitee.am.gateway.handler.common.auth.idp.IdentityProviderManager) UserService(io.gravitee.am.gateway.handler.root.service.user.UserService) ConstantKeys(io.gravitee.am.common.utils.ConstantKeys) JWTService(io.gravitee.am.gateway.handler.common.jwt.JWTService) ClientSyncService(io.gravitee.am.gateway.handler.common.client.ClientSyncService) AsyncResult(io.vertx.core.AsyncResult) User(io.gravitee.am.model.User) SimpleAuthenticationContext(io.gravitee.am.identityprovider.api.SimpleAuthenticationContext) SocialAuthenticationProvider(io.gravitee.am.identityprovider.api.social.SocialAuthenticationProvider) UriBuilder(io.gravitee.am.common.web.UriBuilder) AuthenticationFlowContextService(io.gravitee.am.service.AuthenticationFlowContextService) RequestUtils(io.gravitee.am.gateway.handler.common.vertx.utils.RequestUtils) Logger(org.slf4j.Logger) HttpServerRequest(io.vertx.reactivex.core.http.HttpServerRequest) JWT(io.gravitee.am.common.jwt.JWT) CertificateManager(io.gravitee.am.gateway.handler.common.certificate.CertificateManager) Request(io.gravitee.am.identityprovider.api.common.Request) Domain(io.gravitee.am.model.Domain) VertxHttpServerRequest(io.gravitee.am.gateway.handler.common.vertx.core.http.VertxHttpServerRequest) Future(io.vertx.core.Future) RoutingContext(io.vertx.reactivex.ext.web.RoutingContext) WebClient(io.vertx.reactivex.ext.web.client.WebClient) UserNotFoundException(io.gravitee.am.service.exception.UserNotFoundException) UriBuilderRequest(io.gravitee.am.gateway.handler.common.vertx.utils.UriBuilderRequest) MultiMap(io.vertx.reactivex.core.MultiMap) UserToken(io.gravitee.am.gateway.handler.root.service.user.model.UserToken) Parameters(io.gravitee.am.common.oidc.Parameters) EndUserAuthentication(io.gravitee.am.gateway.handler.common.auth.user.EndUserAuthentication) CONTEXT_PATH(io.gravitee.am.gateway.handler.common.vertx.utils.UriBuilderRequest.CONTEXT_PATH) Handler(io.vertx.core.Handler) StringUtils(org.springframework.util.StringUtils) UserNotFoundException(io.gravitee.am.service.exception.UserNotFoundException) User(io.gravitee.am.model.User) User(io.gravitee.am.model.User) UserToken(io.gravitee.am.gateway.handler.root.service.user.model.UserToken)

Example 3 with UserToken

use of io.gravitee.am.gateway.handler.root.service.user.model.UserToken in project gravitee-access-management by gravitee-io.

the class LogoutEndpointHandlerTest method shouldInvokeLogoutEndpoint_targetUrl_client_id_token_restriction_mismatch.

@Test
public void shouldInvokeLogoutEndpoint_targetUrl_client_id_token_restriction_mismatch() throws Exception {
    JWT jwt = new JWT();
    jwt.setAud("client-id");
    Client client = new Client();
    client.setClientId("client-id");
    client.setPostLogoutRedirectUris(Arrays.asList("https://dev"));
    User endUser = new User();
    endUser.setId("user-id");
    endUser.setClient("client-id");
    when(userService.extractSessionFromIdToken("idToken")).thenReturn(Single.just(new UserToken(endUser, client)));
    when(userService.logout(any(), eq(false), any())).thenReturn(Completable.complete());
    router.route().order(-1).handler(routingContext -> {
        routingContext.getDelegate().setUser(new io.gravitee.am.gateway.handler.common.vertx.web.auth.user.User(endUser));
        routingContext.next();
    });
    testRequest(HttpMethod.GET, "/logout?post_logout_redirect_uri=https%3A%2F%2Ftest&id_token_hint=idToken", null, resp -> {
        String location = resp.headers().get("location");
        assertNotNull(location);
        assertTrue(location.endsWith("/error?client_id=client-id&error=invalid_request&error_description=The+post_logout_redirect_uri+MUST+match+the+registered+callback+URLs"));
    }, HttpStatusCode.FOUND_302, "Found", null);
}
Also used : User(io.gravitee.am.model.User) JWT(io.gravitee.am.common.jwt.JWT) Client(io.gravitee.am.model.oidc.Client) WebClient(io.vertx.reactivex.ext.web.client.WebClient) UserToken(io.gravitee.am.gateway.handler.root.service.user.model.UserToken) Test(org.junit.Test)

Example 4 with UserToken

use of io.gravitee.am.gateway.handler.root.service.user.model.UserToken in project gravitee-access-management by gravitee-io.

the class LogoutCallbackEndpoint method logout.

private void logout(RoutingContext routingContext) {
    // First, restore the initial query parameters (those provided when accessing /oauth/authorize on AM side).
    restoreState(routingContext, next -> {
        if (next.failed()) {
            routingContext.fail(next.cause());
            return;
        }
        // restore the session (required for the next steps)
        restoreCurrentSession(routingContext, sessionHandler -> {
            if (sessionHandler.failed()) {
                routingContext.fail(sessionHandler.cause());
                return;
            }
            final UserToken currentSession = sessionHandler.result();
            // but for safety we test it.
            if (currentSession != null) {
                // put current session in context for later use
                if (currentSession.getClient() != null) {
                    Client safeClient = new Client(currentSession.getClient());
                    safeClient.setClientSecret(null);
                    routingContext.put(ConstantKeys.CLIENT_CONTEXT_KEY, safeClient);
                }
                if (currentSession.getUser() != null) {
                    routingContext.put(ConstantKeys.USER_CONTEXT_KEY, currentSession.getUser());
                }
            }
            // invalidate session
            invalidateSession(routingContext);
        });
    });
}
Also used : Client(io.gravitee.am.model.oidc.Client) UserToken(io.gravitee.am.gateway.handler.root.service.user.model.UserToken)

Example 5 with UserToken

use of io.gravitee.am.gateway.handler.root.service.user.model.UserToken in project gravitee-access-management by gravitee-io.

the class LogoutEndpoint method logout.

private void logout(RoutingContext routingContext) {
    // restore the current session
    restoreCurrentSession(routingContext, sessionHandler -> {
        final UserToken currentSession = sessionHandler.result();
        if (currentSession != null) {
            // put current session in context for later use
            if (currentSession.getClient() != null) {
                Client safeClient = new Client(currentSession.getClient());
                safeClient.setClientSecret(null);
                routingContext.put(ConstantKeys.CLIENT_CONTEXT_KEY, safeClient);
            }
            if (currentSession.getUser() != null) {
                routingContext.put(ConstantKeys.USER_CONTEXT_KEY, currentSession.getUser());
            }
        }
        evaluateSingleSignOut(routingContext, endpointHandler -> {
            final String oidcEndSessionEndpoint = endpointHandler.result();
            if (oidcEndSessionEndpoint != null) {
                // this action will return to the AM logout callback to finally logout the user from AM
                if ("GET".equals(routingContext.request().method().name())) {
                    doRedirect(currentSession != null ? currentSession.getClient() : null, routingContext, oidcEndSessionEndpoint);
                } else {
                    // if the RP calls the OP with POST method we can't follow redirect
                    // we need to connect to the delegated OP via HTTP call
                    backChannelLogout(routingContext, oidcEndSessionEndpoint);
                }
            } else {
                // External OP do not provide EndSessionEndpoint, call the "standard" AM logout mechanism
                // to invalidate session
                invalidateSession(routingContext);
            }
        });
    });
}
Also used : Client(io.gravitee.am.model.oidc.Client) WebClient(io.vertx.reactivex.ext.web.client.WebClient) UserToken(io.gravitee.am.gateway.handler.root.service.user.model.UserToken)

Aggregations

UserToken (io.gravitee.am.gateway.handler.root.service.user.model.UserToken)6 Client (io.gravitee.am.model.oidc.Client)5 User (io.gravitee.am.model.User)3 MultiMap (io.vertx.reactivex.core.MultiMap)3 WebClient (io.vertx.reactivex.ext.web.client.WebClient)3 JWT (io.gravitee.am.common.jwt.JWT)2 ConstantKeys (io.gravitee.am.common.utils.ConstantKeys)2 CertificateManager (io.gravitee.am.gateway.handler.common.certificate.CertificateManager)2 ClientSyncService (io.gravitee.am.gateway.handler.common.client.ClientSyncService)2 JWTService (io.gravitee.am.gateway.handler.common.jwt.JWTService)2 RequestUtils (io.gravitee.am.gateway.handler.common.vertx.utils.RequestUtils)2 UserService (io.gravitee.am.gateway.handler.root.service.user.UserService)2 Domain (io.gravitee.am.model.Domain)2 AuthenticationFlowContextService (io.gravitee.am.service.AuthenticationFlowContextService)2 UserNotFoundException (io.gravitee.am.service.exception.UserNotFoundException)2 AsyncResult (io.vertx.core.AsyncResult)2 Future (io.vertx.core.Future)2 Handler (io.vertx.core.Handler)2 HttpServerRequest (io.vertx.reactivex.core.http.HttpServerRequest)2 RoutingContext (io.vertx.reactivex.ext.web.RoutingContext)2