56 MultivaluedMap<String, String> params = context.getHttpRequest().getDecodedFormParameters();
58 String clientAssertionType = params.getFirst(OAuth2Constants.CLIENT_ASSERTION_TYPE);
59 String clientAssertion = params.getFirst(OAuth2Constants.CLIENT_ASSERTION);
61 if (clientAssertionType == null) {
62 Response challengeResponse = ClientAuthUtil.errorResponse(Response.Status.BAD_REQUEST.getStatusCode(),
"invalid_client",
"Parameter client_assertion_type is missing");
63 context.challenge(challengeResponse);
67 if (!clientAssertionType.equals(OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT)) {
68 Response challengeResponse = ClientAuthUtil.errorResponse(Response.Status.BAD_REQUEST.getStatusCode(),
"invalid_client",
"Parameter client_assertion_type has value '" 69 + clientAssertionType +
"' but expected is '" + OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT +
"'");
70 context.challenge(challengeResponse);
74 if (clientAssertion == null) {
75 Response challengeResponse = ClientAuthUtil.errorResponse(Response.Status.BAD_REQUEST.getStatusCode(),
"invalid_client",
"client_assertion parameter missing");
76 context.failure(AuthenticationFlowError.INVALID_CLIENT_CREDENTIALS, challengeResponse);
81 JWSInput jws =
new JWSInput(clientAssertion);
82 JsonWebToken token = jws.readJsonContent(JsonWebToken.class);
84 RealmModel realm = context.getRealm();
85 String clientId = token.getSubject();
86 if (clientId == null) {
87 throw new RuntimeException(
"Can't identify client. Issuer missing on JWT token");
90 context.getEvent().client(clientId);
91 ClientModel client = realm.getClientByClientId(clientId);
93 context.failure(AuthenticationFlowError.CLIENT_NOT_FOUND, null);
96 context.setClient(client);
99 if (!client.isEnabled()) {
100 context.failure(AuthenticationFlowError.CLIENT_DISABLED, null);
104 String clientSecretString = client.getSecret();
105 if (clientSecretString == null) {
106 context.failure(AuthenticationFlowError.INVALID_CLIENT_CREDENTIALS, null);
114 SecretKey clientSecret =
new SecretKeySpec(clientSecretString.getBytes(
"UTF-8"),
"HmacSHA256");
116 boolean signatureValid;
118 signatureValid = HMACProvider.verify(jws, clientSecret);
119 }
catch (RuntimeException e) {
120 Throwable cause = e.getCause() != null ? e.getCause() : e;
121 throw new RuntimeException(
"Signature on JWT token by client secret failed validation", cause);
123 if (!signatureValid) {
124 throw new RuntimeException(
"Signature on JWT token by client secret failed validation");
130 String issuerUrl = Urls.realmIssuer(context.getUriInfo().getBaseUri(), realm.getName());
131 String tokenUrl = OIDCLoginProtocolService.tokenUrl(context.getUriInfo().getBaseUriBuilder()).build(realm.getName()).toString();
132 if (!token.hasAudience(issuerUrl) && !token.hasAudience(tokenUrl)) {
133 throw new RuntimeException(
"Token audience doesn't match domain. Realm issuer is '" + issuerUrl +
"' but audience from token is '" + Arrays.asList(token.getAudience()).toString() +
"'");
136 if (!token.isActive()) {
137 throw new RuntimeException(
"Token is not active");
141 if (token.getExpiration() == 0 && token.getIssuedAt() + 10 < Time.currentTime()) {
142 throw new RuntimeException(
"Token is not active");
146 }
catch (Exception e) {
147 ServicesLogger.LOGGER.errorValidatingAssertion(e);
148 Response challengeResponse = ClientAuthUtil.errorResponse(Response.Status.BAD_REQUEST.getStatusCode(),
"unauthorized_client",
"Client authentication with client secret signed JWT failed: " + e.getMessage());
149 context.failure(AuthenticationFlowError.INVALID_CLIENT_CREDENTIALS, challengeResponse);