KEYCLOAK-14202 Client Policy - Executor : Enforce secure signature algorithm for Signed JWT client authentication

Co-authored-by: Andrii Murashkin <amu@adorsys.com.ua>
This commit is contained in:
Takashi Norimatsu 2020-12-16 11:47:47 +09:00 committed by Marek Posolda
parent ca7c866eb4
commit 05dfac75ca
4 changed files with 451 additions and 1 deletions

View file

@ -0,0 +1,99 @@
/*
* Copyright 2020 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.clientpolicy.executor;
import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.OAuth2Constants;
import org.keycloak.OAuthErrorException;
import org.keycloak.component.ComponentModel;
import org.keycloak.crypto.Algorithm;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.JWSInputException;
import org.keycloak.models.KeycloakSession;
import org.keycloak.services.clientpolicy.ClientPolicyContext;
import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.ClientPolicyLogger;
public class SecureSigningAlgorithmForSignedJwtEnforceExecutor implements ClientPolicyExecutorProvider {
private static final Logger logger = Logger.getLogger(SecureSigningAlgorithmForSignedJwtEnforceExecutor.class);
private final KeycloakSession session;
private final ComponentModel componentModel;
public SecureSigningAlgorithmForSignedJwtEnforceExecutor(KeycloakSession session, ComponentModel componentModel) {
this.session = session;
this.componentModel = componentModel;
}
@Override
public String getName() {
return componentModel.getName();
}
@Override
public String getProviderId() {
return componentModel.getProviderId();
}
@Override
public void executeOnEvent(ClientPolicyContext context) throws ClientPolicyException {
switch (context.getEvent()) {
case TOKEN_REQUEST:
case TOKEN_REFRESH:
case TOKEN_REVOKE:
case TOKEN_INTROSPECT:
case LOGOUT_REQUEST:
HttpRequest req = session.getContext().getContextObject(HttpRequest.class);
String clientAssertion = req.getDecodedFormParameters().getFirst(OAuth2Constants.CLIENT_ASSERTION);
JWSInput jws = null;
try {
jws = new JWSInput(clientAssertion);
} catch (JWSInputException e) {
throw new ClientPolicyException(OAuthErrorException.INVALID_REQUEST, "not allowed input format.");
}
String alg = jws.getHeader().getAlgorithm().name();
verifySecureSigningAlgorithm(alg);
break;
default:
return;
}
}
private void verifySecureSigningAlgorithm(String signatureAlgorithm) throws ClientPolicyException {
if (signatureAlgorithm == null) {
ClientPolicyLogger.log(logger, "Signing algorithm not specified explicitly.");
return;
}
// Please change also SecureSigningAlgorithmForSignedJwtEnforceExecutorFactory.getHelpText() if you are changing any algorithms here.
switch (signatureAlgorithm) {
case Algorithm.PS256:
case Algorithm.PS384:
case Algorithm.PS512:
case Algorithm.ES256:
case Algorithm.ES384:
case Algorithm.ES512:
ClientPolicyLogger.log(logger, "Passed. signatureAlgorithm = " + signatureAlgorithm);
return;
}
ClientPolicyLogger.log(logger, "NOT allowed signatureAlgorithm = " + signatureAlgorithm);
throw new ClientPolicyException(OAuthErrorException.INVALID_REQUEST, "not allowed signature algorithm.");
}
}

View file

@ -0,0 +1,65 @@
/*
* Copyright 2020 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.services.clientpolicy.executor;
import org.keycloak.Config.Scope;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.provider.ProviderConfigProperty;
import java.util.Collections;
import java.util.List;
public class SecureSigningAlgorithmForSignedJwtEnforceExecutorFactory implements ClientPolicyExecutorProviderFactory {
public static final String PROVIDER_ID = "securesignalgjwt-enforce-executor";
@Override
public ClientPolicyExecutorProvider create(KeycloakSession session, ComponentModel model) {
return new SecureSigningAlgorithmForSignedJwtEnforceExecutor(session, model);
}
@Override
public void init(Scope config) {
}
@Override
public void postInit(KeycloakSessionFactory factory) {
}
@Override
public void close() {
}
@Override
public String getId() {
return PROVIDER_ID;
}
@Override
public String getHelpText() {
return "It refuses the client whose JWT token signature algorithms are considered not to be secure. It accepts ES256, ES384, ES512, PS256, PS384 and PS512.";
}
@Override
public List<ProviderConfigProperty> getConfigProperties() {
return Collections.emptyList();
}
}

View file

@ -4,4 +4,5 @@ org.keycloak.services.clientpolicy.executor.SecureClientAuthEnforceExecutorFacto
org.keycloak.services.clientpolicy.executor.PKCEEnforceExecutorFactory
org.keycloak.services.clientpolicy.executor.SecureSessionEnforceExecutorFactory
org.keycloak.services.clientpolicy.executor.SecureSigningAlgorithmEnforceExecutorFactory
org.keycloak.services.clientpolicy.executor.SecureRedirectUriEnforceExecutorFactory
org.keycloak.services.clientpolicy.executor.SecureRedirectUriEnforceExecutorFactory
org.keycloak.services.clientpolicy.executor.SecureSigningAlgorithmForSignedJwtEnforceExecutorFactory

View file

@ -25,18 +25,37 @@ import static org.keycloak.testsuite.admin.ApiUtil.findUserByUsername;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.core.Response;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.hamcrest.Matchers;
import org.jboss.logging.Logger;
import org.junit.After;
@ -46,6 +65,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.keycloak.OAuth2Constants;
import org.keycloak.OAuthErrorException;
import org.keycloak.adapters.AdapterUtils;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.authentication.authenticators.client.ClientIdAndSecretAuthenticator;
import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
@ -55,13 +75,21 @@ import org.keycloak.client.registration.Auth;
import org.keycloak.client.registration.ClientRegistration;
import org.keycloak.client.registration.ClientRegistrationException;
import org.keycloak.common.Profile;
import org.keycloak.common.util.Base64;
import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.KeyUtils;
import org.keycloak.common.util.KeycloakUriBuilder;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.common.util.Time;
import org.keycloak.common.util.UriUtils;
import org.keycloak.constants.ServiceUrlConstants;
import org.keycloak.crypto.KeyType;
import org.keycloak.crypto.SignatureSignerContext;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
import org.keycloak.events.EventType;
import org.keycloak.jose.jws.Algorithm;
import org.keycloak.jose.jws.JWSBuilder;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.Constants;
import org.keycloak.models.utils.KeycloakModelUtils;
@ -70,6 +98,7 @@ import org.keycloak.protocol.oidc.OIDCConfigAttributes;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.JsonWebToken;
import org.keycloak.representations.RefreshToken;
import org.keycloak.representations.idm.ClientInitialAccessCreatePresentation;
import org.keycloak.representations.idm.ClientInitialAccessPresentation;
@ -102,6 +131,7 @@ import org.keycloak.services.clientpolicy.executor.SecureRequestObjectExecutorFa
import org.keycloak.services.clientpolicy.executor.SecureResponseTypeExecutorFactory;
import org.keycloak.services.clientpolicy.executor.SecureSessionEnforceExecutorFactory;
import org.keycloak.services.clientpolicy.executor.SecureSigningAlgorithmEnforceExecutorFactory;
import org.keycloak.services.clientpolicy.executor.SecureSigningAlgorithmForSignedJwtEnforceExecutorFactory;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.admin.ApiUtil;
@ -110,6 +140,7 @@ import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer;
import org.keycloak.testsuite.client.resources.TestApplicationResourceUrls;
import org.keycloak.testsuite.client.resources.TestOIDCEndpointsApplicationResource;
import org.keycloak.testsuite.rest.resource.TestingOIDCEndpointsApplicationResource;
import org.keycloak.testsuite.rest.resource.TestingOIDCEndpointsApplicationResource.AuthorizationEndpointRequestObject;
import org.keycloak.testsuite.services.clientpolicy.condition.TestRaiseExeptionConditionFactory;
import org.keycloak.testsuite.util.OAuthClient;
@ -1235,6 +1266,260 @@ public class ClientPolicyBasicsTest extends AbstractKeycloakTest {
}
}
@Test
public void testSecureSigningAlgorithmForSignedJwtEnforceExecutor() throws Exception {
// policy including client role condition
String policyName = "MyPolicy";
createPolicy(policyName, DefaultClientPolicyProviderFactory.PROVIDER_ID, null, null, null);
logger.info("... Created Policy : " + policyName);
createCondition("ClientRolesCondition", ClientRolesConditionFactory.PROVIDER_ID, null, (ComponentRepresentation provider) -> {
setConditionClientRoles(provider, new ArrayList<>(Arrays.asList("sample-client-role-alpha", "sample-client-role-zeta")));
});
registerCondition("ClientRolesCondition", policyName);
logger.info("... Registered Condition : " + "ClientRolesCondition");
createExecutor("SecureSigningAlgorithmForSignedJwtEnforceExecutor", SecureSigningAlgorithmForSignedJwtEnforceExecutorFactory.PROVIDER_ID, null,
(ComponentRepresentation provider) -> {
});
registerExecutor("SecureSigningAlgorithmForSignedJwtEnforceExecutor", policyName);
logger.info("... Registered Executor : SecureSigningAlgorithmForSignedJwtEnforceExecutor");
// crate a client with client role
String clientAlphaId = "Alpha-App";
String clientAlphaSecret = "secretAlpha";
String cAlphaId = null;
cAlphaId = createClientByAdmin(clientAlphaId, (ClientRepresentation clientRep) -> {
clientRep.setDefaultRoles(Arrays.asList("sample-client-role-alpha", "sample-client-role-common").toArray(new String[2]));
clientRep.setSecret(clientAlphaSecret);
clientRep.setClientAuthenticatorType(JWTClientAuthenticator.PROVIDER_ID);
clientRep.setAttributes(new HashMap<>());
clientRep.getAttributes().put(OIDCConfigAttributes.TOKEN_ENDPOINT_AUTH_SIGNING_ALG, org.keycloak.crypto.Algorithm.ES256);
});
try {
ClientResource clientResource = ApiUtil.findClientByClientId(adminClient.realm(REALM_NAME), clientAlphaId);
ClientRepresentation clientRep = clientResource.toRepresentation();
KeyPair keyPair = setupJwks(org.keycloak.crypto.Algorithm.ES256, clientRep, clientResource);
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
successfulLoginAndLogoutWithSignedJWT(clientAlphaId, privateKey, publicKey);
} finally {
deleteClientByAdmin(cAlphaId);
}
}
private CloseableHttpResponse sendRequest(String requestUrl, List<NameValuePair> parameters) throws Exception {
CloseableHttpClient client = new DefaultHttpClient();
try {
HttpPost post = new HttpPost(requestUrl);
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
post.setEntity(formEntity);
return client.execute(post);
} finally {
oauth.closeClient(client);
}
}
private void successfulLoginAndLogoutWithSignedJWT(String clientId, PrivateKey privateKey, PublicKey publicKey) throws Exception {
String signedJwt = createSignedRequestToken(clientId, getRealmInfoUrl(), privateKey, publicKey, org.keycloak.crypto.Algorithm.ES256);
oauth.clientId(clientId);
oauth.doLogin("test-user@localhost", "password");
EventRepresentation loginEvent = events.expectLogin()
.client(clientId)
.assertEvent();
String sessionId = loginEvent.getSessionId();
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
//obtain access token
OAuthClient.AccessTokenResponse response = doAccessTokenRequestWithSignedJWT(code, signedJwt);
assertEquals(200, response.getStatusCode());
oauth.verifyToken(response.getAccessToken());
RefreshToken refreshToken = oauth.parseRefreshToken(response.getRefreshToken());
assertEquals(sessionId, refreshToken.getSessionState());
assertEquals(sessionId, refreshToken.getSessionState());
events.expectCodeToToken(loginEvent.getDetails().get(Details.CODE_ID), loginEvent.getSessionId())
.client(clientId)
.detail(Details.CLIENT_AUTH_METHOD, JWTClientAuthenticator.PROVIDER_ID)
.assertEvent();
//refresh token
signedJwt = createSignedRequestToken(clientId, getRealmInfoUrl(), privateKey, publicKey, org.keycloak.crypto.Algorithm.ES256);
OAuthClient.AccessTokenResponse refreshedResponse = doRefreshTokenRequestWithSignedJWT(response.getRefreshToken(), signedJwt);
assertEquals(200, refreshedResponse.getStatusCode());
//introspect token
signedJwt = createSignedRequestToken(clientId, getRealmInfoUrl(), privateKey, publicKey, org.keycloak.crypto.Algorithm.ES256);
HttpResponse tokenIntrospectionResponse = doTokenIntrospectionWithSignedJWT("access_token", refreshedResponse.getAccessToken(), signedJwt);
assertEquals(200, tokenIntrospectionResponse.getStatusLine().getStatusCode());
//revoke token
signedJwt = createSignedRequestToken(clientId, getRealmInfoUrl(), privateKey, publicKey, org.keycloak.crypto.Algorithm.ES256);
HttpResponse revokeTokenResponse = doTokenRevokeWithSignedJWT("refresh_toke", refreshedResponse.getRefreshToken(), signedJwt);
assertEquals(200, revokeTokenResponse.getStatusLine().getStatusCode());
signedJwt = createSignedRequestToken(clientId, getRealmInfoUrl(), privateKey, publicKey, org.keycloak.crypto.Algorithm.ES256);
OAuthClient.AccessTokenResponse tokenRes = doRefreshTokenRequestWithSignedJWT(refreshedResponse.getRefreshToken(), signedJwt);
assertEquals(400, tokenRes.getStatusCode());
assertEquals(OAuthErrorException.INVALID_GRANT, tokenRes.getError());
//logout
signedJwt = createSignedRequestToken(clientId, getRealmInfoUrl(), privateKey, publicKey, org.keycloak.crypto.Algorithm.ES256);
HttpResponse logoutResponse = doLogoutWithSignedJWT(refreshedResponse.getRefreshToken(), signedJwt);
assertEquals(204, logoutResponse.getStatusLine().getStatusCode());
}
private KeyPair setupJwks(String algorithm, ClientRepresentation clientRepresentation, ClientResource clientResource) throws Exception {
// generate and register client keypair
TestOIDCEndpointsApplicationResource oidcClientEndpointsResource = testingClient.testApp().oidcClientEndpoints();
oidcClientEndpointsResource.generateKeys(algorithm);
Map<String, String> generatedKeys = oidcClientEndpointsResource.getKeysAsBase64();
KeyPair keyPair = getKeyPairFromGeneratedBase64(generatedKeys, algorithm);
// use and set jwks_url
OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRepresentation).setUseJwksUrl(true);
String jwksUrl = TestApplicationResourceUrls.clientJwksUri();
OIDCAdvancedConfigWrapper.fromClientRepresentation(clientRepresentation).setJwksUrl(jwksUrl);
clientResource.update(clientRepresentation);
// set time offset, so that new keys are downloaded
setTimeOffset(20);
return keyPair;
}
private KeyPair getKeyPairFromGeneratedBase64(Map<String, String> generatedKeys, String algorithm) throws Exception {
// It seems that PemUtils.decodePrivateKey, decodePublicKey can only treat RSA type keys, not EC type keys. Therefore, these are not used.
String privateKeyBase64 = generatedKeys.get(TestingOIDCEndpointsApplicationResource.PRIVATE_KEY);
String publicKeyBase64 = generatedKeys.get(TestingOIDCEndpointsApplicationResource.PUBLIC_KEY);
PrivateKey privateKey = decodePrivateKey(Base64.decode(privateKeyBase64), algorithm);
PublicKey publicKey = decodePublicKey(Base64.decode(publicKeyBase64), algorithm);
return new KeyPair(publicKey, privateKey);
}
private static PrivateKey decodePrivateKey(byte[] der, String algorithm) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(der);
String keyAlg = getKeyAlgorithmFromJwaAlgorithm(algorithm);
KeyFactory kf = KeyFactory.getInstance(keyAlg, "BC");
return kf.generatePrivate(spec);
}
private static PublicKey decodePublicKey(byte[] der, String algorithm) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
X509EncodedKeySpec spec = new X509EncodedKeySpec(der);
String keyAlg = getKeyAlgorithmFromJwaAlgorithm(algorithm);
KeyFactory kf = KeyFactory.getInstance(keyAlg, "BC");
return kf.generatePublic(spec);
}
private String createSignedRequestToken(String clientId, String realmInfoUrl, PrivateKey privateKey, PublicKey publicKey, String algorithm) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
JsonWebToken jwt = createRequestToken(clientId, realmInfoUrl);
String kid = KeyUtils.createKeyId(publicKey);
SignatureSignerContext signer = oauth.createSigner(privateKey, kid, algorithm);
return new JWSBuilder().kid(kid).jsonContent(jwt).sign(signer);
}
private OAuthClient.AccessTokenResponse doAccessTokenRequestWithSignedJWT(String code, String signedJwt) throws Exception {
List<NameValuePair> parameters = new LinkedList<>();
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.AUTHORIZATION_CODE));
parameters.add(new BasicNameValuePair(OAuth2Constants.CODE, code));
parameters.add(new BasicNameValuePair(OAuth2Constants.REDIRECT_URI, oauth.getRedirectUri()));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION, signedJwt));
CloseableHttpResponse response = sendRequest(oauth.getAccessTokenUrl(), parameters);
return new OAuthClient.AccessTokenResponse(response);
}
private OAuthClient.AccessTokenResponse doRefreshTokenRequestWithSignedJWT(String refreshToken, String signedJwt) throws Exception {
List<NameValuePair> parameters = new LinkedList<>();
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.REFRESH_TOKEN));
parameters.add(new BasicNameValuePair(OAuth2Constants.REFRESH_TOKEN, refreshToken));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION, signedJwt));
CloseableHttpResponse response = sendRequest(oauth.getRefreshTokenUrl(), parameters);
return new OAuthClient.AccessTokenResponse(response);
}
private HttpResponse doTokenIntrospectionWithSignedJWT(String tokenType, String tokenToIntrospect, String signedJwt) throws Exception {
List<NameValuePair> parameters = new LinkedList<>();
parameters.add(new BasicNameValuePair("token", tokenToIntrospect));
parameters.add(new BasicNameValuePair("token_type_hint", tokenType));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION, signedJwt));
return sendRequest(oauth.getTokenIntrospectionUrl(), parameters);
}
private HttpResponse doTokenRevokeWithSignedJWT(String tokenType, String tokenToIntrospect, String signedJwt) throws Exception {
List<NameValuePair> parameters = new LinkedList<>();
parameters.add(new BasicNameValuePair("token", tokenToIntrospect));
parameters.add(new BasicNameValuePair("token_type_hint", tokenType));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION, signedJwt));
return sendRequest(oauth.getTokenRevocationUrl(), parameters);
}
private HttpResponse doLogoutWithSignedJWT(String refreshToken, String signedJwt) throws Exception {
List<NameValuePair> parameters = new LinkedList<>();
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.REFRESH_TOKEN));
parameters.add(new BasicNameValuePair(OAuth2Constants.REFRESH_TOKEN, refreshToken));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION, signedJwt));
return sendRequest(oauth.getLogoutUrl().build(), parameters);
}
private JsonWebToken createRequestToken(String clientId, String realmInfoUrl) {
JsonWebToken reqToken = new JsonWebToken();
reqToken.id(AdapterUtils.generateId());
reqToken.issuer(clientId);
reqToken.subject(clientId);
reqToken.audience(realmInfoUrl);
int now = Time.currentTime();
reqToken.issuedAt(now);
reqToken.expiration(now + 10);
reqToken.notBefore(now);
return reqToken;
}
private static String getKeyAlgorithmFromJwaAlgorithm(String jwaAlgorithm) {
String keyAlg = null;
switch (jwaAlgorithm) {
case org.keycloak.crypto.Algorithm.RS256:
case org.keycloak.crypto.Algorithm.RS384:
case org.keycloak.crypto.Algorithm.RS512:
case org.keycloak.crypto.Algorithm.PS256:
case org.keycloak.crypto.Algorithm.PS384:
case org.keycloak.crypto.Algorithm.PS512:
keyAlg = KeyType.RSA;
break;
case org.keycloak.crypto.Algorithm.ES256:
case org.keycloak.crypto.Algorithm.ES384:
case org.keycloak.crypto.Algorithm.ES512:
keyAlg = KeyType.EC;
break;
default :
throw new RuntimeException("Unsupported signature algorithm");
}
return keyAlg;
}
private String getRealmInfoUrl() {
String authServerBaseUrl = UriUtils.getOrigin(oauth.getRedirectUri()) + "/auth";
return KeycloakUriBuilder.fromUri(authServerBaseUrl).path(ServiceUrlConstants.REALM_INFO_PATH).build(REALM_NAME).toString();
}
private AuthorizationEndpointRequestObject createValidRequestObjectForSecureRequestObjectExecutor(String clientId) throws URISyntaxException {
AuthorizationEndpointRequestObject requestObject = new AuthorizationEndpointRequestObject();
requestObject.id(KeycloakModelUtils.generateId());