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 d4326c6f7a..292430b4f5 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
@@ -55,6 +55,9 @@
+
+
+
diff --git a/core/src/main/java/org/keycloak/OAuth2Constants.java b/core/src/main/java/org/keycloak/OAuth2Constants.java
index 493748abf3..e17d21ff09 100644
--- a/core/src/main/java/org/keycloak/OAuth2Constants.java
+++ b/core/src/main/java/org/keycloak/OAuth2Constants.java
@@ -31,6 +31,13 @@ public interface OAuth2Constants {
String CLIENT_CREDENTIALS = "client_credentials";
+ // https://tools.ietf.org/html/draft-ietf-oauth-assertions-01#page-5
+ String CLIENT_ASSERTION_TYPE = "client_assertion_type";
+ String CLIENT_ASSERTION = "client_assertion";
+
+ // https://tools.ietf.org/html/draft-jones-oauth-jwt-bearer-03#section-2.2
+ String CLIENT_ASSERTION_TYPE_JWT = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
+
}
diff --git a/core/src/main/java/org/keycloak/representations/idm/CertificateRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/CertificateRepresentation.java
new file mode 100644
index 0000000000..82bb495af8
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/CertificateRepresentation.java
@@ -0,0 +1,30 @@
+package org.keycloak.representations.idm;
+
+/**
+ * PEM values of key and certificate
+ *
+ * @author Marek Posolda
+ */
+public class CertificateRepresentation {
+
+ protected String privateKey;
+ protected String certificate;
+
+ public String getPrivateKey() {
+ return privateKey;
+ }
+
+ public void setPrivateKey(String privateKey) {
+ this.privateKey = privateKey;
+ }
+
+ public String getCertificate() {
+ return certificate;
+ }
+
+ public void setCertificate(String certificate) {
+ this.certificate = certificate;
+ }
+
+
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
index 43aeb613a3..5b59c23ee5 100755
--- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
@@ -90,6 +90,7 @@ public class RealmRepresentation {
protected String browserFlow;
protected String registrationFlow;
protected String directGrantFlow;
+ protected String clientAuthenticationFlow;
@Deprecated
protected Boolean social;
@@ -735,4 +736,12 @@ public class RealmRepresentation {
public void setDirectGrantFlow(String directGrantFlow) {
this.directGrantFlow = directGrantFlow;
}
+
+ public String getClientAuthenticationFlow() {
+ return clientAuthenticationFlow;
+ }
+
+ public void setClientAuthenticationFlow(String clientAuthenticationFlow) {
+ this.clientAuthenticationFlow = clientAuthenticationFlow;
+ }
}
diff --git a/core/src/main/java/org/keycloak/util/KeystoreUtil.java b/core/src/main/java/org/keycloak/util/KeystoreUtil.java
index a6085724a6..0be87bc553 100755
--- a/core/src/main/java/org/keycloak/util/KeystoreUtil.java
+++ b/core/src/main/java/org/keycloak/util/KeystoreUtil.java
@@ -4,6 +4,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
+import java.security.PrivateKey;
import org.keycloak.constants.GenericConstants;
@@ -12,6 +13,14 @@ import org.keycloak.constants.GenericConstants;
* @version $Revision: 1 $
*/
public class KeystoreUtil {
+ static {
+ BouncyIntegration.init();
+ }
+
+ public enum KeystoreFormat {
+ JKS,
+ PKCS12
+ }
public static KeyStore loadKeyStore(String filename, String password) throws Exception {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
@@ -22,4 +31,26 @@ public class KeystoreUtil {
trustStream.close();
return trustStore;
}
+
+ public static PrivateKey loadPrivateKeyFromKeystore(String keystoreFile, String storePassword, String keyPassword, String keyAlias, KeystoreFormat format) {
+ InputStream stream = FindFile.findFile(keystoreFile);
+
+ try {
+ KeyStore keyStore = null;
+ if (format == KeystoreFormat.JKS) {
+ keyStore = KeyStore.getInstance(format.toString());
+ } else {
+ keyStore = KeyStore.getInstance(format.toString(), "BC");
+ }
+
+ keyStore.load(stream, storePassword.toCharArray());
+ PrivateKey key = (PrivateKey) keyStore.getKey(keyAlias, keyPassword.toCharArray());
+ if (key == null) {
+ throw new RuntimeException("Couldn't load key with alias '" + keyAlias + "' from keystore");
+ }
+ return key;
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to load private key: " + e.getMessage(), e);
+ }
+ }
}
diff --git a/events/api/src/main/java/org/keycloak/events/Details.java b/events/api/src/main/java/org/keycloak/events/Details.java
index 468d8528ad..b7ec6779d7 100755
--- a/events/api/src/main/java/org/keycloak/events/Details.java
+++ b/events/api/src/main/java/org/keycloak/events/Details.java
@@ -37,9 +37,5 @@ public interface Details {
String IMPERSONATOR = "impersonator";
String CLIENT_AUTH_METHOD = "client_auth_method";
- String CLIENT_AUTH_METHOD_VALUE_CLIENT_CREDENTIALS = "client_credentials";
- String CLIENT_AUTH_METHOD_VALUE_CERTIFICATE = "client_certificate";
- String CLIENT_AUTH_METHOD_VALUE_KERBEROS_KEYTAB = "kerberos_keytab";
- String CLIENT_AUTH_METHOD_VALUE_SIGNED_JWT = "signed_jwt";
}
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js
index 66bfba7961..2a37bc0c63 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/app.js
@@ -623,10 +623,67 @@ module.config([ '$routeProvider', function($routeProvider) {
},
client : function(ClientLoader) {
return ClientLoader();
+ },
+ clientAuthenticatorProviders : function(ClientAuthenticatorProvidersLoader) {
+ return ClientAuthenticatorProvidersLoader();
}
},
controller : 'ClientCredentialsCtrl'
})
+ .when('/realms/:realm/clients/:client/credentials/client-secret', {
+ templateUrl : resourceUrl + '/partials/client-credentials-secret.html',
+ resolve : {
+ realm : function(RealmLoader) {
+ return RealmLoader();
+ },
+ client : function(ClientLoader) {
+ return ClientLoader();
+ }
+ },
+ controller : 'ClientSecretCtrl'
+ })
+ .when('/realms/:realm/clients/:client/credentials/client-signed-jwt', {
+ templateUrl : resourceUrl + '/partials/client-credentials-jwt.html',
+ resolve : {
+ realm : function(RealmLoader) {
+ return RealmLoader();
+ },
+ client : function(ClientLoader) {
+ return ClientLoader();
+ }
+ },
+ controller : 'ClientSignedJWTCtrl'
+ })
+ .when('/realms/:realm/clients/:client/credentials/client-signed-jwt/:keyType/import/:attribute', {
+ templateUrl : resourceUrl + '/partials/client-credentials-jwt-key-import.html',
+ resolve : {
+ realm : function(RealmLoader) {
+ return RealmLoader();
+ },
+ client : function(ClientLoader) {
+ return ClientLoader();
+ },
+ callingContext : function() {
+ return "jwt-credentials";
+ }
+ },
+ controller : 'ClientCertificateImportCtrl'
+ })
+ .when('/realms/:realm/clients/:client/credentials/client-signed-jwt/:keyType/export/:attribute', {
+ templateUrl : resourceUrl + '/partials/client-credentials-jwt-key-export.html',
+ resolve : {
+ realm : function(RealmLoader) {
+ return RealmLoader();
+ },
+ client : function(ClientLoader) {
+ return ClientLoader();
+ },
+ callingContext : function() {
+ return "jwt-credentials";
+ }
+ },
+ controller : 'ClientCertificateExportCtrl'
+ })
.when('/realms/:realm/clients/:client/identity-provider', {
templateUrl : resourceUrl + '/partials/client-identity-provider.html',
resolve : {
@@ -695,6 +752,9 @@ module.config([ '$routeProvider', function($routeProvider) {
},
client : function(ClientLoader) {
return ClientLoader();
+ },
+ callingContext : function() {
+ return "saml";
}
},
controller : 'ClientCertificateImportCtrl'
@@ -707,6 +767,9 @@ module.config([ '$routeProvider', function($routeProvider) {
},
client : function(ClientLoader) {
return ClientLoader();
+ },
+ callingContext : function() {
+ return "saml";
}
},
controller : 'ClientCertificateExportCtrl'
@@ -1134,6 +1197,9 @@ module.config([ '$routeProvider', function($routeProvider) {
},
authenticatorProviders : function(AuthenticatorProvidersLoader) {
return AuthenticatorProvidersLoader();
+ },
+ clientAuthenticatorProviders : function(ClientAuthenticatorProvidersLoader) {
+ return ClientAuthenticatorProvidersLoader();
}
},
controller : 'CreateExecutionCtrl'
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 61eefd9cb6..b50c4a02d2 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,17 +30,23 @@ module.controller('ClientRoleListCtrl', function($scope, $location, realm, clien
});
});
-module.controller('ClientCredentialsCtrl', function($scope, $location, realm, client, ClientCredentials, Notifications) {
+module.controller('ClientCredentialsCtrl', function($scope, $location, realm, client, clientAuthenticatorProviders, Notifications) {
$scope.realm = realm;
$scope.client = client;
- var secret = ClientCredentials.get({ realm : realm.realm, client : client.id },
+ $scope.clientAuthenticatorProviders = clientAuthenticatorProviders;
+});
+
+module.controller('ClientSecretCtrl', function($scope, $location, realm, client, ClientSecret, Notifications) {
+ $scope.realm = realm;
+ $scope.client = client;
+ var secret = ClientSecret.get({ realm : realm.realm, client : client.id },
function() {
$scope.secret = secret.value;
}
);
$scope.changePassword = function() {
- var secret = ClientCredentials.update({ realm : realm.realm, client : client.id },
+ var secret = ClientSecret.update({ realm : realm.realm, client : client.id },
function() {
Notifications.success('The secret has been changed.');
$scope.secret = secret.value;
@@ -57,6 +63,34 @@ module.controller('ClientCredentialsCtrl', function($scope, $location, realm, cl
}, function() {
$scope.path = $location.path().substring(1).split("/");
});
+
+ $scope.cancel = function() {
+ $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/credentials");
+ };
+});
+
+module.controller('ClientSignedJWTCtrl', function($scope, $location, realm, client, ClientCertificate, Notifications) {
+
+ $scope.realm = realm;
+ $scope.client = client;
+
+ var signingKeyInfo = ClientCertificate.get({ realm : realm.realm, client : client.id, attribute: 'jwt.credentials' },
+ function() {
+ $scope.signingKeyInfo = signingKeyInfo;
+ }
+ );
+
+ $scope.importCertificate = function() {
+ $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/credentials/client-signed-jwt/Signing/import/jwt.credentials");
+ };
+
+ $scope.generateSigningKey = function() {
+ $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/credentials/client-signed-jwt/Signing/export/jwt.credentials");
+ };
+
+ $scope.cancel = function() {
+ $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/credentials");
+ };
});
module.controller('ClientIdentityProviderCtrl', function($scope, $location, $route, realm, client, Client, $location, Notifications) {
@@ -212,16 +246,26 @@ module.controller('ClientSamlKeyCtrl', function($scope, $location, $http, $uploa
});
});
-module.controller('ClientCertificateImportCtrl', function($scope, $location, $http, $upload, realm, client, $routeParams,
+module.controller('ClientCertificateImportCtrl', function($scope, $location, $http, $upload, realm, client, callingContext, $routeParams,
ClientCertificate, ClientCertificateGenerate,
ClientCertificateDownload, Notifications) {
+ console.log("callingContext: " + callingContext);
+
var keyType = $routeParams.keyType;
var attribute = $routeParams.attribute;
$scope.realm = realm;
$scope.client = client;
$scope.keyType = keyType;
+ if (callingContext == 'saml') {
+ var uploadUrl = authUrl + '/admin/realms/' + realm.realm + '/clients/' + client.id + '/certificates/' + attribute + '/upload';
+ var redirectLocation = "/realms/" + realm.realm + "/clients/" + client.id + "/saml/keys";
+ } else if (callingContext == 'jwt-credentials') {
+ var uploadUrl = authUrl + '/admin/realms/' + realm.realm + '/clients/' + client.id + '/certificates/' + attribute + '/upload-certificate';
+ var redirectLocation = "/realms/" + realm.realm + "/clients/" + client.id + "/credentials/client-signed-jwt";
+ }
+
$scope.files = [];
$scope.onFileSelect = function($files) {
@@ -244,7 +288,7 @@ module.controller('ClientCertificateImportCtrl', function($scope, $location, $ht
for (var i = 0; i < $scope.files.length; i++) {
var $file = $scope.files[i];
$scope.upload = $upload.upload({
- url: authUrl + '/admin/realms/' + realm.realm + '/clients/' + client.id + '/certificates/' + attribute + '/upload',
+ url: uploadUrl,
// method: POST or PUT,
// headers: {'headerKey': 'headerValue'}, withCredential: true,
data: {keystoreFormat: $scope.uploadKeyFormat,
@@ -259,12 +303,11 @@ module.controller('ClientCertificateImportCtrl', function($scope, $location, $ht
//formDataAppender: function(formData, key, val){}
}).success(function(data, status, headers) {
Notifications.success("Keystore uploaded successfully.");
- $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/saml/keys");
- })
- .error(function() {
- Notifications.error("The key store can not be uploaded. Please verify the file.");
-
- });
+ $location.url(redirectLocation);
+ }).error(function(data) {
+ var errorMsg = data['error_description'] ? data['error_description'] : 'The key store can not be uploaded. Please verify the file.';
+ Notifications.error(errorMsg);
+ });
//.then(success, error, progress);
}
};
@@ -276,7 +319,7 @@ module.controller('ClientCertificateImportCtrl', function($scope, $location, $ht
});
});
-module.controller('ClientCertificateExportCtrl', function($scope, $location, $http, $upload, realm, client, $routeParams,
+module.controller('ClientCertificateExportCtrl', function($scope, $location, $http, $upload, realm, client, callingContext, $routeParams,
ClientCertificate, ClientCertificateGenerate,
ClientCertificateDownload, Notifications) {
var keyType = $routeParams.keyType;
@@ -284,9 +327,19 @@ module.controller('ClientCertificateExportCtrl', function($scope, $location, $ht
$scope.realm = realm;
$scope.client = client;
$scope.keyType = keyType;
+
+ if (callingContext == 'saml') {
+ var downloadUrl = authUrl + '/admin/realms/' + realm.realm + '/clients/' + client.id + '/certificates/' + attribute + '/download';
+ var realmCertificate = true;
+ } else if (callingContext == 'jwt-credentials') {
+ var downloadUrl = authUrl + '/admin/realms/' + realm.realm + '/clients/' + client.id + '/certificates/' + attribute + '/generate-and-download'
+ var realmCertificate = false;
+ }
+
var jks = {
keyAlias: client.clientId,
- realmAlias: realm.realm
+ realmAlias: realm.realm,
+ realmCertificate: realmCertificate
};
$scope.keyFormats = [
@@ -304,7 +357,7 @@ module.controller('ClientCertificateExportCtrl', function($scope, $location, $ht
$scope.download = function() {
$http({
- url: authUrl + '/admin/realms/' + realm.realm + '/clients/' + client.id + '/certificates/' + attribute + '/download',
+ url: downloadUrl,
method: 'POST',
responseType: 'arraybuffer',
data: $scope.jks,
@@ -335,6 +388,10 @@ module.controller('ClientCertificateExportCtrl', function($scope, $location, $ht
}, function() {
$scope.path = $location.path().substring(1).split("/");
});
+
+ $scope.cancel = function() {
+ $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/credentials/client-signed-jwt");
+ }
});
module.controller('ClientSessionsCtrl', function($scope, realm, sessionCount, client,
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
index ef1f60296f..00da83c290 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
@@ -1656,9 +1656,11 @@ module.controller('CreateExecutionFlowCtrl', function($scope, realm, topFlow, pa
Notifications, $location) {
$scope.realm = realm;
$scope.formProviders = formProviders;
+
+ var defaultFlowType = parentFlow.providerId == 'client-flow' ? 'client-flow' : 'basic-flow';
$scope.flow = {
alias: "",
- type: "basic-flow",
+ type: defaultFlowType,
description: ""
}
$scope.provider = {};
@@ -1678,7 +1680,7 @@ module.controller('CreateExecutionFlowCtrl', function($scope, realm, topFlow, pa
};
});
-module.controller('CreateExecutionCtrl', function($scope, realm, topFlow, parentFlow, formActionProviders, authenticatorProviders,
+module.controller('CreateExecutionCtrl', function($scope, realm, topFlow, parentFlow, formActionProviders, authenticatorProviders, clientAuthenticatorProviders,
CreateExecution,
Notifications, $location) {
$scope.realm = realm;
@@ -1686,6 +1688,8 @@ module.controller('CreateExecutionCtrl', function($scope, realm, topFlow, parent
console.log('parentFlow.providerId: ' + parentFlow.providerId);
if (parentFlow.providerId == 'form-flow') {
$scope.providers = formActionProviders;
+ } else if (parentFlow.providerId == 'client-flow') {
+ $scope.providers = clientAuthenticatorProviders;
} else {
$scope.providers = authenticatorProviders;
}
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js
index e9cf3dfc18..1ecbd7dfce 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/loaders.js
@@ -392,6 +392,14 @@ module.factory('AuthenticatorProvidersLoader', function(Loader, AuthenticatorPro
});
});
+module.factory('ClientAuthenticatorProvidersLoader', function(Loader, ClientAuthenticatorProviders, $route, $q) {
+ return Loader.query(ClientAuthenticatorProviders, function() {
+ return {
+ realm : $route.current.params.realm
+ }
+ });
+});
+
module.factory('AuthenticationFlowLoader', function(Loader, AuthenticationFlows, $route, $q) {
return Loader.get(AuthenticationFlows, function() {
return {
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js
index a2e6446412..c8ba5f5d1e 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/services.js
@@ -931,7 +931,7 @@ module.factory('ClientInstallationJBoss', function($resource) {
}
});
-module.factory('ClientCredentials', function($resource) {
+module.factory('ClientSecret', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/clients/:client/client-secret', {
realm : '@realm',
client : '@client'
@@ -1223,6 +1223,12 @@ module.factory('AuthenticatorProviders', function($resource) {
});
});
+module.factory('ClientAuthenticatorProviders', function($resource) {
+ return $resource(authUrl + '/admin/realms/:realm/authentication/client-authenticator-providers', {
+ realm : '@realm'
+ });
+});
+
module.factory('AuthenticationFlowsCopy', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/authentication/flows/:alias/copy', {
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt-key-export.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt-key-export.html
new file mode 100644
index 0000000000..b933e9aa47
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt-key-export.html
@@ -0,0 +1,57 @@
+
+
+
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt-key-import.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt-key-import.html
new file mode 100644
index 0000000000..82b255d59b
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt-key-import.html
@@ -0,0 +1,62 @@
+
+
+
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt.html
new file mode 100644
index 0000000000..5f580ab2bc
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt.html
@@ -0,0 +1,36 @@
+
+
+
+ - Clients
+ - {{client.clientId}}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-secret.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-secret.html
new file mode 100644
index 0000000000..cec0f15264
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-secret.html
@@ -0,0 +1,27 @@
+
+
+
+ - Clients
+ - {{client.clientId}}
+
+
+
+
+
+
+
+
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 b58af1e866..043cee64fc 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,20 +7,24 @@
-
+
+
+
+ Client Auth Type |
+ |
+
+
+
+
+ |
+ {{authenticator.displayName|capitalize}} |
+ Configure |
+
+
+ No client authenticators available |
+
+
+
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-saml-keys.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-saml-keys.html
index 540fa9ddfd..cadfb49111 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-saml-keys.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/client-saml-keys.html
@@ -5,8 +5,6 @@
{{client.clientId}}
- {{client.clientId|capitalize}}
-