8000 Make JWT client validator hooks protected by puneetdixit200 · Pull Request #49047 · keycloak/keycloak · GitHub
[go: up one dir, main page]

Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public boolean validate() {
validateTokenActive(getAllowedClockSkew(), getMaximumExpirationTime(), isReusePermitted());
}

private boolean validateClientAssertionParameters() {
protected boolean validateClientAssertionParameters() {
String clientAssertionType = clientAssertionState.getClientAssertionType();
String clientAssertion = clientAssertionState.getClientAssertion();

Expand All @@ -92,7 +92,7 @@ private boolean validateClientAssertionParameters() {
return true;
}

private boolean validateClient() {
protected boolean validateClient() {
JsonWebToken token = clientAssertionState.getToken();

String clientId = token.getSubject();
Expand Down Expand Up @@ -133,7 +133,7 @@ private boolean validateClient() {
return true;
}

private boolean validateSignature() {
protected boolean validateSignature() {
return signatureValidator.verifySignature(this);
}

Expand All @@ -150,11 +150,11 @@ public boolean failure(String error, String errorDescription, int statusCode) {
return failure(AuthenticationFlowError.INVALID_CLIENT_CREDENTIALS, challengeResponse);
}

private boolean failure(AuthenticationFlowError error) {
protected boolean failure(AuthenticationFlowError error) {
return failure(error, null);
}

private boolean failure(AuthenticationFlowError error, Response response) {
protected boolean failure(AuthenticationFlowError error, Response response) {
context.failure(error, response);
return false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package org.keycloak.authentication.authenticators.client.extensibility;

import java.util.List;

import jakarta.ws.rs.core.Response;

import org.keycloak.authentication.AuthenticationFlowError;
import org.keycloak.authentication.authenticators.client.AbstractJWTClientValidator;
import org.keycloak.authentication.authenticators.client.FederatedJWTClientValidator;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertNotNull;

class ClientValidatorExtensibilityTest {

@Test
void validatorsExposeProtectedHooksForSubclassCustomization() {
assertNotNull(CustomJWTClientValidator.class);
assertNotNull(CustomFederatedJWTClientValidator.class);
}

private abstract static class CustomJWTClientValidator extends AbstractJWTClientValidator {

private CustomJWTClientValidator() throws Exception {
super(null, null, null);
}

@Override
protected boolean validateClientAssertionParameters() {
return true;
}

@Override
protected boolean validateClient() {
return failure(AuthenticationFlowError.CLIENT_NOT_FOUND);
}

@Override
protected boolean validateSignature() {
return failure(AuthenticationFlowError.INVALID_CLIENT_CREDENTIALS, Response.status(Response.Status.UNAUTHORIZED).build());
}

@Override
protected String getExpectedTokenIssuer() {
return "custom-issuer";
}

@Override
protected List<String> getExpectedAudiences() {
return List.of("custom-audience");
}

@Override
protected boolean isMultipleAudienceAllowed() {
return false;
}

@Override
protected int getAllowedClockSkew() {
return 0;
}

@Override
protected int getMaximumExpirationTime() {
return 300;
}

@Override
protected boolean isReusePermitted() {
return false;
}

@Override
protected String getExpectedSignatureAlgorithm() {
return "RS256";
}
}

private abstract static class CustomFederatedJWTClientValidator extends FederatedJWTClientValidator {

private CustomFederatedJWTClientValidator() throws Exception {
super(null, null, "custom-issuer", 0, true);
}

@Override
protected boolean validateClient() {
return true;
}

@Override
protected List<String> getExpectedAudiences() {
return List.of("custom-audience");
}
}
}
0