diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.5.0.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.5.0.xml index 52930a3a780..d5619d9f5e8 100755 --- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.5.0.xml +++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.5.0.xml @@ -61,6 +61,12 @@ + + + + + + diff --git a/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java index e5ab5036400..020445e4066 100755 --- a/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java @@ -15,6 +15,7 @@ public class ClientRepresentation { protected String baseUrl; protected Boolean surrogateAuthRequired; protected Boolean enabled; + protected String clientAuthenticatorType; protected String secret; protected String[] defaultRoles; protected List redirectUris; @@ -89,6 +90,14 @@ public class ClientRepresentation { this.baseUrl = baseUrl; } + public String getClientAuthenticatorType() { + return clientAuthenticatorType; + } + + public void setClientAuthenticatorType(String clientAuthenticatorType) { + this.clientAuthenticatorType = clientAuthenticatorType; + } + public String getSecret() { return secret; } diff --git a/docbook/reference/en/en-US/modules/auth-spi.xml b/docbook/reference/en/en-US/modules/auth-spi.xml index 81b7d9d893a..ff7f061c463 100755 --- a/docbook/reference/en/en-US/modules/auth-spi.xml +++ b/docbook/reference/en/en-US/modules/auth-spi.xml @@ -921,7 +921,7 @@ public class SecretQuestionRequiredActionFactory implements RequiredActionFactor in the location accessible to your client application - Uploaded in Keycloak admin console - This option is useful if you already has existing private key of your client. + Uploaded in Keycloak admin console - This option is useful if you already have existing private key of your client. In this case, you just need to upload the public key and certificate to the Keycloak server. @@ -993,7 +993,8 @@ public class SecretQuestionRequiredActionFactory implements RequiredActionFactor Finally you need to configure admin console . You need to create new client authentication flow and define execution with your authenticator (you can also add the builtin authenticators and configure requirements etc) - and finally configure Clients binding . See Adding Authenticator for more details. + and finally configure Clients binding . See Adding Authenticator for more details. Then + you need to go to Client credentials tab and choose the method for authentication your client and configure client credentials (if possible). diff --git a/examples/demo-template/service-account/src/main/webapp/WEB-INF/keycloak-client-signed-jwt.json b/examples/demo-template/service-account/src/main/webapp/WEB-INF/keycloak-client-signed-jwt.json index 6c07d1eb90a..3e90c34a300 100644 --- a/examples/demo-template/service-account/src/main/webapp/WEB-INF/keycloak-client-signed-jwt.json +++ b/examples/demo-template/service-account/src/main/webapp/WEB-INF/keycloak-client-signed-jwt.json @@ -3,7 +3,7 @@ "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", "auth-server-url" : "http://localhost:8080/auth", "ssl-required" : "external", - "resource" : "product-sa-client", + "resource" : "product-sa-client-jwt-auth", "credentials": { "jwt": { "client-keystore-file": "classpath:keystore-client.jks", diff --git a/examples/demo-template/testrealm.json b/examples/demo-template/testrealm.json index 8d3e597258f..0ba235f2def 100755 --- a/examples/demo-template/testrealm.json +++ b/examples/demo-template/testrealm.json @@ -78,6 +78,13 @@ "email" : "service-account-product-sa-client@placeholder.org", "serviceAccountClientId": "product-sa-client", "realmRoles": [ "user" ] + }, + { + "username" : "service-account-product-sa-client-jwt-auth", + "enabled": true, + "email" : "service-account-product-sa-client-jwt-auth@placeholder.org", + "serviceAccountClientId": "product-sa-client-jwt-auth", + "realmRoles": [ "user" ] } ], "roles" : { @@ -173,7 +180,13 @@ "clientId": "product-sa-client", "enabled": true, "secret": "password", + "serviceAccountsEnabled": true + }, + { + "clientId": "product-sa-client-jwt-auth", + "enabled": true, "serviceAccountsEnabled": true, + "clientAuthenticatorType": "client-jwt", "attributes": { "jwt.credential.certificate": "MIICnTCCAYUCBgFPPLDaTzANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdjbGllbnQxMB4XDTE1MDgxNzE3MjI0N1oXDTI1MDgxNzE3MjQyN1owEjEQMA4GA1UEAwwHY2xpZW50MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIUjjgv+V3s96O+Za9002Lp/trtGuHBeaeVL9dFKMKzO2MPqdRmHB4PqNlDdd28Rwf5Xn6iWdFpyUKOnI/yXDLhdcuFpR0sMNK/C9Lt+hSpPFLuzDqgtPgDotlMxiHIWDOZ7g9/gPYNXbNvjv8nSiyqoguoCQiiafW90bPHsiVLdP7ZIUwCcfi1qQm7FhxRJ1NiW5dvUkuCnnWEf0XR+Wzc5eC9EgB0taLFiPsSEIlWMm5xlahYyXkPdNOqZjiRnrTWm5Y4uk8ZcsD/KbPTf/7t7cQXipVaswgjdYi1kK2/zRwOhg1QwWFX/qmvdd+fLxV0R6VqRDhn7Qep2cxwMxLsCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAKE6OA46sf20bz8LZPoiNsqRwBUDkaMGXfnob7s/hJZIIwDEx0IAQ3uKsG7q9wb+aA6s+v7S340zb2k3IxuhFaHaZpAd4CyR5cn1FHylbzoZ7rI/3ASqHDqpljdJaFqPH+m7nZWtyDvtZf+gkZ8OjsndwsSBK1d/jMZPp29qYbl1+XfO7RCp/jDqro/R3saYFaIFiEZPeKn1hUJn6BO48vxH1xspSu9FmlvDOEAOz4AuM58z4zRMP49GcFdCWr1wkonJUHaSptJaQwmBwLFUkCbE5I1ixGMb7mjEud6Y5jhfzJiZMo2U8RfcjNbrN0diZl3jB6LQIwESnhYSghaTjNQ==" } diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js index 2e3a251a46c..4ec4c22160f 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js @@ -30,10 +30,42 @@ module.controller('ClientRoleListCtrl', function($scope, $location, realm, clien }); }); -module.controller('ClientCredentialsCtrl', function($scope, $location, realm, client, clientAuthenticatorProviders, Notifications) { +module.controller('ClientCredentialsCtrl', function($scope, $location, realm, client, clientAuthenticatorProviders, Client) { $scope.realm = realm; - $scope.client = client; + $scope.client = angular.copy(client); $scope.clientAuthenticatorProviders = clientAuthenticatorProviders; + + var updateConfigButtonVisibility = function() { + for (var i=0 ; iCopy - + diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-credentials.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-credentials.html index 043cee64fc3..8415fbe5daf 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-credentials.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-credentials.html @@ -7,24 +7,27 @@ - - - - - - - - - - - - - - - - - -
Client Auth Type
{{authenticator.displayName|capitalize}}Configure
No client authenticators available
+
+
+
+ +
+
+ +
+
+ Client Authenticator used for authentication this client against Keycloak server + +
+
+
+ diff --git a/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_5_0.java b/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_5_0.java index dd550dc13a5..95a52248804 100755 --- a/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_5_0.java +++ b/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_5_0.java @@ -2,6 +2,7 @@ package org.keycloak.migration.migrators; import org.keycloak.migration.ModelVersion; import org.keycloak.models.AuthenticationFlowModel; +import org.keycloak.models.ClientModel; import org.keycloak.models.ImpersonationConstants; import org.keycloak.models.KeycloakSession; import org.keycloak.models.OTPPolicy; @@ -38,6 +39,10 @@ public class MigrateTo1_5_0 { } else { realm.setClientAuthenticationFlow(realm.getFlowByAlias(DefaultAuthenticationFlows.CLIENT_AUTHENTICATION_FLOW)); } + + for (ClientModel client : realm.getClients()) { + client.setClientAuthenticatorType(KeycloakModelUtils.getDefaultClientAuthenticatorType()); + } } } diff --git a/model/api/src/main/java/org/keycloak/models/ClientModel.java b/model/api/src/main/java/org/keycloak/models/ClientModel.java index 96a7dd75777..daccf8e0aa3 100755 --- a/model/api/src/main/java/org/keycloak/models/ClientModel.java +++ b/model/api/src/main/java/org/keycloak/models/ClientModel.java @@ -75,6 +75,9 @@ public interface ClientModel extends RoleContainerModel { void setNodeReRegistrationTimeout(int timeout); + String getClientAuthenticatorType(); + void setClientAuthenticatorType(String clientAuthenticatorType); + boolean validateSecret(String secret); String getSecret(); public void setSecret(String secret); diff --git a/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java b/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java index 8e0c21bd8d1..52e972196ba 100755 --- a/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java +++ b/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java @@ -14,6 +14,7 @@ public class ClientEntity extends AbstractIdentifiableEntity { private String name; private String realmId; private boolean enabled; + private String clientAuthenticatorType; private String secret; private String protocol; private int notBefore; @@ -67,6 +68,14 @@ public class ClientEntity extends AbstractIdentifiableEntity { this.enabled = enabled; } + public String getClientAuthenticatorType() { + return clientAuthenticatorType; + } + + public void setClientAuthenticatorType(String clientAuthenticatorType) { + this.clientAuthenticatorType = clientAuthenticatorType; + } + public String getSecret() { return secret; } diff --git a/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java b/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java index 79a9b12b51f..b64ebb04b62 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java +++ b/model/api/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java @@ -180,12 +180,17 @@ public final class KeycloakModelUtils { return secret; } + public static String getDefaultClientAuthenticatorType() { + return "client-secret"; + } + public static String generateCodeSecret() { return UUID.randomUUID().toString(); } public static ClientModel createClient(RealmModel realm, String name) { ClientModel app = realm.addClient(name); + app.setClientAuthenticatorType(getDefaultClientAuthenticatorType()); generateSecret(app); app.setFullScopeAllowed(true); diff --git a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java index 1a411c7109b..f2d4f1ebe17 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java +++ b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java @@ -307,6 +307,7 @@ public class ModelToRepresentation { rep.setBaseUrl(clientModel.getBaseUrl()); rep.setNotBefore(clientModel.getNotBefore()); rep.setNodeReRegistrationTimeout(clientModel.getNodeReRegistrationTimeout()); + rep.setClientAuthenticatorType(clientModel.getClientAuthenticatorType()); Set redirectUris = clientModel.getRedirectUris(); if (redirectUris != null) { diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java index 31d257586d2..4faff0194e1 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java +++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java @@ -692,6 +692,12 @@ public class RepresentationToModel { client.setNotBefore(resourceRep.getNotBefore()); } + if (resourceRep.getClientAuthenticatorType() != null) { + client.setClientAuthenticatorType(resourceRep.getClientAuthenticatorType()); + } else { + client.setClientAuthenticatorType(KeycloakModelUtils.getDefaultClientAuthenticatorType()); + } + client.setSecret(resourceRep.getSecret()); if (client.getSecret() == null) { KeycloakModelUtils.generateSecret(client); @@ -770,6 +776,7 @@ public class RepresentationToModel { if (rep.getBaseUrl() != null) resource.setBaseUrl(rep.getBaseUrl()); if (rep.isSurrogateAuthRequired() != null) resource.setSurrogateAuthRequired(rep.isSurrogateAuthRequired()); if (rep.getNodeReRegistrationTimeout() != null) resource.setNodeReRegistrationTimeout(rep.getNodeReRegistrationTimeout()); + if (rep.getClientAuthenticatorType() != null) resource.setClientAuthenticatorType(rep.getClientAuthenticatorType()); resource.updateClient(); if (rep.getProtocol() != null) resource.setProtocol(rep.getProtocol()); diff --git a/model/file/src/main/java/org/keycloak/models/file/adapter/ClientAdapter.java b/model/file/src/main/java/org/keycloak/models/file/adapter/ClientAdapter.java index 87f0ee34ee2..8003b70dedc 100755 --- a/model/file/src/main/java/org/keycloak/models/file/adapter/ClientAdapter.java +++ b/model/file/src/main/java/org/keycloak/models/file/adapter/ClientAdapter.java @@ -145,6 +145,16 @@ public class ClientAdapter implements ClientModel { entity.setEnabled(enabled); } + @Override + public String getClientAuthenticatorType() { + return entity.getClientAuthenticatorType(); + } + + @Override + public void setClientAuthenticatorType(String clientAuthenticatorType) { + entity.setClientAuthenticatorType(clientAuthenticatorType); + } + @Override public boolean validateSecret(String secret) { return secret.equals(entity.getSecret()); diff --git a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java index 97914006dc9..9f79b157ed8 100755 --- a/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java +++ b/model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientAdapter.java @@ -95,6 +95,18 @@ public class ClientAdapter implements ClientModel { updated.setEnabled(enabled); } + @Override + public String getClientAuthenticatorType() { + if (updated != null) return updated.getClientAuthenticatorType(); + return cached.getClientAuthenticatorType(); + } + + @Override + public void setClientAuthenticatorType(String clientAuthenticatorType) { + getDelegateForUpdate(); + updated.setClientAuthenticatorType(clientAuthenticatorType); + } + public boolean validateSecret(String secret) { return secret.equals(getSecret()); } diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java index 911021e2fbe..25749c3fa06 100755 --- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java +++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java @@ -29,6 +29,7 @@ public class CachedClient implements Serializable { private String realm; private Set redirectUris = new HashSet(); private boolean enabled; + private String clientAuthenticatorType; private String secret; private String protocol; private Map attributes = new HashMap(); @@ -53,6 +54,7 @@ public class CachedClient implements Serializable { public CachedClient(RealmCache cache, RealmProvider delegate, RealmModel realm, ClientModel model) { id = model.getId(); + clientAuthenticatorType = model.getClientAuthenticatorType(); secret = model.getSecret(); clientId = model.getClientId(); name = model.getName(); @@ -112,6 +114,10 @@ public class CachedClient implements Serializable { return enabled; } + public String getClientAuthenticatorType() { + return clientAuthenticatorType; + } + public String getSecret() { return secret; } diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java index fc551c7edfb..b0acc417fd1 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java @@ -151,6 +151,16 @@ public class ClientAdapter implements ClientModel { entity.getRedirectUris().remove(redirectUri); } + @Override + public String getClientAuthenticatorType() { + return entity.getClientAuthenticatorType(); + } + + @Override + public void setClientAuthenticatorType(String clientAuthenticatorType) { + entity.setClientAuthenticatorType(clientAuthenticatorType); + } + @Override public String getSecret() { return entity.getSecret(); diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java index 8b57335d87e..1f6ac251b37 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java @@ -40,6 +40,8 @@ public class ClientEntity { private boolean enabled; @Column(name="SECRET") private String secret; + @Column(name="CLIENT_AUTHENTICATOR_TYPE") + private String clientAuthenticatorType; @Column(name="NOT_BEFORE") private int notBefore; @Column(name="PUBLIC_CLIENT") @@ -170,6 +172,14 @@ public class ClientEntity { this.redirectUris = redirectUris; } + public String getClientAuthenticatorType() { + return clientAuthenticatorType; + } + + public void setClientAuthenticatorType(String clientAuthenticatorType) { + this.clientAuthenticatorType = clientAuthenticatorType; + } + public String getSecret() { return secret; } diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java index 40ea0d2f625..26effca9c33 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java @@ -141,6 +141,17 @@ public class ClientAdapter extends AbstractMongoAdapter imple updateMongoEntity(); } + @Override + public String getClientAuthenticatorType() { + return getMongoEntity().getClientAuthenticatorType(); + } + + @Override + public void setClientAuthenticatorType(String clientAuthenticatorType) { + getMongoEntity().setClientAuthenticatorType(clientAuthenticatorType); + updateMongoEntity(); + } + @Override public boolean validateSecret(String secret) { return secret.equals(getMongoEntity().getSecret()); diff --git a/services/src/main/java/org/keycloak/authentication/ClientAuthenticationFlow.java b/services/src/main/java/org/keycloak/authentication/ClientAuthenticationFlow.java index 7c864f10d43..2065de0f024 100644 --- a/services/src/main/java/org/keycloak/authentication/ClientAuthenticationFlow.java +++ b/services/src/main/java/org/keycloak/authentication/ClientAuthenticationFlow.java @@ -1,5 +1,7 @@ package org.keycloak.authentication; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -11,6 +13,7 @@ import org.keycloak.events.Errors; import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.AuthenticationFlowModel; import org.keycloak.models.ClientModel; +import org.keycloak.models.utils.KeycloakModelUtils; /** * @author Marek Posolda @@ -18,19 +21,12 @@ import org.keycloak.models.ClientModel; public class ClientAuthenticationFlow implements AuthenticationFlow { Response alternativeChallenge = null; - boolean alternativeSuccessful = false; - List executions; - Iterator executionIterator; AuthenticationProcessor processor; AuthenticationFlowModel flow; - private List successAuthenticators = new LinkedList<>(); - public ClientAuthenticationFlow(AuthenticationProcessor processor, AuthenticationFlowModel flow) { this.processor = processor; this.flow = flow; - this.executions = processor.getRealm().getAuthenticationExecutions(flow.getId()); - this.executionIterator = executions.iterator(); } @Override @@ -40,131 +36,109 @@ public class ClientAuthenticationFlow implements AuthenticationFlow { @Override public Response processFlow() { - while (executionIterator.hasNext()) { - AuthenticationExecutionModel model = executionIterator.next(); - - if (model.isDisabled()) { - continue; - } - - if (model.isAlternative() && alternativeSuccessful) { - continue; - } - - if (model.isAuthenticatorFlow()) { - AuthenticationFlow authenticationFlow; - authenticationFlow = processor.createFlowExecution(model.getFlowId(), model); - - Response flowChallenge = authenticationFlow.processFlow(); - if (flowChallenge == null) { - if (model.isAlternative()) alternativeSuccessful = true; - continue; - } else { - if (model.isAlternative()) { - alternativeChallenge = flowChallenge; - } else if (model.isRequired()) { - return flowChallenge; - } else { - continue; - } - return flowChallenge; - } - } + List executions = findExecutionsToRun(); + for (AuthenticationExecutionModel model : executions) { ClientAuthenticatorFactory factory = (ClientAuthenticatorFactory) processor.getSession().getKeycloakSessionFactory().getProviderFactory(ClientAuthenticator.class, model.getAuthenticator()); if (factory == null) { throw new AuthenticationFlowException("Could not find ClientAuthenticatorFactory for: " + model.getAuthenticator(), AuthenticationFlowError.INTERNAL_ERROR); } ClientAuthenticator authenticator = factory.create(); AuthenticationProcessor.logger.debugv("client authenticator: {0}", factory.getId()); - ClientModel authClient = processor.getClient(); - if (authenticator.requiresClient() && authClient == null) { - // Continue if it's alternative or optional flow - if (model.isAlternative() || model.isOptional()) { - AuthenticationProcessor.logger.debugv("client authenticator: {0} requires client, but client not available. Skipping", factory.getId()); - continue; - } - - if (alternativeChallenge != null) { - return alternativeChallenge; - } - throw new AuthenticationFlowException("client authenticator: " + factory.getId(), AuthenticationFlowError.CLIENT_NOT_FOUND); - } - - if (authenticator.requiresClient() && authClient != null) { - boolean configuredFor = authenticator.configuredFor(processor.getSession(), processor.getRealm(), authClient); - if (!configuredFor) { - if (model.isRequired()) { - throw new AuthenticationFlowException("Client setup required for authenticator " + factory.getId() + " for client " + authClient.getClientId(), - AuthenticationFlowError.CLIENT_CREDENTIALS_SETUP_REQUIRED); - } else if (model.isOptional()) { - continue; - } - } - } AuthenticationProcessor.Result context = processor.createClientAuthenticatorContext(model, authenticator, executions); authenticator.authenticateClient(context); Response response = processResult(context); if (response != null) return response; - authClient = processor.getClient(); - if (authClient != null && authClient.isPublicClient()) { - AuthenticationProcessor.logger.debugv("Public client {0} identified by {1} . Skip next client authenticators", authClient.getClientId(), factory.getId()); - logSuccessEvent(); - return null; + ClientModel client = processor.getClient(); + if (client != null) { + + String expectedClientAuthType = client.getClientAuthenticatorType(); + + // Fallback to secret just in case (for backwards compatibility) + if (expectedClientAuthType == null) { + expectedClientAuthType = KeycloakModelUtils.getDefaultClientAuthenticatorType(); + AuthenticationProcessor.logger.warnv("Client {0} doesn't have have authentication method configured. Fallback to {1}", client.getClientId(), expectedClientAuthType); + } + + // Check if client authentication matches + if (factory.getId().equals(expectedClientAuthType)) { + AuthenticationProcessor.logger.debugv("Client {0} authenticated by {1}", client.getClientId(), factory.getId()); + processor.getEvent().detail(Details.CLIENT_AUTH_METHOD, factory.getId()); + return null; + } else { + throw new AuthenticationFlowException("Client " + client.getClientId() + " was authenticated by incorrect method " + factory.getId(), + AuthenticationFlowError.INVALID_CLIENT_CREDENTIALS); + } } } - return finishClientAuthentication(); + // Check if any alternative challenge was identified + if (alternativeChallenge != null) { + processor.getEvent().error(Errors.INVALID_CLIENT); + return alternativeChallenge; + } + throw new AuthenticationFlowException("Client was not identified by any client authenticator", AuthenticationFlowError.UNKNOWN_CLIENT); } + protected List findExecutionsToRun() { + List executions = processor.getRealm().getAuthenticationExecutions(flow.getId()); + List executionsToRun = new ArrayList<>(); - public Response processResult(AuthenticationProcessor.Result result) { + for (AuthenticationExecutionModel execution : executions) { + if (execution.isRequired()) { + executionsToRun = Arrays.asList(execution); + break; + } + + if (execution.isAlternative()) { + executionsToRun.add(execution); + } + } + + if (AuthenticationProcessor.logger.isTraceEnabled()) { + List exIds = new ArrayList<>(); + for (AuthenticationExecutionModel execution : executionsToRun) { + exIds.add(execution.getId()); + } + AuthenticationProcessor.logger.tracef("Using executions for client authentication: %s", exIds.toString()); + } + + return executionsToRun; + } + + protected Response processResult(AuthenticationProcessor.Result result) { AuthenticationExecutionModel execution = result.getExecution(); FlowStatus status = result.getStatus(); + + AuthenticationProcessor.logger.debugv("client authenticator {0}: {1}", status.toString(), execution.getAuthenticator()); + if (status == FlowStatus.SUCCESS) { - AuthenticationProcessor.logger.debugv("client authenticator SUCCESS: {0}", execution.getAuthenticator()); - if (execution.isAlternative()) alternativeSuccessful = true; - successAuthenticators.add(execution.getAuthenticator()); return null; } else if (status == FlowStatus.FAILED) { - AuthenticationProcessor.logger.debugv("client authenticator FAILED: {0}", execution.getAuthenticator()); if (result.getChallenge() != null) { return sendChallenge(result, execution); + } else { + throw new AuthenticationFlowException(result.getError()); } - throw new AuthenticationFlowException(result.getError()); } else if (status == FlowStatus.FORCE_CHALLENGE) { return sendChallenge(result, execution); } else if (status == FlowStatus.CHALLENGE) { - AuthenticationProcessor.logger.debugv("client authenticator CHALLENGE: {0}", execution.getAuthenticator()); - if (execution.isRequired()) { - return sendChallenge(result, execution); - } - ClientModel client = processor.getClient(); - if (execution.isOptional() && client != null && result.getClientAuthenticator().configuredFor(processor.getSession(), processor.getRealm(), client)) { - return sendChallenge(result, execution); - } + // Make sure the first priority alternative challenge is used - if (execution.isAlternative() && alternativeChallenge == null) { + if (alternativeChallenge == null) { alternativeChallenge = result.getChallenge(); } return null; } else if (status == FlowStatus.FAILURE_CHALLENGE) { - AuthenticationProcessor.logger.debugv("client authenticator FAILURE_CHALLENGE: {0}", execution.getAuthenticator()); return sendChallenge(result, execution); } else if (status == FlowStatus.ATTEMPTED) { - AuthenticationProcessor.logger.debugv("client authenticator ATTEMPTED: {0}", execution.getAuthenticator()); - if (execution.getRequirement() == AuthenticationExecutionModel.Requirement.REQUIRED) { - throw new AuthenticationFlowException(AuthenticationFlowError.INVALID_CLIENT_CREDENTIALS); - } return null; } else { - AuthenticationProcessor.logger.debugv("client authenticator INTERNAL_ERROR: {0}", execution.getAuthenticator()); AuthenticationProcessor.logger.error("Unknown result status"); throw new AuthenticationFlowException(AuthenticationFlowError.INTERNAL_ERROR); } - } public Response sendChallenge(AuthenticationProcessor.Result result, AuthenticationExecutionModel execution) { @@ -183,34 +157,4 @@ public class ClientAuthenticationFlow implements AuthenticationFlow { return result.getChallenge(); } - - private Response finishClientAuthentication() { - if (processor.getClient() == null) { - // Check if any alternative challenge was identified - if (alternativeChallenge != null) { - processor.getEvent().error(Errors.INVALID_CLIENT); - return alternativeChallenge; - } - - throw new AuthenticationFlowException("Client was not identified by any client authenticator", AuthenticationFlowError.UNKNOWN_CLIENT); - } - - logSuccessEvent(); - return null; - } - - private void logSuccessEvent() { - StringBuilder result = new StringBuilder(); - boolean first = true; - for (String authenticator : successAuthenticators) { - if (first) { - first = false; - } else { - result.append(" "); - } - result.append(authenticator); - } - - processor.getEvent().detail(Details.CLIENT_AUTH_METHOD, result.toString()); - } } diff --git a/services/src/main/java/org/keycloak/authentication/ClientAuthenticator.java b/services/src/main/java/org/keycloak/authentication/ClientAuthenticator.java index 47c0d5de3eb..9e26b239b1b 100644 --- a/services/src/main/java/org/keycloak/authentication/ClientAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/ClientAuthenticator.java @@ -28,21 +28,4 @@ public interface ClientAuthenticator extends Provider { */ void authenticateClient(ClientAuthenticationFlowContext context); - - /** - * Does this authenticator require that the client has already been identified? That ClientAuthenticationFlowContext.getClient() is not null? - * - * @return - */ - boolean requiresClient(); - - /** - * Is this authenticator configured for this client? - * - * @param session - * @param realm - * @param client - * @return - */ - boolean configuredFor(KeycloakSession session, RealmModel realm, ClientModel client); } diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/client/ClientIdAndSecretAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/client/ClientIdAndSecretAuthenticator.java index 55d0fded036..b4917ece33c 100644 --- a/services/src/main/java/org/keycloak/authentication/authenticators/client/ClientIdAndSecretAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/client/ClientIdAndSecretAuthenticator.java @@ -36,7 +36,6 @@ public class ClientIdAndSecretAuthenticator extends AbstractClientAuthenticator public static final String PROVIDER_ID = "client-secret"; public static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = { - AuthenticationExecutionModel.Requirement.REQUIRED, AuthenticationExecutionModel.Requirement.ALTERNATIVE, AuthenticationExecutionModel.Requirement.DISABLED }; @@ -133,16 +132,6 @@ public class ClientIdAndSecretAuthenticator extends AbstractClientAuthenticator return true; } - @Override - public boolean requiresClient() { - return false; - } - - @Override - public boolean configuredFor(KeycloakSession session, RealmModel realm, ClientModel client) { - return client.getSecret() != null; - } - @Override public AuthenticationExecutionModel.Requirement[] getRequirementChoices() { return REQUIREMENT_CHOICES; diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/client/JWTClientAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/client/JWTClientAuthenticator.java index f01731a79cb..48336a9ed22 100644 --- a/services/src/main/java/org/keycloak/authentication/authenticators/client/JWTClientAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/client/JWTClientAuthenticator.java @@ -41,7 +41,6 @@ public class JWTClientAuthenticator extends AbstractClientAuthenticator { public static final String CERTIFICATE_ATTR = "jwt.credential.certificate"; public static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = { - AuthenticationExecutionModel.Requirement.REQUIRED, AuthenticationExecutionModel.Requirement.ALTERNATIVE, AuthenticationExecutionModel.Requirement.DISABLED }; @@ -135,16 +134,6 @@ public class JWTClientAuthenticator extends AbstractClientAuthenticator { } } - @Override - public boolean requiresClient() { - return false; - } - - @Override - public boolean configuredFor(KeycloakSession session, RealmModel realm, ClientModel client) { - return client.getAttribute(CERTIFICATE_ATTR) != null; - } - @Override public String getDisplayType() { return "Signed Jwt"; diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java index bc7fdb3e8d1..c017ba30198 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java @@ -39,7 +39,7 @@ public class AuthorizeClientUtil { ClientModel client = processor.getClient(); if (client == null) { - throw new ErrorResponseException("invalid_client", "Client authentication was successful, but client is null", Response.Status.BAD_REQUEST); + throw new ErrorResponseException("invalid_client", "Client authentication ended, but client is null", Response.Status.BAD_REQUEST); } return new ClientAuthResult(client, processor.getClientAuthAttributes()); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java index dc49661c381..bae16d5a9b1 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AdminAPITest.java @@ -133,6 +133,9 @@ public class AdminAPITest { ClientRepresentation newApp = new ClientRepresentation(); if (appRep.getId() != null) newApp.setId(appRep.getId()); newApp.setClientId(appRep.getClientId()); + if (appRep.getClientAuthenticatorType() != null) { + newApp.setClientAuthenticatorType(appRep.getClientAuthenticatorType()); + } if (appRep.getSecret() != null) { newApp.setSecret(appRep.getSecret()); } @@ -177,6 +180,7 @@ public class AdminAPITest { if (appRep.getAdminUrl() != null) Assert.assertEquals(appRep.getAdminUrl(), storedApp.getAdminUrl()); if (appRep.getBaseUrl() != null) Assert.assertEquals(appRep.getBaseUrl(), storedApp.getBaseUrl()); if (appRep.isSurrogateAuthRequired() != null) Assert.assertEquals(appRep.isSurrogateAuthRequired(), storedApp.isSurrogateAuthRequired()); + if (appRep.getClientAuthenticatorType() != null) Assert.assertEquals(appRep.getClientAuthenticatorType(), storedApp.getClientAuthenticatorType()); if (appRep.getNotBefore() != null) { Assert.assertEquals(appRep.getNotBefore(), storedApp.getNotBefore()); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/LDAPMultipleAttributesTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/LDAPMultipleAttributesTest.java index edd210cb412..0b417e3c8ea 100644 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/LDAPMultipleAttributesTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/LDAPMultipleAttributesTest.java @@ -30,6 +30,7 @@ import org.keycloak.models.UserFederationProviderModel; import org.keycloak.models.UserModel; import org.keycloak.protocol.oidc.OIDCLoginProtocolService; import org.keycloak.protocol.oidc.mappers.UserAttributeMapper; +import org.keycloak.services.managers.ClientManager; import org.keycloak.services.managers.RealmManager; import org.keycloak.testsuite.OAuthClient; import org.keycloak.testsuite.adapter.AdapterTest; @@ -78,7 +79,7 @@ public class LDAPMultipleAttributesTest { ldapFedProvider.getLdapIdentityStore().updatePassword(bruce, "password"); // Create ldap-portal client - ClientModel ldapClient = appRealm.addClient("ldap-portal"); + ClientModel ldapClient = new ClientManager(manager).createClient(appRealm, "ldap-portal"); ldapClient.addRedirectUri("/ldap-portal"); ldapClient.addRedirectUri("/ldap-portal/*"); ldapClient.setManagementUrl("/ldap-portal"); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java index 9f7becefe2e..33cc03753cd 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java @@ -35,6 +35,7 @@ import org.keycloak.events.EventType; import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.AuthenticationFlowModel; import org.keycloak.models.BrowserSecurityHeaders; +import org.keycloak.models.ClientModel; import org.keycloak.models.PasswordPolicy; import org.keycloak.models.RealmModel; import org.keycloak.models.UserCredentialModel; @@ -120,8 +121,6 @@ public class CustomFlowTest { execution.setAuthenticatorFlow(false); appRealm.addAuthenticatorExecution(execution); - new ClientManager().createClient(appRealm, "dummy-client"); - AuthenticationFlowModel clientFlow = new AuthenticationFlowModel(); clientFlow.setAlias("client-dummy"); clientFlow.setDescription("dummy pass through flow"); @@ -138,6 +137,11 @@ public class CustomFlowTest { execution.setPriority(10); execution.setAuthenticatorFlow(false); appRealm.addAuthenticatorExecution(execution); + + // Set passthrough clientAuthenticator for our clients + ClientModel dummyClient = new ClientManager().createClient(appRealm, "dummy-client"); + dummyClient.setClientAuthenticatorType(PassThroughClientAuthenticator.PROVIDER_ID); + appRealm.getClientByClientId("test-app").setClientAuthenticatorType(PassThroughClientAuthenticator.PROVIDER_ID); } }); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/PassThroughClientAuthenticator.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/PassThroughClientAuthenticator.java index 1d7e74fda8f..cfcd1fe6889 100644 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/PassThroughClientAuthenticator.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/PassThroughClientAuthenticator.java @@ -58,16 +58,6 @@ public class PassThroughClientAuthenticator extends AbstractClientAuthenticator context.success(); } - @Override - public boolean requiresClient() { - return false; - } - - @Override - public boolean configuredFor(KeycloakSession session, RealmModel realm, ClientModel client) { - return true; - } - @Override public String getDisplayType() { return "PassThrough Client Validation"; diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsBasicAuthTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsBasicAuthTest.java index 1b5a249e913..6cd79988ee5 100644 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsBasicAuthTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsBasicAuthTest.java @@ -21,6 +21,7 @@ import org.junit.rules.ExternalResource; import org.keycloak.adapters.HttpClientBuilder; import org.keycloak.models.ClientModel; import org.keycloak.models.RealmModel; +import org.keycloak.services.managers.ClientManager; import org.keycloak.services.managers.RealmManager; import org.keycloak.testsuite.Constants; import org.keycloak.testsuite.rule.KeycloakRule; @@ -42,7 +43,7 @@ public class JaxrsBasicAuthTest { @Override public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { - ClientModel app = appRealm.addClient("jaxrs-app"); + ClientModel app = new ClientManager(manager).createClient(appRealm, "jaxrs-app"); app.setEnabled(true); app.setSecret("password"); app.setFullScopeAllowed(true); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java index 332c94b56e6..558ff39a8b4 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java @@ -110,6 +110,10 @@ public class ImportTest extends AbstractModelTest { Assert.assertTrue(10 == appRegisteredNodes.get("node1")); Assert.assertTrue(20 == appRegisteredNodes.get("172.10.15.20")); + // test clientAuthenticatorType + Assert.assertEquals(application.getClientAuthenticatorType(), "client-secret"); + Assert.assertEquals(otherApp.getClientAuthenticatorType(), "client-jwt"); + // Test finding applications by ID Assert.assertNull(realm.getClientById("982734")); Assert.assertEquals(application, realm.getClientById(application.getId())); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java index c3f04bd85de..2aa13b26d96 100644 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java @@ -58,9 +58,11 @@ public class ClientAuthSignedJWTTest { ClientModel app1 = appRealm.addClient("client1"); new ClientManager(manager).enableServiceAccount(app1); app1.setAttribute(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=="); + app1.setClientAuthenticatorType(JWTClientAuthenticator.PROVIDER_ID); ClientModel app2 = appRealm.addClient("client2"); new ClientManager(manager).enableServiceAccount(app2); + app2.setClientAuthenticatorType(JWTClientAuthenticator.PROVIDER_ID); // 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=="); @@ -176,7 +178,7 @@ public class ClientAuthSignedJWTTest { } @Test - public void testDirectGrantRequest() throws Exception { + public void testDirectGrantRequestSuccess() throws Exception { oauth.clientId("client2"); OAuthClient.AccessTokenResponse response = doGrantAccessTokenRequest("test-user@localhost", "password", getClient2SignedJWT()); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java index 7cefa79c55d..6c205adbd2e 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java @@ -29,6 +29,7 @@ import org.keycloak.OAuth2Constants; import org.keycloak.models.ClientModel; import org.keycloak.models.Constants; import org.keycloak.models.RealmModel; +import org.keycloak.services.managers.ClientManager; import org.keycloak.services.managers.RealmManager; import org.keycloak.testsuite.OAuthClient; import org.keycloak.testsuite.pages.ErrorPage; @@ -49,18 +50,18 @@ public class OAuthRedirectUriTest { public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() { @Override public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { - ClientModel installedApp = appRealm.addClient("test-installed"); + ClientModel installedApp = new ClientManager(manager).createClient(appRealm, "test-installed"); installedApp.setEnabled(true); installedApp.addRedirectUri(Constants.INSTALLED_APP_URN); installedApp.addRedirectUri(Constants.INSTALLED_APP_URL); installedApp.setSecret("password"); - ClientModel installedApp2 = appRealm.addClient("test-installed2"); + ClientModel installedApp2 = new ClientManager(manager).createClient(appRealm, "test-installed2"); installedApp2.setEnabled(true); installedApp2.addRedirectUri(Constants.INSTALLED_APP_URL + "/myapp"); installedApp2.setSecret("password"); - ClientModel installedApp3 = appRealm.addClient("test-wildcard"); + ClientModel installedApp3 = new ClientManager(manager).createClient(appRealm, "test-wildcard"); installedApp3.setEnabled(true); installedApp3.addRedirectUri("http://example.com/foo/*"); installedApp3.addRedirectUri("http://localhost:8081/foo/*"); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java index 4deaceed094..252909154f7 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java @@ -17,6 +17,7 @@ import org.keycloak.models.UserCredentialModel; import org.keycloak.models.UserModel; import org.keycloak.representations.AccessToken; import org.keycloak.representations.RefreshToken; +import org.keycloak.services.managers.ClientManager; import org.keycloak.services.managers.RealmManager; import org.keycloak.testsuite.AssertEvents; import org.keycloak.testsuite.OAuthClient; @@ -36,7 +37,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest { public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() { @Override public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { - ClientModel app = appRealm.addClient("resource-owner"); + ClientModel app = new ClientManager(manager).createClient(appRealm, "resource-owner"); app.setSecret("secret"); UserModel user = session.users().addUser(appRealm, "direct-login"); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ServiceAccountTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ServiceAccountTest.java index c1b8f84bda3..5c5dc2652ae 100644 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ServiceAccountTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/ServiceAccountTest.java @@ -34,11 +34,11 @@ public class ServiceAccountTest { public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() { @Override public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { - ClientModel app = appRealm.addClient("service-account-cl"); + ClientModel app = new ClientManager(manager).createClient(appRealm, "service-account-cl"); app.setSecret("secret1"); new ClientManager(manager).enableServiceAccount(app); - ClientModel disabledApp = appRealm.addClient("service-account-disabled"); + ClientModel disabledApp = new ClientManager(manager).createClient(appRealm, "service-account-disabled"); disabledApp.setSecret("secret1"); UserModel serviceAccountUser = session.users().getUserByUsername(ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + "service-account-cl", appRealm); diff --git a/testsuite/integration/src/test/resources/adapter-test/demorealm.json b/testsuite/integration/src/test/resources/adapter-test/demorealm.json index af9a5597181..5bf2bdd9531 100755 --- a/testsuite/integration/src/test/resources/adapter-test/demorealm.json +++ b/testsuite/integration/src/test/resources/adapter-test/demorealm.json @@ -123,6 +123,7 @@ "enabled": true, "adminUrl": "http://localhost:8081/secure-portal", "baseUrl": "http://localhost:8081/secure-portal", + "clientAuthenticatorType": "client-jwt", "redirectUris": [ "http://localhost:8081/secure-portal/*" ], diff --git a/testsuite/integration/src/test/resources/model/testrealm.json b/testsuite/integration/src/test/resources/model/testrealm.json index 9df4385fa20..acbbdf5805e 100755 --- a/testsuite/integration/src/test/resources/model/testrealm.json +++ b/testsuite/integration/src/test/resources/model/testrealm.json @@ -164,6 +164,7 @@ "name": "Other Application", "enabled": true, "serviceAccountsEnabled": true, + "clientAuthenticatorType": "client-jwt", "protocolMappers" : [ { "name" : "gss delegation credential", diff --git a/testsuite/tomcat6/src/test/resources/adapter-test/demorealm.json b/testsuite/tomcat6/src/test/resources/adapter-test/demorealm.json index a0ddce4ec78..b577bfae950 100755 --- a/testsuite/tomcat6/src/test/resources/adapter-test/demorealm.json +++ b/testsuite/tomcat6/src/test/resources/adapter-test/demorealm.json @@ -123,6 +123,7 @@ "enabled": true, "adminUrl": "http://localhost:8082/secure-portal", "baseUrl": "http://localhost:8082/secure-portal", + "clientAuthenticatorType": "client-jwt", "redirectUris": [ "http://localhost:8082/secure-portal/*" ],