use of io.quarkus.security.AuthenticationRedirectException in project quarkus by quarkusio.
the class CodeAuthenticationMechanism method processRedirectFromOidc.
private Uni<SecurityIdentity> processRedirectFromOidc(RoutingContext context, OidcTenantConfig oidcTenantConfig, IdentityProviderManager identityProviderManager, Cookie stateCookie, MultiMap requestParams) {
String[] parsedStateCookieValue = COOKIE_PATTERN.split(stateCookie.getValue());
OidcUtils.removeCookie(context, oidcTenantConfig, stateCookie.getName());
if (!isStateValid(requestParams, parsedStateCookieValue[0])) {
return Uni.createFrom().failure(new AuthenticationCompletionException());
}
if (requestParams.contains(OidcConstants.CODE_FLOW_CODE)) {
// start a new session by starting the code flow dance
Uni<TenantConfigContext> resolvedContext = resolver.resolveContext(context);
return resolvedContext.onItem().transformToUni(new Function<TenantConfigContext, Uni<? extends SecurityIdentity>>() {
@Override
public Uni<SecurityIdentity> apply(TenantConfigContext tenantContext) {
return performCodeFlow(identityProviderManager, context, tenantContext, requestParams, parsedStateCookieValue);
}
});
} else if (requestParams.contains(OidcConstants.CODE_FLOW_ERROR)) {
OidcUtils.removeCookie(context, oidcTenantConfig, stateCookie.getName());
String error = requestParams.get(OidcConstants.CODE_FLOW_ERROR);
String errorDescription = requestParams.get(OidcConstants.CODE_FLOW_ERROR_DESCRIPTION);
LOG.debugf("Authentication has failed, error: %s, description: %s", error, errorDescription);
if (oidcTenantConfig.authentication.errorPath.isPresent()) {
URI absoluteUri = URI.create(context.request().absoluteURI());
StringBuilder errorUri = new StringBuilder(buildUri(context, isForceHttps(oidcTenantConfig), absoluteUri.getAuthority(), oidcTenantConfig.authentication.errorPath.get()));
errorUri.append('?').append(getRequestParametersAsQuery(absoluteUri, requestParams, oidcTenantConfig));
String finalErrorUri = errorUri.toString();
LOG.debugf("Error URI: %s", finalErrorUri);
return Uni.createFrom().failure(new AuthenticationRedirectException(finalErrorUri));
} else {
return Uni.createFrom().failure(new AuthenticationCompletionException());
}
} else {
LOG.debug("State cookie is present but neither 'code' nor 'error' query parameter is returned");
return Uni.createFrom().failure(new AuthenticationCompletionException());
}
}
use of io.quarkus.security.AuthenticationRedirectException in project quarkus-resteasy-problem by TietoEVRY.
the class AuthenticationRedirectExceptionMapperTest method shouldProduceHttp302WithAllNeededHeaders.
@Test
void shouldProduceHttp302WithAllNeededHeaders() {
AuthenticationRedirectException exception = new AuthenticationRedirectException("/login");
Response response = mapper.toResponse(exception);
assertThat(response.getStatus()).isEqualTo(302);
assertThat(response.getHeaderString(HttpHeaders.LOCATION)).isEqualTo("/login");
assertThat(response.getHeaderString(HttpHeaders.CACHE_CONTROL)).isEqualTo("no-store");
assertThat(response.getHeaderString("Pragma")).isEqualTo("no-cache");
}
use of io.quarkus.security.AuthenticationRedirectException in project quarkus by quarkusio.
the class CodeAuthenticationMechanism method reAuthenticate.
private Uni<SecurityIdentity> reAuthenticate(Cookie sessionCookie, RoutingContext context, IdentityProviderManager identityProviderManager, TenantConfigContext configContext) {
context.put(TenantConfigContext.class.getName(), configContext);
return resolver.getTokenStateManager().getTokens(context, configContext.oidcConfig, sessionCookie.getValue(), getTokenStateRequestContext).chain(new Function<AuthorizationCodeTokens, Uni<? extends SecurityIdentity>>() {
@Override
public Uni<? extends SecurityIdentity> apply(AuthorizationCodeTokens session) {
if (isBackChannelLogoutPendingAndValid(configContext, session.getIdToken())) {
return OidcUtils.removeSessionCookie(context, configContext.oidcConfig, sessionCookie.getName(), resolver.getTokenStateManager()).chain(new Function<Void, Uni<? extends SecurityIdentity>>() {
@Override
public Uni<SecurityIdentity> apply(Void t) {
return Uni.createFrom().nullItem();
}
});
}
context.put(OidcConstants.ACCESS_TOKEN_VALUE, session.getAccessToken());
context.put(AuthorizationCodeTokens.class.getName(), session);
return authenticate(identityProviderManager, context, new IdTokenCredential(session.getIdToken(), isInternalIdToken(session.getIdToken(), configContext))).call(new Function<SecurityIdentity, Uni<?>>() {
@Override
public Uni<Void> apply(SecurityIdentity identity) {
if (isLogout(context, configContext)) {
fireEvent(SecurityEvent.Type.OIDC_LOGOUT_RP_INITIATED, identity);
return buildLogoutRedirectUriUni(context, configContext, session.getIdToken());
}
return VOID_UNI;
}
}).onFailure().recoverWithUni(new Function<Throwable, Uni<? extends SecurityIdentity>>() {
@Override
public Uni<? extends SecurityIdentity> apply(Throwable t) {
if (t instanceof AuthenticationRedirectException) {
throw (AuthenticationRedirectException) t;
}
if (!(t instanceof TokenAutoRefreshException)) {
boolean expired = (t.getCause() instanceof InvalidJwtException) && ((InvalidJwtException) t.getCause()).hasErrorCode(ErrorCodes.EXPIRED);
if (!expired) {
LOG.debugf("Authentication failure: %s", t.getCause());
throw new AuthenticationCompletionException(t.getCause());
}
if (!configContext.oidcConfig.token.refreshExpired) {
LOG.debug("Token has expired, token refresh is not allowed");
throw new AuthenticationCompletionException(t.getCause());
}
LOG.debug("Token has expired, trying to refresh it");
return refreshSecurityIdentity(configContext, session.getRefreshToken(), context, identityProviderManager, false, null);
} else {
return refreshSecurityIdentity(configContext, session.getRefreshToken(), context, identityProviderManager, true, ((TokenAutoRefreshException) t).getSecurityIdentity());
}
}
});
}
});
}
use of io.quarkus.security.AuthenticationRedirectException in project quarkus by quarkusio.
the class CodeAuthenticationMechanism method performCodeFlow.
private Uni<SecurityIdentity> performCodeFlow(IdentityProviderManager identityProviderManager, RoutingContext context, TenantConfigContext configContext, MultiMap requestParams, String[] parsedStateCookieValue) {
String userPath = null;
String userQuery = null;
// This is an original redirect from IDP, check if the original request path and query need to be restored
CodeAuthenticationStateBean stateBean = getCodeAuthenticationBean(parsedStateCookieValue, configContext);
if (stateBean != null && stateBean.getRestorePath() != null) {
String restorePath = stateBean.getRestorePath();
int userQueryIndex = restorePath.indexOf("?");
if (userQueryIndex >= 0) {
userPath = restorePath.substring(0, userQueryIndex);
if (userQueryIndex + 1 < restorePath.length()) {
userQuery = restorePath.substring(userQueryIndex + 1);
}
} else {
userPath = restorePath;
}
}
final String finalUserPath = userPath;
final String finalUserQuery = userQuery;
final String code = requestParams.get(OidcConstants.CODE_FLOW_CODE);
Uni<AuthorizationCodeTokens> codeFlowTokensUni = getCodeFlowTokensUni(context, configContext, code, stateBean != null ? stateBean.getCodeVerifier() : null);
return codeFlowTokensUni.onItemOrFailure().transformToUni(new BiFunction<AuthorizationCodeTokens, Throwable, Uni<? extends SecurityIdentity>>() {
@Override
public Uni<SecurityIdentity> apply(final AuthorizationCodeTokens tokens, final Throwable tOuter) {
if (tOuter != null) {
LOG.debugf("Exception during the code to token exchange: %s", tOuter.getMessage());
return Uni.createFrom().failure(new AuthenticationCompletionException(tOuter));
}
boolean internalIdToken = !configContext.oidcConfig.authentication.isIdTokenRequired().orElse(true);
if (tokens.getIdToken() == null) {
if (!internalIdToken) {
return Uni.createFrom().failure(new AuthenticationCompletionException("ID Token is not available"));
} else {
tokens.setIdToken(generateInternalIdToken(configContext.oidcConfig, null));
}
}
context.put(NEW_AUTHENTICATION, Boolean.TRUE);
context.put(OidcConstants.ACCESS_TOKEN_VALUE, tokens.getAccessToken());
context.put(AuthorizationCodeTokens.class.getName(), tokens);
return authenticate(identityProviderManager, context, new IdTokenCredential(tokens.getIdToken(), internalIdToken)).call(new Function<SecurityIdentity, Uni<?>>() {
@Override
public Uni<Void> apply(SecurityIdentity identity) {
if (internalIdToken && configContext.oidcConfig.allowUserInfoCache && configContext.oidcConfig.cacheUserInfoInIdtoken) {
tokens.setIdToken(generateInternalIdToken(configContext.oidcConfig, identity.getAttribute(OidcUtils.USER_INFO_ATTRIBUTE)));
}
return processSuccessfulAuthentication(context, configContext, tokens, identity);
}
}).map(new Function<SecurityIdentity, SecurityIdentity>() {
@Override
public SecurityIdentity apply(SecurityIdentity identity) {
boolean removeRedirectParams = configContext.oidcConfig.authentication.isRemoveRedirectParameters();
if (removeRedirectParams || finalUserPath != null || finalUserQuery != null) {
URI absoluteUri = URI.create(context.request().absoluteURI());
StringBuilder finalUriWithoutQuery = new StringBuilder(buildUri(context, isForceHttps(configContext.oidcConfig), absoluteUri.getAuthority(), (finalUserPath != null ? finalUserPath : absoluteUri.getRawPath())));
if (!removeRedirectParams) {
finalUriWithoutQuery.append('?').append(getRequestParametersAsQuery(absoluteUri, requestParams, configContext.oidcConfig));
}
if (finalUserQuery != null) {
finalUriWithoutQuery.append(!removeRedirectParams ? "" : "?");
finalUriWithoutQuery.append(finalUserQuery);
}
String finalRedirectUri = finalUriWithoutQuery.toString();
LOG.debugf("Final redirect URI: %s", finalRedirectUri);
throw new AuthenticationRedirectException(finalRedirectUri);
} else {
return identity;
}
}
}).onFailure().transform(new Function<Throwable, Throwable>() {
@Override
public Throwable apply(Throwable tInner) {
if (tInner instanceof AuthenticationRedirectException) {
return tInner;
}
return new AuthenticationCompletionException(tInner);
}
});
}
});
}
Aggregations