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()));
});
}
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))));
}
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);
}
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);
});
});
}
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);
}
});
});
}
Aggregations