Skip to content

Commit

Permalink
Get OIDC recover from the connection failure if the discovery is disa…
Browse files Browse the repository at this point in the history
…bled
  • Loading branch information
sberyozkin committed Nov 26, 2021
1 parent 3198006 commit 7f040cf
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
import java.util.function.Function;
Expand Down Expand Up @@ -151,17 +152,20 @@ private Uni<TenantConfigContext> createTenantContext(Vertx vertx, OidcTenantConf
if (!oidcConfig.discoveryEnabled) {
if (!isServiceApp(oidcConfig)) {
if (!oidcConfig.authorizationPath.isPresent() || !oidcConfig.tokenPath.isPresent()) {
throw new OIDCException("'web-app' applications must have 'authorization-path' and 'token-path' properties "
+ "set when the discovery is disabled.");
throw new ConfigurationException(
"'web-app' applications must have 'authorization-path' and 'token-path' properties "
+ "set when the discovery is disabled.",
Set.of("quarkus.oidc.authorization-path", "quarkus.oidc.token-path"));
}
}
// JWK and introspection endpoints have to be set for both 'web-app' and 'service' applications
if (!oidcConfig.jwksPath.isPresent() && !oidcConfig.introspectionPath.isPresent()) {
if (!oidcConfig.authentication.isIdTokenRequired() && oidcConfig.authentication.isUserInfoRequired()) {
LOG.debugf("tenant %s supports only UserInfo", oidcConfig.tenantId.get());
} else {
throw new OIDCException(
"Either 'jwks-path' or 'introspection-path' properties must be set when the discovery is disabled.");
throw new ConfigurationException(
"Either 'jwks-path' or 'introspection-path' properties must be set when the discovery is disabled.",
Set.of("quarkus.oidc.jwks-path", "quarkus.oidc.introspection-path"));
}
}
}
Expand Down Expand Up @@ -254,6 +258,7 @@ protected static Uni<JsonWebKeySet> getJsonWebSetUni(OidcProviderClient client,
.withBackOff(OidcCommonUtils.CONNECTION_BACKOFF_DURATION, OidcCommonUtils.CONNECTION_BACKOFF_DURATION)
.expireIn(connectionDelayInMillisecs)
.onFailure()
.transform(t -> toOidcException(t, oidcConfig.authServerUrl.get()))
.invoke(client::close);
} else {
return client.getJsonWebKeySet();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ public class CustomTenantResolver implements TenantResolver {
@Override
public String resolve(RoutingContext context) {
String path = context.normalizedPath();
if (path.contains("recovered-no-discovery")) {
return "no-discovery";
}
if (path.endsWith("code-flow")) {
return "code-flow";
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.quarkus.it.keycloak;

import javax.annotation.security.RolesAllowed;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.eclipse.microprofile.jwt.JsonWebToken;

import io.quarkus.it.keycloak.model.User;
import io.quarkus.security.identity.SecurityIdentity;

@Path("/recovered-no-discovery/api/users")
public class UsersResourceOidcRecoveredNoDiscovery {

@Inject
SecurityIdentity identity;

@GET
@Path("/preferredUserName")
@RolesAllowed("user")
@Produces(MediaType.APPLICATION_JSON)
public User preferredUserName() {
return new User(((JsonWebToken) identity.getPrincipal()).getClaim("preferred_username"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ quarkus.oidc.client-id=quarkus-app
quarkus.oidc.credentials.secret=secret
quarkus.oidc.authentication.scopes=profile,email,phone

quarkus.oidc.no-discovery.auth-server-url=http://localhost:8180/auth/realms/quarkus2/
quarkus.oidc.no-discovery.discovery-enabled=false
quarkus.oidc.no-discovery.jwks-path=protocol/openid-connect/certs
quarkus.oidc.no-discovery.client-id=quarkus-app
quarkus.oidc.no-discovery.credentials.secret=secret
quarkus.oidc.no-discovery.authentication.scopes=profile,email,phone

quarkus.oidc.code-flow.auth-server-url=${keycloak.url}/realms/quarkus/
quarkus.oidc.code-flow.client-id=quarkus-web-app
quarkus.oidc.code-flow.credentials.secret=secret
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,20 @@
public class BearerTokenOidcRecoveredTest {

@Test
public void testSecureAccessSuccessPreferredUsername() {
public void testOidcRecoveredWithDiscovery() {
String token = getAccessToken("alice", new HashSet<>(Arrays.asList("user", "admin")));

// Server has not started
RestAssured.given().auth().oauth2(token)
.when().get("/recovered/api/users/preferredUserName")
.then()
.statusCode(500);

// Server is starting now
WiremockTestResource server = new WiremockTestResource();
server.start();
try {
RestAssured.given().auth().oauth2(getAccessToken("alice", new HashSet<>(Arrays.asList("user", "admin"))))
RestAssured.given().auth().oauth2(token)
.when().get("/recovered/api/users/preferredUserName")
.then()
.statusCode(200)
Expand All @@ -31,6 +39,30 @@ public void testSecureAccessSuccessPreferredUsername() {
}
}

@Test
public void testOidcRecoveredWithNoDiscovery() {
String token = getAccessToken("alice", new HashSet<>(Arrays.asList("user", "admin")));

// Server has not started
RestAssured.given().auth().oauth2(token)
.when().get("/recovered-no-discovery/api/users/preferredUserName")
.then()
.statusCode(500);

// Server is starting now
WiremockTestResource server = new WiremockTestResource();
server.start();
try {
RestAssured.given().auth().oauth2(token)
.when().get("/recovered-no-discovery/api/users/preferredUserName")
.then()
.statusCode(200)
.body("userName", equalTo("alice"));
} finally {
server.stop();
}
}

private String getAccessToken(String userName, Set<String> groups) {
return Jwt.preferredUserName(userName)
.groups(groups)
Expand Down

0 comments on commit 7f040cf

Please sign in to comment.