KEYCLOAK-14289 OAuth Authorization Server Metadata for Token Revocation
This commit is contained in:
parent
97400827d2
commit
cd76ed0d74
3 changed files with 79 additions and 8 deletions
|
@ -118,6 +118,15 @@ public class OIDCConfigurationRepresentation {
|
|||
@JsonProperty("tls_client_certificate_bound_access_tokens")
|
||||
private Boolean tlsClientCertificateBoundAccessTokens;
|
||||
|
||||
@JsonProperty("revocation_endpoint")
|
||||
private String revocationEndpoint;
|
||||
|
||||
@JsonProperty("revocation_endpoint_auth_methods_supported")
|
||||
private List<String> revocationEndpointAuthMethodsSupported;
|
||||
|
||||
@JsonProperty("revocation_endpoint_auth_signing_alg_values_supported")
|
||||
private List<String> revocationEndpointAuthSigningAlgValuesSupported;
|
||||
|
||||
protected Map<String, Object> otherClaims = new HashMap<String, Object>();
|
||||
|
||||
public String getIssuer() {
|
||||
|
@ -347,6 +356,30 @@ public class OIDCConfigurationRepresentation {
|
|||
this.tlsClientCertificateBoundAccessTokens = tlsClientCertificateBoundAccessTokens;
|
||||
}
|
||||
|
||||
public String getRevocationEndpoint() {
|
||||
return revocationEndpoint;
|
||||
}
|
||||
|
||||
public void setRevocationEndpoint(String revocationEndpoint) {
|
||||
this.revocationEndpoint = revocationEndpoint;
|
||||
}
|
||||
|
||||
public List<String> getRevocationEndpointAuthMethodsSupported() {
|
||||
return revocationEndpointAuthMethodsSupported;
|
||||
}
|
||||
|
||||
public void setRevocationEndpointAuthMethodsSupported(List<String> revocationEndpointAuthMethodsSupported) {
|
||||
this.revocationEndpointAuthMethodsSupported = revocationEndpointAuthMethodsSupported;
|
||||
}
|
||||
|
||||
public List<String> getRevocationEndpointAuthSigningAlgValuesSupported() {
|
||||
return revocationEndpointAuthSigningAlgValuesSupported;
|
||||
}
|
||||
|
||||
public void setRevocationEndpointAuthSigningAlgValuesSupported(List<String> revocationEndpointAuthSigningAlgValuesSupported) {
|
||||
this.revocationEndpointAuthSigningAlgValuesSupported = revocationEndpointAuthSigningAlgValuesSupported;
|
||||
}
|
||||
|
||||
@JsonAnyGetter
|
||||
public Map<String, Object> getOtherClaims() {
|
||||
return otherClaims;
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.keycloak.wellknown.WellKnownProvider;
|
|||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
@ -134,6 +135,14 @@ public class OIDCWellKnownProvider implements WellKnownProvider {
|
|||
// https://tools.ietf.org/html/draft-ietf-oauth-mtls-08#section-6.2
|
||||
config.setTlsClientCertificateBoundAccessTokens(true);
|
||||
|
||||
URI revocationEndpoint = frontendUriBuilder.clone().path(OIDCLoginProtocolService.class, "revoke")
|
||||
.build(realm.getName(), OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||
if (isHttps(revocationEndpoint)) {
|
||||
config.setRevocationEndpoint(revocationEndpoint.toString());
|
||||
config.setRevocationEndpointAuthMethodsSupported(getClientAuthMethodsSupported());
|
||||
config.setRevocationEndpointAuthSigningAlgValuesSupported(getSupportedClientSigningAlgorithms(false));
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
|
@ -200,4 +209,8 @@ public class OIDCWellKnownProvider implements WellKnownProvider {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isHttps(URI uri) {
|
||||
return uri.getScheme().equals("https");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ import java.net.URI;
|
|||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
|
@ -102,7 +103,7 @@ public class OIDCWellKnownProviderTest extends AbstractKeycloakTest {
|
|||
public void testDiscovery() {
|
||||
Client client = ClientBuilder.newClient();
|
||||
try {
|
||||
OIDCConfigurationRepresentation oidcConfig = getOIDCDiscoveryRepresentation(client);
|
||||
OIDCConfigurationRepresentation oidcConfig = getOIDCDiscoveryRepresentation(client, OAuthClient.AUTH_SERVER_ROOT);
|
||||
|
||||
// URIs are filled
|
||||
assertEquals(oidcConfig.getAuthorizationEndpoint(), OIDCLoginProtocolService.authUrl(UriBuilder.fromUri(OAuthClient.AUTH_SERVER_ROOT)).build("test").toString());
|
||||
|
@ -161,6 +162,28 @@ public class OIDCWellKnownProviderTest extends AbstractKeycloakTest {
|
|||
// https://tools.ietf.org/html/draft-ietf-oauth-mtls-08#section-6.2
|
||||
Assert.assertTrue(oidcConfig.getTlsClientCertificateBoundAccessTokens());
|
||||
|
||||
// Token Revocation
|
||||
assertEquals(oidcConfig.getRevocationEndpoint(), oauth.getTokenRevocationUrl());
|
||||
Assert.assertNames(oidcConfig.getRevocationEndpointAuthMethodsSupported(), "client_secret_basic",
|
||||
"client_secret_post", "private_key_jwt", "client_secret_jwt", "tls_client_auth");
|
||||
Assert.assertNames(oidcConfig.getRevocationEndpointAuthSigningAlgValuesSupported(), Algorithm.PS256,
|
||||
Algorithm.PS384, Algorithm.PS512, Algorithm.RS256, Algorithm.RS384, Algorithm.RS512, Algorithm.ES256,
|
||||
Algorithm.ES384, Algorithm.ES512, Algorithm.HS256, Algorithm.HS384, Algorithm.HS512);
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpDiscovery() {
|
||||
Client client = ClientBuilder.newClient();
|
||||
try {
|
||||
OIDCConfigurationRepresentation oidcConfig = getOIDCDiscoveryRepresentation(client, "http://localhost:8180/auth");
|
||||
|
||||
// Token Revocation
|
||||
assertNull(oidcConfig.getRevocationEndpoint());
|
||||
Assert.assertNull(oidcConfig.getRevocationEndpointAuthMethodsSupported());
|
||||
Assert.assertNull(oidcConfig.getRevocationEndpointAuthSigningAlgValuesSupported());
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
|
@ -175,7 +198,7 @@ public class OIDCWellKnownProviderTest extends AbstractKeycloakTest {
|
|||
|
||||
Client client = ClientBuilder.newClient();
|
||||
try {
|
||||
OIDCConfigurationRepresentation oidcConfig = getOIDCDiscoveryRepresentation(client);
|
||||
OIDCConfigurationRepresentation oidcConfig = getOIDCDiscoveryRepresentation(client, OAuthClient.AUTH_SERVER_ROOT);
|
||||
|
||||
// assert issuer matches
|
||||
assertEquals(idToken.getIssuer(), oidcConfig.getIssuer());
|
||||
|
@ -214,23 +237,25 @@ public class OIDCWellKnownProviderTest extends AbstractKeycloakTest {
|
|||
public void testIntrospectionEndpointClaim() throws IOException {
|
||||
Client client = ClientBuilder.newClient();
|
||||
try {
|
||||
ObjectNode oidcConfig = JsonSerialization.readValue(getOIDCDiscoveryConfiguration(client), ObjectNode.class);
|
||||
assertEquals(oidcConfig.get("introspection_endpoint").asText(), getOIDCDiscoveryRepresentation(client).getIntrospectionEndpoint());
|
||||
ObjectNode oidcConfig = JsonSerialization
|
||||
.readValue(getOIDCDiscoveryConfiguration(client, OAuthClient.AUTH_SERVER_ROOT), ObjectNode.class);
|
||||
assertEquals(oidcConfig.get("introspection_endpoint").asText(),
|
||||
getOIDCDiscoveryRepresentation(client, OAuthClient.AUTH_SERVER_ROOT).getIntrospectionEndpoint());
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
private OIDCConfigurationRepresentation getOIDCDiscoveryRepresentation(Client client) {
|
||||
private OIDCConfigurationRepresentation getOIDCDiscoveryRepresentation(Client client, String uriTemplate) {
|
||||
try {
|
||||
return JsonSerialization.readValue(getOIDCDiscoveryConfiguration(client), OIDCConfigurationRepresentation.class);
|
||||
return JsonSerialization.readValue(getOIDCDiscoveryConfiguration(client, uriTemplate), OIDCConfigurationRepresentation.class);
|
||||
} catch (IOException cause) {
|
||||
throw new RuntimeException("Failed to parse OIDC configuration", cause);
|
||||
}
|
||||
}
|
||||
|
||||
private String getOIDCDiscoveryConfiguration(Client client) {
|
||||
UriBuilder builder = UriBuilder.fromUri(OAuthClient.AUTH_SERVER_ROOT);
|
||||
private String getOIDCDiscoveryConfiguration(Client client, String uriTemplate) {
|
||||
UriBuilder builder = UriBuilder.fromUri(uriTemplate);
|
||||
URI oidcDiscoveryUri = RealmsResource.wellKnownProviderUrl(builder).build("test", OIDCWellKnownProviderFactory.PROVIDER_ID);
|
||||
WebTarget oidcDiscoveryTarget = client.target(oidcDiscoveryUri);
|
||||
|
||||
|
|
Loading…
Reference in a new issue