Skip to content

Commit

Permalink
Verify primary OIDC token first before requesting UserInfo
Browse files Browse the repository at this point in the history
  • Loading branch information
sberyozkin committed Jun 2, 2023
1 parent d87ef55 commit 1677a8f
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,19 @@ public Uni<SecurityIdentity> apply(UserInfo userInfo, Throwable t) {
}
});
} else {
final Uni<TokenVerificationResult> primaryTokenUni;
if (isInternalIdToken(request)) {
if (vertxContext.get(NEW_AUTHENTICATION) == Boolean.TRUE) {
// No need to verify it in this case as 'CodeAuthenticationMechanism' has just created it
primaryTokenUni = Uni.createFrom()
.item(new TokenVerificationResult(OidcUtils.decodeJwtContent(request.getToken().getToken()), null));
} else {
primaryTokenUni = verifySelfSignedTokenUni(resolvedContext, request.getToken().getToken());
}
} else {
primaryTokenUni = verifyTokenUni(resolvedContext, request.getToken().getToken(), isIdToken(request), null);
}

// Verify Code Flow access token first if it is available and has to be verified.
// It may be refreshed if it has or has nearly expired
Uni<TokenVerificationResult> codeAccessTokenUni = verifyCodeFlowAccessTokenUni(vertxContext, request,
Expand All @@ -143,7 +156,7 @@ public Uni<SecurityIdentity> apply(TokenVerificationResult codeAccessTokenResult
}
vertxContext.put(CODE_ACCESS_TOKEN_RESULT, codeAccessTokenResult);
}
return getUserInfoAndCreateIdentity(vertxContext, request, resolvedContext);
return getUserInfoAndCreateIdentity(primaryTokenUni, vertxContext, request, resolvedContext);
}
});

Expand All @@ -168,12 +181,16 @@ public Uni<SecurityIdentity> apply(TokenVerificationResult codeAccessToken, Thro
vertxContext.put(CODE_ACCESS_TOKEN_RESULT, codeAccessToken);
}

return createSecurityIdentityWithOidcServer(vertxContext, request, resolvedContext, userInfo);
Uni<TokenVerificationResult> tokenUni = verifyTokenUni(resolvedContext, request.getToken().getToken(),
false, userInfo);

return createSecurityIdentityWithOidcServer(tokenUni, vertxContext, request, resolvedContext, userInfo);
}
});
}

private Uni<SecurityIdentity> getUserInfoAndCreateIdentity(RoutingContext vertxContext, TokenAuthenticationRequest request,
private Uni<SecurityIdentity> getUserInfoAndCreateIdentity(Uni<TokenVerificationResult> tokenUni,
RoutingContext vertxContext, TokenAuthenticationRequest request,
TenantConfigContext resolvedContext) {

Uni<UserInfo> userInfo = resolvedContext.oidcConfig.authentication.isUserInfoRequired().orElse(false)
Expand All @@ -187,7 +204,7 @@ public Uni<SecurityIdentity> apply(UserInfo userInfo, Throwable t) {
if (t != null) {
return Uni.createFrom().failure(new AuthenticationFailedException(t));
}
return createSecurityIdentityWithOidcServer(vertxContext, request, resolvedContext, userInfo);
return createSecurityIdentityWithOidcServer(tokenUni, vertxContext, request, resolvedContext, userInfo);
}
});
}
Expand All @@ -205,20 +222,9 @@ private boolean isOpaqueAccessToken(RoutingContext vertxContext, TokenAuthentica
return false;
}

private Uni<SecurityIdentity> createSecurityIdentityWithOidcServer(RoutingContext vertxContext,
TokenAuthenticationRequest request, TenantConfigContext resolvedContext, final UserInfo userInfo) {
Uni<TokenVerificationResult> tokenUni = null;
if (isInternalIdToken(request)) {
if (vertxContext.get(NEW_AUTHENTICATION) == Boolean.TRUE) {
// No need to verify it in this case as 'CodeAuthenticationMechanism' has just created it
tokenUni = Uni.createFrom()
.item(new TokenVerificationResult(OidcUtils.decodeJwtContent(request.getToken().getToken()), null));
} else {
tokenUni = verifySelfSignedTokenUni(resolvedContext, request.getToken().getToken());
}
} else {
tokenUni = verifyTokenUni(resolvedContext, request.getToken().getToken(), isIdToken(request), userInfo);
}
private Uni<SecurityIdentity> createSecurityIdentityWithOidcServer(Uni<TokenVerificationResult> tokenUni,
RoutingContext vertxContext, TokenAuthenticationRequest request, TenantConfigContext resolvedContext,
final UserInfo userInfo) {

return tokenUni.onItemOrFailure()
.transformToUni(new BiFunction<TokenVerificationResult, Throwable, Uni<? extends SecurityIdentity>>() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,12 @@ quarkus.oidc.tenant-hybrid-service.application-type=service

# Tenant Hybrid Web-App
quarkus.oidc.tenant-hybrid-webapp.auth-server-url=${keycloak.url}/realms/quarkus-hybrid
quarkus.oidc.tenant-hybrid-webapp.user-info-path=http://localhost:8081/oidc/userinfo
quarkus.oidc.tenant-hybrid-webapp.client-id=quarkus-app-hybrid
quarkus.oidc.tenant-hybrid-webapp.credentials.secret=secret
quarkus.oidc.tenant-hybrid-webapp.authentication.user-info-required=true
quarkus.oidc.tenant-hybrid-webapp.allow-user-info-cache=false
quarkus.oidc.tenant-hybrid-webapp.authentication.remove-redirect-parameters=false
quarkus.oidc.tenant-hybrid-webapp.application-type=web-app

# Tenant Hybrid Web-App Service
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ public Boolean call() throws Exception {

@Test
public void testHybridWebApp() throws IOException {
RestAssured.when().post("/oidc/userinfo-endpoint-call-count").then().body(equalTo("0"));
try (final WebClient webClient = createWebClient()) {
HtmlPage page = webClient.getPage("http://localhost:8081/tenants/tenant-hybrid/api/user");
assertNotNull(getStateCookie(webClient, "tenant-hybrid-webapp"));
Expand All @@ -184,6 +185,7 @@ public void testHybridWebApp() throws IOException {
assertEquals("alice:web-app", page.getBody().asNormalizedText());
webClient.getCookieManager().clearCookies();
}
RestAssured.when().get("/oidc/userinfo-endpoint-call-count").then().body(equalTo("1"));
}

@Test
Expand Down

0 comments on commit 1677a8f

Please sign in to comment.