Skip to content

Commit

Permalink
Use Uni to resolve TenantContextConfig
Browse files Browse the repository at this point in the history
  • Loading branch information
sberyozkin committed Nov 9, 2020
1 parent 0c08c3c commit a868d08
Show file tree
Hide file tree
Showing 13 changed files with 305 additions and 174 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ public enum Strategy {
* Default TokenStateManager strategy.
*/
@ConfigItem(defaultValue = "keep_all_tokens")
public Strategy strategy;
public Strategy strategy = Strategy.KEEP_ALL_TOKENS;

/**
* Default TokenStateManager keeps all tokens (ID, access and refresh)
Expand Down Expand Up @@ -1086,4 +1086,12 @@ public static enum ApplicationType {
*/
HYBRID
}

public ApplicationType getApplicationType() {
return applicationType;
}

public void setApplicationType(ApplicationType type) {
this.applicationType = type;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class BearerAuthenticationMechanism extends AbstractOidcAuthenticationMec

public Uni<SecurityIdentity> authenticate(RoutingContext context,
IdentityProviderManager identityProviderManager) {
String token = extractBearerToken(context, resolver.resolve(context, false).oidcConfig);
String token = extractBearerToken(context, resolver.resolveConfig(context));

// if a bearer token is provided try to authenticate
if (token != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,74 +86,97 @@ public Uni<Boolean> apply(Permission permission) {
public Uni<SecurityIdentity> authenticate(RoutingContext context,
IdentityProviderManager identityProviderManager) {

Cookie sessionCookie = context.request().getCookie(getSessionCookieName(resolver.resolve(context, false)));
final Cookie sessionCookie = context.request().getCookie(getSessionCookieName(resolver.resolveConfig(context)));

// if session already established, try to re-authenticate
if (sessionCookie != null) {
TenantConfigContext configContext = resolver.resolve(context, true);
Uni<TenantConfigContext> resolvedContext = resolver.resolveContext(context);
return resolvedContext.onItem()
.transformToUni(new Function<TenantConfigContext, Uni<? extends SecurityIdentity>>() {
@Override
public Uni<SecurityIdentity> apply(TenantConfigContext tenantContext) {
return reAuthenticate(sessionCookie, context, identityProviderManager, tenantContext);
}
});
}

AuthorizationCodeTokens session = resolver.getTokenStateManager().getTokens(context, configContext.oidcConfig,
sessionCookie.getValue());
final String code = context.request().getParam("code");
if (code == null) {
return Uni.createFrom().optional(Optional.empty());
}

context.put("access_token", session.getAccessToken());
return authenticate(identityProviderManager, new IdTokenCredential(session.getIdToken(), context))
.map(new Function<SecurityIdentity, SecurityIdentity>() {
@Override
public SecurityIdentity apply(SecurityIdentity identity) {
if (isLogout(context, configContext)) {
fireEvent(SecurityEvent.Type.OIDC_LOGOUT_RP_INITIATED, identity);
throw redirectToLogoutEndpoint(context, configContext, session.getIdToken());
}
// 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, code);
}
});
}

private Uni<SecurityIdentity> reAuthenticate(Cookie sessionCookie,
RoutingContext context,
IdentityProviderManager identityProviderManager,
TenantConfigContext configContext) {
AuthorizationCodeTokens session = resolver.getTokenStateManager().getTokens(context, configContext.oidcConfig,
sessionCookie.getValue());

return augmentIdentity(identity, session.getAccessToken(), session.getRefreshToken(), context);
context.put("access_token", session.getAccessToken());
return authenticate(identityProviderManager, new IdTokenCredential(session.getIdToken(), context))
.map(new Function<SecurityIdentity, SecurityIdentity>() {
@Override
public SecurityIdentity apply(SecurityIdentity identity) {
if (isLogout(context, configContext)) {
fireEvent(SecurityEvent.Type.OIDC_LOGOUT_RP_INITIATED, identity);
throw redirectToLogoutEndpoint(context, configContext, session.getIdToken());
}
}).on().failure().recoverWithItem(new Function<Throwable, SecurityIdentity>() {
@Override
public SecurityIdentity apply(Throwable throwable) {
if (throwable instanceof AuthenticationRedirectException) {
throw AuthenticationRedirectException.class.cast(throwable);
}

SecurityIdentity identity = null;

if (!(throwable instanceof TokenAutoRefreshException)) {
Throwable cause = throwable.getCause();

if (cause != null && !"expired token".equalsIgnoreCase(cause.getMessage())) {
LOG.debugf("Authentication failure: %s", cause);
throw new AuthenticationCompletionException(cause);
}
if (!configContext.oidcConfig.token.refreshExpired) {
LOG.debug("Token has expired, token refresh is not allowed");
throw new AuthenticationCompletionException(cause);
}
LOG.debug("Token has expired, trying to refresh it");
identity = trySilentRefresh(configContext, session.getRefreshToken(), context,
identityProviderManager);
if (identity == null) {
LOG.debug("SecurityIdentity is null after a token refresh");
throw new AuthenticationCompletionException();
} else {
fireEvent(SecurityEvent.Type.OIDC_SESSION_EXPIRED_AND_REFRESHED, identity);
}
return augmentIdentity(identity, session.getAccessToken(), session.getRefreshToken(), context);
}
}).on().failure().recoverWithItem(new Function<Throwable, SecurityIdentity>() {
@Override
public SecurityIdentity apply(Throwable throwable) {
if (throwable instanceof AuthenticationRedirectException) {
throw AuthenticationRedirectException.class.cast(throwable);
}

SecurityIdentity identity = null;

if (!(throwable instanceof TokenAutoRefreshException)) {
Throwable cause = throwable.getCause();

if (cause != null && !"expired token".equalsIgnoreCase(cause.getMessage())) {
LOG.debugf("Authentication failure: %s", cause);
throw new AuthenticationCompletionException(cause);
}
if (!configContext.oidcConfig.token.refreshExpired) {
LOG.debug("Token has expired, token refresh is not allowed");
throw new AuthenticationCompletionException(cause);
}
LOG.debug("Token has expired, trying to refresh it");
identity = trySilentRefresh(configContext, session.getRefreshToken(), context,
identityProviderManager);
if (identity == null) {
LOG.debug("SecurityIdentity is null after a token refresh");
throw new AuthenticationCompletionException();
} else {
fireEvent(SecurityEvent.Type.OIDC_SESSION_EXPIRED_AND_REFRESHED, identity);
}
} else {
identity = trySilentRefresh(configContext, session.getRefreshToken(), context,
identityProviderManager);
if (identity == null) {
LOG.debug("ID token can no longer be refreshed, using the current SecurityIdentity");
identity = ((TokenAutoRefreshException) throwable).getSecurityIdentity();
} else {
identity = trySilentRefresh(configContext, session.getRefreshToken(), context,
identityProviderManager);
if (identity == null) {
LOG.debug("ID token can no longer be refreshed, using the current SecurityIdentity");
identity = ((TokenAutoRefreshException) throwable).getSecurityIdentity();
} else {
fireEvent(SecurityEvent.Type.OIDC_SESSION_REFRESHED, identity);
}
fireEvent(SecurityEvent.Type.OIDC_SESSION_REFRESHED, identity);
}
return identity;
}
});
}
return identity;
}
});

// start a new session by starting the code flow dance
context.put("new_authentication", Boolean.TRUE);
return performCodeFlow(identityProviderManager, context, resolver);
}

private boolean isJavaScript(RoutingContext context) {
Expand All @@ -174,8 +197,17 @@ private boolean shouldAutoRedirect(TenantConfigContext configContext, RoutingCon

public Uni<ChallengeData> getChallenge(RoutingContext context) {

TenantConfigContext configContext = resolver.resolve(context, true);
removeCookie(context, configContext, getSessionCookieName(configContext));
Uni<TenantConfigContext> tenantContext = resolver.resolveContext(context);
return tenantContext.onItem().transformToUni(new Function<TenantConfigContext, Uni<? extends ChallengeData>>() {
@Override
public Uni<ChallengeData> apply(TenantConfigContext tenantContext) {
return getChallengeInternal(context, tenantContext);
}
});
}

public Uni<ChallengeData> getChallengeInternal(RoutingContext context, TenantConfigContext configContext) {
removeCookie(context, configContext, getSessionCookieName(configContext.oidcConfig));

if (!shouldAutoRedirect(configContext, context)) {
// If the client (usually an SPA) wants to handle the redirect manually, then
Expand Down Expand Up @@ -212,14 +244,9 @@ public Uni<ChallengeData> getChallenge(RoutingContext context) {
}

private Uni<SecurityIdentity> performCodeFlow(IdentityProviderManager identityProviderManager,
RoutingContext context, DefaultTenantConfigResolver resolver) {
RoutingContext context, TenantConfigContext configContext, String code) {

String code = context.request().getParam("code");
if (code == null) {
return Uni.createFrom().optional(Optional.empty());
}

TenantConfigContext configContext = resolver.resolve(context, true);
context.put("new_authentication", Boolean.TRUE);

Cookie stateCookie = context.getCookie(getStateCookieName(configContext));

Expand Down Expand Up @@ -362,7 +389,7 @@ private void processSuccessfulAuthentication(RoutingContext context,
String opaqueAccessToken,
String opaqueRefreshToken,
SecurityIdentity securityIdentity) {
removeCookie(context, configContext, getSessionCookieName(configContext));
removeCookie(context, configContext, getSessionCookieName(configContext.oidcConfig));

if (idToken == null) {
// it can be null if Vert.x did the remote introspection of the ID token
Expand All @@ -383,7 +410,7 @@ private void processSuccessfulAuthentication(RoutingContext context,
String cookieValue = resolver.getTokenStateManager()
.createTokenState(context, configContext.oidcConfig,
new AuthorizationCodeTokens(opaqueIdToken, opaqueAccessToken, opaqueRefreshToken));
createCookie(context, configContext.oidcConfig, getSessionCookieName(configContext), cookieValue, maxAge);
createCookie(context, configContext.oidcConfig, getSessionCookieName(configContext.oidcConfig), cookieValue, maxAge);

fireEvent(SecurityEvent.Type.OIDC_LOGIN, securityIdentity);
}
Expand Down Expand Up @@ -565,7 +592,7 @@ private boolean isForceHttps(TenantConfigContext configContext) {

private AuthenticationRedirectException redirectToLogoutEndpoint(RoutingContext context, TenantConfigContext configContext,
String idToken) {
removeCookie(context, configContext, getSessionCookieName(configContext));
removeCookie(context, configContext, getSessionCookieName(configContext.oidcConfig));
return new AuthenticationRedirectException(buildLogoutRedirectUri(configContext, idToken, context));
}

Expand All @@ -579,8 +606,8 @@ private static String getPostLogoutCookieName(TenantConfigContext configContext)
return POST_LOGOUT_COOKIE_NAME + cookieSuffix;
}

private static String getSessionCookieName(TenantConfigContext configContext) {
String cookieSuffix = getCookieSuffix(configContext.oidcConfig.tenantId.get());
private static String getSessionCookieName(OidcTenantConfig oidcConfig) {
String cookieSuffix = getCookieSuffix(oidcConfig.tenantId.get());
return SESSION_COOKIE_NAME + cookieSuffix;
}

Expand Down
Loading

0 comments on commit a868d08

Please sign in to comment.