KEYCLOAK-14767 OpenShift Review Endpoint audience fix

This commit is contained in:
Sebastian Laskawiec
2020-07-15 11:33:30 +02:00
committed by Bruno Oliveira da Silva
parent cbb79f0430
commit e01159a943
4 changed files with 46 additions and 32 deletions

View File

@@ -271,18 +271,18 @@ public class TokenVerifier<T extends JsonWebToken> {
checks.remove(check);
}
private <P extends Predicate<? super T>> TokenVerifier<T> replaceCheck(Class<? extends Predicate<?>> checkClass, boolean active, P predicate) {
private <P extends Predicate<? super T>> TokenVerifier<T> replaceCheck(Class<? extends Predicate<?>> checkClass, boolean active, P... predicate) {
removeCheck(checkClass);
if (active) {
checks.add(predicate);
checks.addAll(Arrays.asList(predicate));
}
return this;
}
private <P extends Predicate<? super T>> TokenVerifier<T> replaceCheck(Predicate<? super T> check, boolean active, P predicate) {
private <P extends Predicate<? super T>> TokenVerifier<T> replaceCheck(Predicate<? super T> check, boolean active, P... predicate) {
removeCheck(check);
if (active) {
checks.add(predicate);
checks.addAll(Arrays.asList(predicate));
}
return this;
}
@@ -366,11 +366,18 @@ public class TokenVerifier<T extends JsonWebToken> {
/**
* Add check for verifying that token contains the expectedAudience
*
* @param expectedAudience Audience, which needs to be in the target token. Can't be null
* @param expectedAudiences Audiences, which needs to be in the target token. Can be <code>null</code>.
* @return This token verifier
*/
public TokenVerifier<T> audience(String expectedAudience) {
return this.replaceCheck(AudienceCheck.class, true, new AudienceCheck(expectedAudience));
public TokenVerifier<T> audience(String... expectedAudiences) {
if (expectedAudiences == null || expectedAudiences.length == 0) {
return this.replaceCheck(AudienceCheck.class, true, new AudienceCheck(null));
}
AudienceCheck[] audienceChecks = new AudienceCheck[expectedAudiences.length];
for (int i = 0; i < expectedAudiences.length; ++i) {
audienceChecks[i] = new AudienceCheck(expectedAudiences[i]);
}
return this.replaceCheck(AudienceCheck.class, true, audienceChecks);
}
/**

View File

@@ -93,7 +93,8 @@ public class OpenShiftTokenReviewEndpoint implements OIDCExtProvider, Environmen
AccessToken token = null;
try {
TokenVerifier<AccessToken> verifier = TokenVerifier.create(reviewRequest.getSpec().getToken(), AccessToken.class)
.realmUrl(Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName()));
.realmUrl(Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName()))
.audience(reviewRequest.getSpec().getAudiences());
SignatureVerifierContext verifierContext = session.getProvider(SignatureProvider.class, verifier.getHeader().getAlgorithm().name()).verifier(verifier.getHeader().getKeyId());
verifier.verifierContext(verifierContext);

View File

@@ -62,11 +62,15 @@ public class OpenShiftTokenReviewRequestRepresentation implements Serializable {
this.spec = spec;
}
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Spec implements Serializable {
@JsonProperty("token")
private String token;
@JsonProperty("audiences")
private String[] audiences;
public String getToken() {
return token;
}
@@ -75,6 +79,13 @@ public class OpenShiftTokenReviewRequestRepresentation implements Serializable {
this.token = token;
}
public String[] getAudiences() {
return audiences;
}
public void setAudiences(String[] audiences) {
this.audiences = audiences;
}
}
}

View File

@@ -18,6 +18,7 @@ import org.keycloak.events.Details;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.mappers.AudienceProtocolMapper;
import org.keycloak.protocol.oidc.mappers.GroupMembershipMapper;
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
import org.keycloak.protocol.openshift.OpenShiftTokenReviewRequestRepresentation;
@@ -84,7 +85,19 @@ public class OpenShiftTokenReviewEndpointTest extends AbstractTestRealmKeycloakT
client.setPublicClient(false);
client.setClientAuthenticatorType("testsuite-client-dummy");
testRealm.getUsers().add(UserBuilder.create().username("groups-user").password("password").addGroups("/topGroup", "/topGroup/level2group").build());
testRealm.getUsers().add(
UserBuilder.create()
.username("groups-user")
.password("password")
.addGroups("/topGroup", "/topGroup/level2group")
.role("account", "view-profile")
.build());
testRealm.getUsers().add(
UserBuilder.create()
.username("empty-audience")
.password("password")
.build());
}
@Before
@@ -228,29 +241,10 @@ public class OpenShiftTokenReviewEndpointTest extends AbstractTestRealmKeycloakT
}
@Test
public void emptyScope() throws Exception {
ClientRepresentation clientRep = testRealm().clients().findByClientId("test-app").get(0);
List<ClientScopeRepresentation> scopesBefore = testRealm().clients().get(clientRep.getId()).getDefaultClientScopes();
try (ClientAttributeUpdater cau = ClientAttributeUpdater.forClient(adminClient, "test", clientRep.getClientId())
.setConsentRequired(false)
.setFullScopeAllowed(false)
.setDefaultClientScopes(Collections.EMPTY_LIST)
.update()) {
oauth.openid(false);
try {
new Review()
.invoke()
.assertSuccess()
.assertEmptyScope();
} finally {
oauth.openid(true);
}
}
// The default client scopes should be same like before.
int scopesAfterSize = testRealm().clients().get(clientRep.getId()).getDefaultClientScopes().size();
assertEquals(scopesBefore.size(), scopesAfterSize);
public void emptyAudience() {
new Review().username("empty-audience")
.invoke()
.assertError(401, "Token verification failure");
}
@Test
@@ -382,6 +376,7 @@ public class OpenShiftTokenReviewEndpointTest extends AbstractTestRealmKeycloakT
OpenShiftTokenReviewRequestRepresentation request = new OpenShiftTokenReviewRequestRepresentation();
OpenShiftTokenReviewRequestRepresentation.Spec spec = new OpenShiftTokenReviewRequestRepresentation.Spec();
spec.setToken(token);
spec.setAudiences(new String[]{"account"});
request.setSpec(spec);
HttpPost post = new HttpPost(url);