73 MultivaluedMap<String, String> params = context.getHttpRequest().getDecodedFormParameters();
75 String clientAssertionType = params.getFirst(OAuth2Constants.CLIENT_ASSERTION_TYPE);
76 String clientAssertion = params.getFirst(OAuth2Constants.CLIENT_ASSERTION);
78 if (clientAssertionType == null) {
79 Response challengeResponse = ClientAuthUtil.errorResponse(Response.Status.BAD_REQUEST.getStatusCode(),
"invalid_client",
"Parameter client_assertion_type is missing");
80 context.challenge(challengeResponse);
84 if (!clientAssertionType.equals(OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT)) {
85 Response challengeResponse = ClientAuthUtil.errorResponse(Response.Status.BAD_REQUEST.getStatusCode(),
"invalid_client",
"Parameter client_assertion_type has value '" 86 + clientAssertionType +
"' but expected is '" + OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT +
"'");
87 context.challenge(challengeResponse);
91 if (clientAssertion == null) {
92 Response challengeResponse = ClientAuthUtil.errorResponse(Response.Status.BAD_REQUEST.getStatusCode(),
"invalid_client",
"client_assertion parameter missing");
93 context.failure(AuthenticationFlowError.INVALID_CLIENT_CREDENTIALS, challengeResponse);
98 JWSInput jws =
new JWSInput(clientAssertion);
99 JsonWebToken token = jws.readJsonContent(JsonWebToken.class);
101 RealmModel realm = context.getRealm();
102 String clientId = token.getSubject();
103 if (clientId == null) {
104 throw new RuntimeException(
"Can't identify client. Issuer missing on JWT token");
107 context.getEvent().client(clientId);
108 ClientModel client = realm.getClientByClientId(clientId);
109 if (client == null) {
110 context.failure(AuthenticationFlowError.CLIENT_NOT_FOUND, null);
113 context.setClient(client);
116 if (!client.isEnabled()) {
117 context.failure(AuthenticationFlowError.CLIENT_DISABLED, null);
123 if (clientPublicKey == null) {
128 boolean signatureValid;
130 signatureValid = RSAProvider.verify(jws, clientPublicKey);
131 }
catch (RuntimeException e) {
132 Throwable cause = e.getCause() != null ? e.getCause() : e;
133 throw new RuntimeException(
"Signature on JWT token failed validation", cause);
135 if (!signatureValid) {
136 throw new RuntimeException(
"Signature on JWT token failed validation");
140 String issuerUrl = Urls.realmIssuer(context.getUriInfo().getBaseUri(), realm.getName());
141 String tokenUrl = OIDCLoginProtocolService.tokenUrl(context.getUriInfo().getBaseUriBuilder()).build(realm.getName()).toString();
142 if (!token.hasAudience(issuerUrl) && !token.hasAudience(tokenUrl)) {
143 throw new RuntimeException(
"Token audience doesn't match domain. Realm issuer is '" + issuerUrl +
"' but audience from token is '" + Arrays.asList(token.getAudience()).toString() +
"'");
146 if (!token.isActive()) {
147 throw new RuntimeException(
"Token is not active");
151 if (token.getExpiration() == 0 && token.getIssuedAt() + 10 < Time.currentTime()) {
152 throw new RuntimeException(
"Token is not active");
156 }
catch (Exception e) {
157 ServicesLogger.LOGGER.errorValidatingAssertion(e);
158 Response challengeResponse = ClientAuthUtil.errorResponse(Response.Status.BAD_REQUEST.getStatusCode(),
"unauthorized_client",
"Client authentication with signed JWT failed: " + e.getMessage());
159 context.failure(AuthenticationFlowError.INVALID_CLIENT_CREDENTIALS, challengeResponse);
PublicKey getSignatureValidationKey(ClientModel client, ClientAuthenticationFlowContext context, JWSInput jws)
Definition: JWTClientAuthenticator.java:163