/*
* Copyright 2016 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.testsuite.oauth;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
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.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.OAuth2Constants;
import org.keycloak.adapters.AdapterUtils;
import org.keycloak.adapters.authentication.JWTClientCredentialsProvider;
import org.keycloak.admin.client.resource.ClientAttributeCertificateResource;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.authentication.AuthenticationFlowError;
import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
import org.keycloak.common.constants.ServiceAccountConstants;
import org.keycloak.common.util.BouncyIntegration;
import org.keycloak.common.util.KeycloakUriBuilder;
import org.keycloak.common.util.KeystoreUtil;
import org.keycloak.common.util.Time;
import org.keycloak.common.util.UriUtils;
import org.keycloak.constants.ServiceUrlConstants;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.JsonWebToken;
import org.keycloak.representations.KeyStoreConfig;
import org.keycloak.representations.RefreshToken;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.EventRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.util.CertificateInfoHelper;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.auth.page.AuthRealm;
import org.keycloak.testsuite.util.ClientBuilder;
import org.keycloak.testsuite.util.ClientManager;
import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.testsuite.util.RealmBuilder;
import org.keycloak.testsuite.util.UserBuilder;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.core.Response;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
* @author Vaclav Muzikar <vmuzikar@redhat.com>
*/
public class ClientAuthSignedJWTTest extends AbstractKeycloakTest {
@Rule
public AssertEvents events = new AssertEvents(this);
private static String client1SAUserId;
private static RealmRepresentation testRealm;
private static ClientRepresentation app1, app2, app3;
private static UserRepresentation defaultUser, serviceAccountUser;
@BeforeClass
public static void beforeClientAuthSignedJWTTest() {
BouncyIntegration.init();
}
@Override
public void beforeAbstractKeycloakTest() throws Exception {
super.beforeAbstractKeycloakTest();
}
@Override
public void addTestRealms(List<RealmRepresentation> testRealms) {
RealmBuilder realmBuilder = RealmBuilder.create().name("test")
.privateKey("MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=")
.publicKey("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB")
.testEventListener();
app1 = ClientBuilder.create()
.id(KeycloakModelUtils.generateId())
.clientId("client1")
.attribute(JWTClientAuthenticator.CERTIFICATE_ATTR, "MIICnTCCAYUCBgFPPLDaTzANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdjbGllbnQxMB4XDTE1MDgxNzE3MjI0N1oXDTI1MDgxNzE3MjQyN1owEjEQMA4GA1UEAwwHY2xpZW50MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIUjjgv+V3s96O+Za9002Lp/trtGuHBeaeVL9dFKMKzO2MPqdRmHB4PqNlDdd28Rwf5Xn6iWdFpyUKOnI/yXDLhdcuFpR0sMNK/C9Lt+hSpPFLuzDqgtPgDotlMxiHIWDOZ7g9/gPYNXbNvjv8nSiyqoguoCQiiafW90bPHsiVLdP7ZIUwCcfi1qQm7FhxRJ1NiW5dvUkuCnnWEf0XR+Wzc5eC9EgB0taLFiPsSEIlWMm5xlahYyXkPdNOqZjiRnrTWm5Y4uk8ZcsD/KbPTf/7t7cQXipVaswgjdYi1kK2/zRwOhg1QwWFX/qmvdd+fLxV0R6VqRDhn7Qep2cxwMxLsCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAKE6OA46sf20bz8LZPoiNsqRwBUDkaMGXfnob7s/hJZIIwDEx0IAQ3uKsG7q9wb+aA6s+v7S340zb2k3IxuhFaHaZpAd4CyR5cn1FHylbzoZ7rI/3ASqHDqpljdJaFqPH+m7nZWtyDvtZf+gkZ8OjsndwsSBK1d/jMZPp29qYbl1+XfO7RCp/jDqro/R3saYFaIFiEZPeKn1hUJn6BO48vxH1xspSu9FmlvDOEAOz4AuM58z4zRMP49GcFdCWr1wkonJUHaSptJaQwmBwLFUkCbE5I1ixGMb7mjEud6Y5jhfzJiZMo2U8RfcjNbrN0diZl3jB6LQIwESnhYSghaTjNQ==")
.authenticatorType(JWTClientAuthenticator.PROVIDER_ID)
.serviceAccountsEnabled(true)
.build();
realmBuilder.client(app1);
app2 = ClientBuilder.create()
.id(KeycloakModelUtils.generateId())
.clientId("client2")
.directAccessGrants()
.serviceAccountsEnabled(true)
.redirectUris(OAuthClient.APP_ROOT + "/auth")
.attribute(JWTClientAuthenticator.CERTIFICATE_ATTR, "MIICnTCCAYUCBgFPPQDGxTANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdjbGllbnQxMB4XDTE1MDgxNzE4NTAwNVoXDTI1MDgxNzE4NTE0NVowEjEQMA4GA1UEAwwHY2xpZW50MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMMw3PaBffWxgS2PYSDDBp6As+cNvv9kt2C4f/RDAGmvSIHPFev9kuQiKs3Oaws3ZsV4JG3qHEuYgnh9W4vfe3DwNwtD1bjL5FYBhPBFTw0lAQECYxaBHnkjHwUKp957FqdSPPICm3LjmTcEdlH+9dpp9xHCMbbiNiWDzWI1xSxC8Fs2d0hwz1sd+Q4QeTBPIBWcPM+ICZtNG5MN+ORfayu4X+Me5d0tXG2fQO//rAevk1i5IFjKZuOjTwyKB5SJIY4b8QTeg0g/50IU7Ht00Pxw6CK02dHS+FvXHasZlD3ckomqCDjStTBWdhJo5dST0CbOqalkkpLlCCbGA1yEQRsCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAUIMeJ+EAo8eNpCG/nXImacjrKakbFnZYBGD/gqeTGaZynkX+jgBSructTHR83zSH+yELEhsAy+3BfK4EEihp+PEcRnK2fASVkHste8AQ7rlzC+HGGirlwrVhWCdizNUCGK80DE537IZ7nmZw6LFG9P5/Q2MvCsOCYjRUvMkukq6TdXBXR9tETwZ+0gpSfsOxjj0ZF7ftTRUSzx4rFfcbM9fRNdVizdOuKGc8HJPA5lLOxV6CyaYIvi3y5RlQI1OHeS34lE4w9CNPRFa/vdxXvN7ClyzA0HMFNWxBN7pC/Ht/FbhSvaAagJBHg+vCrcY5C26Oli7lAglf/zZrwUPs0w==")
.authenticatorType(JWTClientAuthenticator.PROVIDER_ID)
.build();
realmBuilder.client(app2);
// This one is for keystore-client2.p12 , which doesn't work on Sun JDK
// app2.setAttribute(JWTClientAuthenticator.CERTIFICATE_ATTR, "MIICnTCCAYUCBgFPPLGHHjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdjbGllbnQxMB4XDTE1MDgxNzE3MjMzMVoXDTI1MDgxNzE3MjUxMVowEjEQMA4GA1UEAwwHY2xpZW50MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIsatXj38fFD9fHslNrsWrubobudXYwwdZpGYqkHIhuDeSojGvhBSLmKIFmtbHMVcLEbS0dIEsSbNVrwjdFfuRuvd9Vu6Ng0JUC8fRhSeQniC3jcBuP8P4WlXK4+ir3Wlya+T6Hum9b68BiH0KyNZtFGJ6zLHuCcq9Bl0JifvibnUkDeTZPwgJNA9+GxS/x8fAkApcAbJrgBZvr57PwhbgHoZdB8aAY5f5ogbGzKDtSUMvFh+Jah39gWtn7p3VOuuMXA8SugogoH8C5m2itrPBL1UPhAcKUeWiqx4SmZe/lZo7x2WbSecNiFaiqBhIW+QbqCYW6I4u0YvuLuEe3+TC8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAZzW5DZviCxUQdV5Ab07PZkUfvImHZ73oWWHZqzUQtZtbVdzfp3cnbb2wyXtlOvingO3hgpoTxV8vbKgLbIQfvkGGHBG1F5e0QVdtikfdcwWb7cy4/9F80OD7cgG0ZAzFbQ8ZY7iS3PToBp3+4tbIK2NK0ntt/MYgJnPbHeG4V4qfgUbFm1YgEK7WpbSVU8jGuJ5DWE+mlYgECZKZ5TSlaVGs2XOm6WXrJScucNekwcBWWiHyRsFHZEDzWmzt8TLTLnnb0vVjhx3qCYxah3RbyyMZm6WLZlLAaGEcwNDO8jaA3hAjrxoOA1xEaolQfGVsb/ElelHcR1Zfe0u4Ekd4tw==");
defaultUser = UserBuilder.create()
.id(KeycloakModelUtils.generateId())
//.serviceAccountId(app1.getClientId())
.username("test-user@localhost")
.password("password")
.build();
realmBuilder.user(defaultUser);
client1SAUserId = KeycloakModelUtils.generateId();
serviceAccountUser = UserBuilder.create()
.id(client1SAUserId)
.username(ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + app1.getClientId())
.serviceAccountId(app1.getClientId())
.build();
realmBuilder.user(serviceAccountUser);
testRealm = realmBuilder.build();
testRealms.add(testRealm);
}
@Before
public void recreateApp3() {
app3 = ClientBuilder.create()
.id(KeycloakModelUtils.generateId())
.clientId("client3")
.directAccessGrants()
.authenticatorType(JWTClientAuthenticator.PROVIDER_ID)
.build();
Response resp = adminClient.realm("test").clients().create(app3);
getCleanup().addClientUuid(ApiUtil.getCreatedId(resp));
resp.close();
}
// TEST SUCCESS
@Test
public void testServiceAccountAndLogoutSuccess() throws Exception {
String client1Jwt = getClient1SignedJWT();
OAuthClient.AccessTokenResponse response = doClientCredentialsGrantRequest(client1Jwt);
assertEquals(200, response.getStatusCode());
AccessToken accessToken = oauth.verifyToken(response.getAccessToken());
RefreshToken refreshToken = oauth.verifyRefreshToken(response.getRefreshToken());
events.expectClientLogin()
.client("client1")
.user(client1SAUserId)
.session(accessToken.getSessionState())
.detail(Details.TOKEN_ID, accessToken.getId())
.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
.detail(Details.USERNAME, ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + "client1")
.detail(Details.CLIENT_AUTH_METHOD, JWTClientAuthenticator.PROVIDER_ID)
.assertEvent();
assertEquals(accessToken.getSessionState(), refreshToken.getSessionState());
client1Jwt = getClient1SignedJWT();
OAuthClient.AccessTokenResponse refreshedResponse = doRefreshTokenRequest(response.getRefreshToken(), client1Jwt);
AccessToken refreshedAccessToken = oauth.verifyToken(refreshedResponse.getAccessToken());
RefreshToken refreshedRefreshToken = oauth.verifyRefreshToken(refreshedResponse.getRefreshToken());
assertEquals(accessToken.getSessionState(), refreshedAccessToken.getSessionState());
assertEquals(accessToken.getSessionState(), refreshedRefreshToken.getSessionState());
events.expectRefresh(refreshToken.getId(), refreshToken.getSessionState())
.user(client1SAUserId)
.client("client1")
.detail(Details.CLIENT_AUTH_METHOD, JWTClientAuthenticator.PROVIDER_ID)
.assertEvent();
// Logout and assert refresh will fail
HttpResponse logoutResponse = doLogout(response.getRefreshToken(), getClient1SignedJWT());
assertEquals(204, logoutResponse.getStatusLine().getStatusCode());
events.expectLogout(accessToken.getSessionState())
.client("client1")
.user(client1SAUserId)
.removeDetail(Details.REDIRECT_URI)
.detail(Details.CLIENT_AUTH_METHOD, JWTClientAuthenticator.PROVIDER_ID)
.assertEvent();
response = doRefreshTokenRequest(response.getRefreshToken(), getClient1SignedJWT());
assertEquals(400, response.getStatusCode());
assertEquals("invalid_grant", response.getError());
events.expectRefresh(refreshToken.getId(), refreshToken.getSessionState())
.client("client1")
.user(client1SAUserId)
.removeDetail(Details.TOKEN_ID)
.removeDetail(Details.UPDATED_REFRESH_TOKEN_ID)
.detail(Details.CLIENT_AUTH_METHOD, JWTClientAuthenticator.PROVIDER_ID)
.error(Errors.INVALID_TOKEN).assertEvent();
}
@Test
public void testCodeToTokenRequestSuccess() throws Exception {
oauth.clientId("client2");
oauth.doLogin("test-user@localhost", "password");
EventRepresentation loginEvent = events.expectLogin()
.client("client2")
.assertEvent();
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
OAuthClient.AccessTokenResponse response = doAccessTokenRequest(code, getClient2SignedJWT());
assertEquals(200, response.getStatusCode());
oauth.verifyToken(response.getAccessToken());
oauth.verifyRefreshToken(response.getRefreshToken());
events.expectCodeToToken(loginEvent.getDetails().get(Details.CODE_ID), loginEvent.getSessionId())
.client("client2")
.detail(Details.CLIENT_AUTH_METHOD, JWTClientAuthenticator.PROVIDER_ID)
.assertEvent();
}
@Test
public void testDirectGrantRequestSuccess() throws Exception {
oauth.clientId("client2");
OAuthClient.AccessTokenResponse response = doGrantAccessTokenRequest("test-user@localhost", "password", getClient2SignedJWT());
assertEquals(200, response.getStatusCode());
AccessToken accessToken = oauth.verifyToken(response.getAccessToken());
RefreshToken refreshToken = oauth.verifyRefreshToken(response.getRefreshToken());
events.expectLogin()
.client("client2")
.session(accessToken.getSessionState())
.detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
.detail(Details.TOKEN_ID, accessToken.getId())
.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
.detail(Details.USERNAME, "test-user@localhost")
.detail(Details.CLIENT_AUTH_METHOD, JWTClientAuthenticator.PROVIDER_ID)
.removeDetail(Details.CODE_ID)
.removeDetail(Details.REDIRECT_URI)
.removeDetail(Details.CONSENT)
.assertEvent();
}
@Test
public void testClientWithGeneratedKeysJKS() throws Exception {
testClientWithGeneratedKeys("JKS");
}
@Test
public void testClientWithGeneratedKeysPKCS12() throws Exception {
testClientWithGeneratedKeys("PKCS12");
}
private void testClientWithGeneratedKeys(String format) throws Exception {
ClientRepresentation client = app3;
UserRepresentation user = defaultUser;
final String keyAlias = "somekey";
final String keyPassword = "pwd1";
final String storePassword = "pwd2";
// Generate new keystore (which is intended for sending to the user and store in a client app)
// with public/private keys; in KC, store the certificate itself
KeyStoreConfig keyStoreConfig = new KeyStoreConfig();
keyStoreConfig.setFormat(format);
keyStoreConfig.setKeyPassword(keyPassword);
keyStoreConfig.setStorePassword(storePassword);
keyStoreConfig.setKeyAlias(keyAlias);
client = getClient(testRealm.getRealm(), client.getId()).toRepresentation();
final String certOld = client.getAttributes().get(JWTClientAuthenticator.CERTIFICATE_ATTR);
// Generate the keystore and save the new certificate in client (in KC)
byte[] keyStoreBytes = getClientAttributeCertificateResource(testRealm.getRealm(), client.getId())
.generateAndGetKeystore(keyStoreConfig);
ByteArrayInputStream keyStoreIs = new ByteArrayInputStream(keyStoreBytes);
KeyStore keyStore = getKeystore(keyStoreIs, storePassword, format);
keyStoreIs.close();
client = getClient(testRealm.getRealm(), client.getId()).toRepresentation();
X509Certificate x509Cert = (X509Certificate) keyStore.getCertificate(keyAlias);
assertCertificate(client, certOld,
KeycloakModelUtils.getPemFromCertificate(x509Cert));
// Try to login with the new keys
oauth.clientId(client.getClientId());
PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyAlias, keyPassword.toCharArray());
KeyPair keyPair = new KeyPair(x509Cert.getPublicKey(), privateKey);
OAuthClient.AccessTokenResponse response = doGrantAccessTokenRequest(user.getUsername(),
user.getCredentials().get(0).getValue(),
getClientSignedJWT(keyPair, client.getClientId()));
assertEquals(200, response.getStatusCode());
AccessToken accessToken = oauth.verifyToken(response.getAccessToken());
RefreshToken refreshToken = oauth.verifyRefreshToken(response.getRefreshToken());
events.expectLogin()
.client(client.getClientId())
.session(accessToken.getSessionState())
.detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
.detail(Details.TOKEN_ID, accessToken.getId())
.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
.detail(Details.USERNAME, user.getUsername())
.detail(Details.CLIENT_AUTH_METHOD, JWTClientAuthenticator.PROVIDER_ID)
.removeDetail(Details.CODE_ID)
.removeDetail(Details.REDIRECT_URI)
.removeDetail(Details.CONSENT)
.assertEvent();
}
@Test
public void testUploadKeystoreJKS() throws Exception {
testUploadKeystore("JKS", "client-auth-test/keystore-client1.jks", "clientkey", "storepass");
}
@Test
public void testUploadKeystorePKCS12() throws Exception {
testUploadKeystore("PKCS12", "client-auth-test/keystore-client2.p12", "clientkey", "pwd2");
}
@Test
public void testUploadCertificatePEM() throws Exception {
testUploadKeystore(org.keycloak.services.resources.admin.ClientAttributeCertificateResource.CERTIFICATE_PEM, "client-auth-test/certificate.pem", "undefined", "undefined");
}
@Test
public void testUploadPublicKeyPEM() throws Exception {
testUploadKeystore(org.keycloak.services.resources.admin.ClientAttributeCertificateResource.PUBLIC_KEY_PEM, "client-auth-test/publickey.pem", "undefined", "undefined");
}
@Test
public void testUploadJWKS() throws Exception {
testUploadKeystore(org.keycloak.services.resources.admin.ClientAttributeCertificateResource.JSON_WEB_KEY_SET, "clientreg-test/jwks.json", "undefined", "undefined");
}
// We need to test this as a genuine REST API HTTP request
// since there's no easy and direct way to call ClientAttributeCertificateResource.uploadJksCertificate
// (and especially to create MultipartFormDataInput)
private void testUploadKeystore(String keystoreFormat, String filePath, String keyAlias, String storePassword) throws Exception {
ClientRepresentation client = getClient(testRealm.getRealm(), app3.getId()).toRepresentation();
final String certOld = client.getAttributes().get(JWTClientAuthenticator.CERTIFICATE_ATTR);
// Load the keystore file
URL fileUrl = (getClass().getClassLoader().getResource(filePath));
if (fileUrl == null) {
throw new IOException("File not found: " + filePath);
}
File keystoreFile = new File(fileUrl.getFile());
// Get admin access token, no matter it's master realm's admin
OAuthClient.AccessTokenResponse accessTokenResponse = oauth.doGrantAccessTokenRequest(
AuthRealm.MASTER, AuthRealm.ADMIN, AuthRealm.ADMIN, null, "admin-cli", null);
assertEquals(200, accessTokenResponse.getStatusCode());
final String url = suiteContext.getAuthServerInfo().getContextRoot()
+ "/auth/admin/realms/" + testRealm.getRealm()
+ "/clients/" + client.getId() + "/certificates/jwt.credential/upload-certificate";
// Prepare the HTTP request
FileBody fileBody = new FileBody(keystoreFile);
HttpEntity entity = MultipartEntityBuilder.create()
.addPart("file", fileBody)
.addTextBody("keystoreFormat", keystoreFormat)
.addTextBody("keyAlias", keyAlias)
.addTextBody("storePassword", storePassword)
.addTextBody("keyPassword", "undefined")
.build();
HttpPost httpRequest = new HttpPost(url);
httpRequest.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + accessTokenResponse.getAccessToken());
httpRequest.setEntity(entity);
// Send the request
HttpClient httpClient = HttpClients.createDefault();
HttpResponse httpResponse = httpClient.execute(httpRequest);
assertEquals(200, httpResponse.getStatusLine().getStatusCode());
client = getClient(testRealm.getRealm(), client.getId()).toRepresentation();
// Assert the uploaded certificate
if (keystoreFormat.equals(org.keycloak.services.resources.admin.ClientAttributeCertificateResource.PUBLIC_KEY_PEM)) {
String pem = new String(Files.readAllBytes(keystoreFile.toPath()));
final String publicKeyNew = client.getAttributes().get(JWTClientAuthenticator.ATTR_PREFIX + "." + CertificateInfoHelper.PUBLIC_KEY);
assertEquals("Certificates don't match", pem, publicKeyNew);
} else if (keystoreFormat.equals(org.keycloak.services.resources.admin.ClientAttributeCertificateResource.JSON_WEB_KEY_SET)) {
final String publicKeyNew = client.getAttributes().get(JWTClientAuthenticator.ATTR_PREFIX + "." + CertificateInfoHelper.PUBLIC_KEY);
// Just assert it's valid public key
PublicKey pk = KeycloakModelUtils.getPublicKey(publicKeyNew);
Assert.assertNotNull(pk);
} else if (keystoreFormat.equals(org.keycloak.services.resources.admin.ClientAttributeCertificateResource.CERTIFICATE_PEM)) {
String pem = new String(Files.readAllBytes(keystoreFile.toPath()));
assertCertificate(client, certOld, pem);
} else {
InputStream keystoreIs = new FileInputStream(keystoreFile);
KeyStore keyStore = getKeystore(keystoreIs, storePassword, keystoreFormat);
keystoreIs.close();
String pem = KeycloakModelUtils.getPemFromCertificate((X509Certificate) keyStore.getCertificate(keyAlias));
assertCertificate(client, certOld, pem);
}
}
// TEST ERRORS
@Test
public void testMissingClientAssertionType() throws Exception {
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS));
CloseableHttpResponse resp = sendRequest(oauth.getServiceAccountUrl(), parameters);
OAuthClient.AccessTokenResponse response = new OAuthClient.AccessTokenResponse(resp);
assertError(response, null, "unauthorized_client", Errors.INVALID_CLIENT_CREDENTIALS);
}
@Test
public void testInvalidClientAssertionType() throws Exception {
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION_TYPE, "invalid"));
CloseableHttpResponse resp = sendRequest(oauth.getServiceAccountUrl(), parameters);
OAuthClient.AccessTokenResponse response = new OAuthClient.AccessTokenResponse(resp);
assertError(response, null, "unauthorized_client", Errors.INVALID_CLIENT_CREDENTIALS);
}
@Test
public void testMissingClientAssertion() throws Exception {
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT));
CloseableHttpResponse resp = sendRequest(oauth.getServiceAccountUrl(), parameters);
OAuthClient.AccessTokenResponse response = new OAuthClient.AccessTokenResponse(resp);
assertError(response, null, "unauthorized_client", Errors.INVALID_CLIENT_CREDENTIALS);
}
@Test
public void testAssertionMissingIssuer() throws Exception {
String invalidJwt = getClientSignedJWT(getClient1KeyPair(), null);
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION, invalidJwt));
CloseableHttpResponse resp = sendRequest(oauth.getServiceAccountUrl(), parameters);
OAuthClient.AccessTokenResponse response = new OAuthClient.AccessTokenResponse(resp);
assertError(response, null, "unauthorized_client", Errors.INVALID_CLIENT_CREDENTIALS);
}
@Test
public void testAssertionUnknownClient() throws Exception {
String invalidJwt = getClientSignedJWT(getClient1KeyPair(), "unknown-client");
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION, invalidJwt));
CloseableHttpResponse resp = sendRequest(oauth.getServiceAccountUrl(), parameters);
OAuthClient.AccessTokenResponse response = new OAuthClient.AccessTokenResponse(resp);
assertError(response, "unknown-client", "unauthorized_client", Errors.INVALID_CLIENT_CREDENTIALS);
}
@Test
public void testAssertionDisabledClient() throws Exception {
ClientManager.realm(adminClient.realm("test")).clientId("client1").enabled(false);
String invalidJwt = getClient1SignedJWT();
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION, invalidJwt));
CloseableHttpResponse resp = sendRequest(oauth.getServiceAccountUrl(), parameters);
OAuthClient.AccessTokenResponse response = new OAuthClient.AccessTokenResponse(resp);
assertError(response, "client1", "invalid_client", Errors.CLIENT_DISABLED);
ClientManager.realm(adminClient.realm("test")).clientId("client1").enabled(true);
}
@Test
public void testAssertionUnconfiguredClientCertificate() throws Exception {
class CertificateHolder {
String certificate;
}
final CertificateHolder backupClient1Cert = new CertificateHolder();
backupClient1Cert.certificate = ApiUtil.findClientByClientId(adminClient.realm("test"), "client1")
.toRepresentation().getAttributes().get(JWTClientAuthenticator.CERTIFICATE_ATTR);
ClientManager.realm(adminClient.realm("test")).clientId("client1")
.updateAttribute(JWTClientAuthenticator.CERTIFICATE_ATTR, null);
String invalidJwt = getClient1SignedJWT();
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION, invalidJwt));
CloseableHttpResponse resp = sendRequest(oauth.getServiceAccountUrl(), parameters);
OAuthClient.AccessTokenResponse response = new OAuthClient.AccessTokenResponse(resp);
assertError(response, "client1", "unauthorized_client", "client_credentials_setup_required");
ClientManager.realm(adminClient.realm("test")).clientId("client1").updateAttribute(JWTClientAuthenticator.CERTIFICATE_ATTR, backupClient1Cert.certificate);
}
@Test
public void testAssertionInvalidSignature() throws Exception {
// JWT for client1, but signed by privateKey of client2
String invalidJwt = getClientSignedJWT(getClient2KeyPair(), "client1");
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION, invalidJwt));
CloseableHttpResponse resp = sendRequest(oauth.getServiceAccountUrl(), parameters);
OAuthClient.AccessTokenResponse response = new OAuthClient.AccessTokenResponse(resp);
assertError(response, "client1", "unauthorized_client", AuthenticationFlowError.CLIENT_CREDENTIALS_SETUP_REQUIRED.toString().toLowerCase());
}
@Test
public void testAssertionExpired() throws Exception {
String invalidJwt = getClient1SignedJWT();
setTimeOffset(1000);
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION, invalidJwt));
CloseableHttpResponse resp = sendRequest(oauth.getServiceAccountUrl(), parameters);
OAuthClient.AccessTokenResponse response = new OAuthClient.AccessTokenResponse(resp);
setTimeOffset(0);
assertError(response, "client1", "unauthorized_client", Errors.INVALID_CLIENT_CREDENTIALS);
}
@Test
public void testAssertionInvalidNotBefore() throws Exception {
String invalidJwt = getClient1SignedJWT();
setTimeOffset(-1000);
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT));
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION, invalidJwt));
CloseableHttpResponse resp = sendRequest(oauth.getServiceAccountUrl(), parameters);
OAuthClient.AccessTokenResponse response = new OAuthClient.AccessTokenResponse(resp);
setTimeOffset(0);
assertError(response, "client1", "unauthorized_client", Errors.INVALID_CLIENT_CREDENTIALS);
}
@Test
public void testMissingIdClaim() throws Exception {
OAuthClient.AccessTokenResponse response = testMissingClaim("id");
assertSuccess(response, app1.getClientId(), serviceAccountUser.getId(), serviceAccountUser.getUsername());
}
@Test
public void testMissingIssuerClaim() throws Exception {
OAuthClient.AccessTokenResponse response = testMissingClaim("issuer");
assertSuccess(response, app1.getClientId(), serviceAccountUser.getId(), serviceAccountUser.getUsername());
}
@Test
public void testMissingSubjectClaim() throws Exception {
OAuthClient.AccessTokenResponse response = testMissingClaim("subject");
assertError(response, null, "unauthorized_client", Errors.INVALID_CLIENT_CREDENTIALS);
}
@Test
public void testMissingAudienceClaim() throws Exception {
OAuthClient.AccessTokenResponse response = testMissingClaim("audience");
assertError(response, app1.getClientId(), "unauthorized_client", Errors.INVALID_CLIENT_CREDENTIALS);
}
@Test
public void testMissingIssuedAtClaim() throws Exception {
OAuthClient.AccessTokenResponse response = testMissingClaim("issuedAt");
assertSuccess(response, app1.getClientId(), serviceAccountUser.getId(), serviceAccountUser.getUsername());
}
@Test
// KEYCLOAK-2986
public void testMissingExpirationClaim() throws Exception {
// Missing only exp; the lifespan should be calculated from issuedAt
OAuthClient.AccessTokenResponse response = testMissingClaim("expiration");
assertSuccess(response, app1.getClientId(), serviceAccountUser.getId(), serviceAccountUser.getUsername());
// Test expired lifespan
response = testMissingClaim(-11, "expiration");
assertError(response, app1.getClientId(), "unauthorized_client", Errors.INVALID_CLIENT_CREDENTIALS);
// Missing exp and issuedAt should return error
response = testMissingClaim("expiration", "issuedAt");
assertError(response, app1.getClientId(), "unauthorized_client", Errors.INVALID_CLIENT_CREDENTIALS);
}
@Test
public void testMissingNotBeforeClaim() throws Exception {
OAuthClient.AccessTokenResponse response = testMissingClaim("notBefore");
assertSuccess(response, app1.getClientId(), serviceAccountUser.getId(), serviceAccountUser.getUsername());
}
private OAuthClient.AccessTokenResponse testMissingClaim(String... claims) throws Exception {
return testMissingClaim(0, claims);
}
private OAuthClient.AccessTokenResponse testMissingClaim(int tokenTimeOffset, String... claims) throws Exception {
CustomJWTClientCredentialsProvider jwtProvider = new CustomJWTClientCredentialsProvider();
jwtProvider.setupKeyPair(getClient1KeyPair());
jwtProvider.setTokenTimeout(10);
for (String claim : claims) {
jwtProvider.enableClaim(claim, false);
}
Time.setOffset(tokenTimeOffset);
String jwt = jwtProvider.createSignedRequestToken(app1.getClientId(), getRealmInfoUrl());
Time.setOffset(0);
return doClientCredentialsGrantRequest(jwt);
}
private void assertError(OAuthClient.AccessTokenResponse response, String clientId, String responseError, String eventError) {
assertEquals(400, response.getStatusCode());
assertEquals(responseError, response.getError());
events.expectClientLogin()
.client(clientId)
.session((String) null)
.clearDetails()
.error(eventError)
.user((String) null)
.assertEvent();
}
private void assertSuccess(OAuthClient.AccessTokenResponse response, String clientId, String userId, String userName) {
assertEquals(200, response.getStatusCode());
AccessToken accessToken = oauth.verifyToken(response.getAccessToken());
RefreshToken refreshToken = oauth.verifyRefreshToken(response.getRefreshToken());
events.expectClientLogin()
.client(clientId)
.user(userId)
.session(accessToken.getSessionState())
.detail(Details.TOKEN_ID, accessToken.getId())
.detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
.detail(Details.USERNAME, userName)
.detail(Details.CLIENT_AUTH_METHOD, JWTClientAuthenticator.PROVIDER_ID)
.assertEvent();
}
private static void assertCertificate(ClientRepresentation client, String certOld, String pem) {
final String certNew = client.getAttributes().get(JWTClientAuthenticator.CERTIFICATE_ATTR);
assertNotEquals("The old and new certificates shouldn't match", certOld, certNew);
assertEquals("Certificates don't match", pem, certNew);
}
// HELPER METHODS
private OAuthClient.AccessTokenResponse doAccessTokenRequest(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 doRefreshTokenRequest(String refreshToken, String signedJwt) throws Exception {
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
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 doLogout(String refreshToken, String signedJwt) throws Exception {
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
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 OAuthClient.AccessTokenResponse doClientCredentialsGrantRequest(String signedJwt) throws Exception {
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS));
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.getServiceAccountUrl(), parameters);
return new OAuthClient.AccessTokenResponse(response);
}
private OAuthClient.AccessTokenResponse doGrantAccessTokenRequest(String username, String password, String signedJwt) throws Exception {
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD));
parameters.add(new BasicNameValuePair("username", username));
parameters.add(new BasicNameValuePair("password", password));
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.getResourceOwnerPasswordCredentialGrantUrl(), parameters);
return new OAuthClient.AccessTokenResponse(response);
}
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 String getClient1SignedJWT() {
return getClientSignedJWT(getClient1KeyPair(), "client1");
}
private String getClient2SignedJWT() {
return getClientSignedJWT(getClient2KeyPair(), "client2");
}
private KeyPair getClient1KeyPair() {
return KeystoreUtil.loadKeyPairFromKeystore("classpath:client-auth-test/keystore-client1.jks",
"storepass", "keypass", "clientkey", KeystoreUtil.KeystoreFormat.JKS);
}
private KeyPair getClient2KeyPair() {
return KeystoreUtil.loadKeyPairFromKeystore("classpath:client-auth-test/keystore-client2.jks",
"storepass", "keypass", "clientkey", KeystoreUtil.KeystoreFormat.JKS);
}
private String getClientSignedJWT(KeyPair keyPair, String clientId) {
JWTClientCredentialsProvider jwtProvider = new JWTClientCredentialsProvider();
jwtProvider.setupKeyPair(keyPair);
jwtProvider.setTokenTimeout(10);
return jwtProvider.createSignedRequestToken(clientId, getRealmInfoUrl());
}
private String getRealmInfoUrl() {
String authServerBaseUrl = UriUtils.getOrigin(oauth.getRedirectUri()) + "/auth";
return KeycloakUriBuilder.fromUri(authServerBaseUrl).path(ServiceUrlConstants.REALM_INFO_PATH).build("test").toString();
}
private ClientAttributeCertificateResource getClientAttributeCertificateResource(String realm, String clientId) {
return getClient(realm, clientId).getCertficateResource("jwt.credential");
}
private ClientResource getClient(String realm, String clientId) {
return realmsResouce().realm(realm).clients().get(clientId);
}
/**
* Custom JWTClientCredentialsProvider with support for missing JWT claims
*/
protected class CustomJWTClientCredentialsProvider extends JWTClientCredentialsProvider {
private Map<String, Boolean> enabledClaims = new HashMap<>();
public CustomJWTClientCredentialsProvider() {
super();
final String[] claims = {"id", "issuer", "subject", "audience", "expiration", "notBefore", "issuedAt"};
for (String claim : claims) {
enabledClaims.put(claim, true);
}
}
public void enableClaim(String claim, boolean value) {
if (!enabledClaims.containsKey(claim)) {
throw new IllegalArgumentException("Claim \"" + claim + "\" doesn't exist");
}
enabledClaims.put(claim, value);
}
public boolean isClaimEnabled(String claim) {
Boolean value = enabledClaims.get(claim);
if (value == null) {
throw new IllegalArgumentException("Claim \"" + claim + "\" doesn't exist");
}
return value;
}
public Set<String> getClaims() {
return enabledClaims.keySet();
}
@Override
protected JsonWebToken createRequestToken(String clientId, String realmInfoUrl) {
JsonWebToken reqToken = new JsonWebToken();
if (isClaimEnabled("id")) reqToken.id(AdapterUtils.generateId());
if (isClaimEnabled("issuer")) reqToken.issuer(clientId);
if (isClaimEnabled("subject")) reqToken.subject(clientId);
if (isClaimEnabled("audience")) reqToken.audience(realmInfoUrl);
int now = Time.currentTime();
if (isClaimEnabled("issuedAt")) reqToken.issuedAt(now);
if (isClaimEnabled("expiration")) reqToken.expiration(now + getTokenTimeout());
if (isClaimEnabled("notBefore")) reqToken.notBefore(now);
return reqToken;
}
}
private static KeyStore getKeystore(InputStream is, String storePassword, String format) throws Exception {
KeyStore keyStore = format.equals("JKS") ? KeyStore.getInstance(format) : KeyStore.getInstance(format, "BC");
keyStore.load(is, storePassword.toCharArray());
return keyStore;
}
}