From 8f18e9bbbc0eb6ac46c3017c6d65b1d0e82dc070 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Mon, 6 Jul 2015 17:44:39 -0400 Subject: [PATCH] auth config ui --- .../theme/base/admin/resources/js/app.js | 32 ++- .../admin/resources/js/controllers/realm.js | 87 +++++++ .../theme/base/admin/resources/js/loaders.js | 24 ++ .../theme/base/admin/resources/js/services.js | 23 ++ .../partials/authentication-flows.html | 7 +- .../partials/authenticator-config.html | 64 +++++ .../resources/theme/base/login/register.ftl | 2 +- .../models/AuthenticatorConfigModel.java | 2 + .../authentication/AuthenticatorFactory.java | 2 +- .../ConfigurableAuthenticatorFactory.java | 3 +- .../UsernamePasswordFormFactory.java | 2 +- .../forms/RegistrationPage.java | 12 + .../forms/RegistrationPassword.java | 11 + .../forms/RegistrationProfile.java | 10 + .../forms/RegistrationRecaptcha.java | 33 ++- .../forms/RegistrationUserCreation.java | 11 + .../AuthenticationManagementResource.java | 224 +++++++++++++++++- 17 files changed, 525 insertions(+), 24 deletions(-) create mode 100755 forms/common-themes/src/main/resources/theme/base/admin/resources/partials/authenticator-config.html 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 7568e04cef..eb34666604 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 @@ -978,7 +978,7 @@ module.config([ '$routeProvider', function($routeProvider) { }, clients : function(ClientListLoader) { return ClientListLoader(); - }, + } }, controller : 'UserFederationMapperCtrl' }) @@ -1066,6 +1066,36 @@ module.config([ '$routeProvider', function($routeProvider) { }, controller : 'RealmPasswordPolicyCtrl' }) + .when('/realms/:realm/authentication/config/:provider/:config', { + templateUrl : resourceUrl + '/partials/authenticator-config.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + configType : function(AuthenticationConfigDescriptionLoader) { + return AuthenticationConfigDescriptionLoader(); + }, + config : function(AuthenticationConfigLoader) { + return AuthenticationConfigLoader(); + } + }, + controller : 'AuthenticationConfigCtrl' + }) + .when('/create/authentication/:realm/execution/:executionId/provider/:provider', { + templateUrl : resourceUrl + '/partials/authenticator-config.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + configType : function(AuthenticationConfigDescriptionLoader) { + return AuthenticationConfigDescriptionLoader(); + }, + execution : function(ExecutionIdLoader) { + return ExecutionIdLoader(); + } + }, + controller : 'AuthenticationConfigCreateCtrl' + }) .when('/server-info', { templateUrl : resourceUrl + '/partials/server-info.html' }) 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 93e7cc3b8e..e9341b329b 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 @@ -1634,6 +1634,93 @@ module.controller('RequiredActionsCtrl', function($scope, realm, RequiredActions }); +module.controller('AuthenticationConfigCtrl', function($scope, realm, configType, config, AuthenticationConfig, Notifications, Dialog, $location) { + $scope.realm = realm; + $scope.configType = configType; + $scope.create = false; + $scope.config = angular.copy(config); + $scope.changed = false; + + $scope.$watch(function() { + return $location.path(); + }, function() { + $scope.path = $location.path().substring(1).split("/"); + }); + + $scope.$watch('config', function() { + if (!angular.equals($scope.config, config)) { + $scope.changed = true; + } + }, true); + + $scope.save = function() { + AuthenticationConfig.update({ + realm : realm.realm, + config : config.id + }, $scope.config, function() { + $scope.changed = false; + config = angular.copy($scope.config); + $location.url("/realms/" + realm.realm + '/authentication/config/' + configType.providerId + "/" + config.id); + Notifications.success("Your changes have been saved."); + }); + }; + + $scope.reset = function() { + $scope.config = angular.copy(config); + $scope.changed = false; + }; + + $scope.cancel = function() { + //$location.url("/realms"); + window.history.back(); + }; + + $scope.remove = function() { + Dialog.confirmDelete($scope.config.alias, 'config', function() { + AuthenticationConfig.remove({ realm: realm.realm, config : $scope.config.id }, function() { + Notifications.success("The config has been deleted."); + $location.url("/realms/" + realm.realm + '/authentication/flows'); + }); + }); + }; + +}); + +module.controller('AuthenticationConfigCreateCtrl', function($scope, realm, configType, execution, AuthenticationExecutionConfig, Notifications, Dialog, $location) { + $scope.realm = realm; + $scope.create = true; + $scope.config = { config: {}}; + $scope.configType = configType; + + $scope.$watch(function() { + return $location.path(); + }, function() { + $scope.path = $location.path().substring(1).split("/"); + }); + + $scope.save = function() { + AuthenticationExecutionConfig.save({ + realm : realm.realm, + execution: execution + }, $scope.config, function(data, headers) { + var l = headers().location; + var id = l.substring(l.lastIndexOf("/") + 1); + var url = "/realms/" + realm.realm + '/authentication/config/' + configType.providerId + "/" + id; + console.log('redirect url: ' + url); + $location.url(url); + Notifications.success("Config has been created."); + }); + }; + + $scope.cancel = function() { + //$location.url("/realms"); + window.history.back(); + }; + + +}); + + 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 da41b3c05a..72c6b8cef0 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 @@ -348,5 +348,29 @@ module.factory('AuthenticationFlowsLoader', function(Loader, AuthenticationFlows }); }); +module.factory('AuthenticationConfigDescriptionLoader', function(Loader, AuthenticationConfigDescription, $route, $q) { + return Loader.get(AuthenticationConfigDescription, function () { + return { + realm: $route.current.params.realm, + provider: $route.current.params.provider + } + }); +}); + +module.factory('ExecutionIdLoader', function($route) { + return function() { return $route.current.params.executionId; }; +}); + +module.factory('AuthenticationConfigLoader', function(Loader, AuthenticationConfig, $route, $q) { + return Loader.get(AuthenticationConfig, function () { + return { + realm: $route.current.params.realm, + config: $route.current.params.config + } + }); +}); + + + 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 6f25efb012..f3c4475495 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 @@ -1094,5 +1094,28 @@ module.factory('AuthenticationFlows', function($resource) { realm : '@realm' }); }); +module.factory('AuthenticationConfigDescription', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/config-description/:provider', { + realm : '@realm', + provider: '@provider' + }); +}); + +module.factory('AuthenticationConfig', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/config/:config', { + realm : '@realm', + config: '@config' + }, { + update: { + method : 'PUT' + } + }); +}); +module.factory('AuthenticationExecutionConfig', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/executions/:execution/config', { + realm : '@realm', + execution: '@execution' + }); +}); diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/authentication-flows.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/authentication-flows.html index 5084ab93fe..4c65931f8c 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/authentication-flows.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/authentication-flows.html @@ -6,7 +6,7 @@ - + @@ -49,6 +50,10 @@ + diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/authenticator-config.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/authenticator-config.html new file mode 100755 index 0000000000..a093240616 --- /dev/null +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/authenticator-config.html @@ -0,0 +1,64 @@ +
+ + + +

Create Authenticator Config

+

{{config.alias|capitalize}}

+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ Name of the configuration. +
+
+ + +
+ +
+
+ +
+
+ +
+ {{option.helpText}} +
+ +
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+ + \ No newline at end of file diff --git a/forms/common-themes/src/main/resources/theme/base/login/register.ftl b/forms/common-themes/src/main/resources/theme/base/login/register.ftl index 75a48fc738..cf7bd1d1ad 100755 --- a/forms/common-themes/src/main/resources/theme/base/login/register.ftl +++ b/forms/common-themes/src/main/resources/theme/base/login/register.ftl @@ -110,7 +110,7 @@ <#if recaptchaRequired??>
-
+
diff --git a/model/api/src/main/java/org/keycloak/models/AuthenticatorConfigModel.java b/model/api/src/main/java/org/keycloak/models/AuthenticatorConfigModel.java index 44b8982e00..9b60192848 100755 --- a/model/api/src/main/java/org/keycloak/models/AuthenticatorConfigModel.java +++ b/model/api/src/main/java/org/keycloak/models/AuthenticatorConfigModel.java @@ -32,6 +32,8 @@ public class AuthenticatorConfigModel implements Serializable { this.alias = alias; } + + public Map getConfig() { return config; } diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/AuthenticatorFactory.java index f928bea1fd..5f32b410d6 100755 --- a/services/src/main/java/org/keycloak/authentication/AuthenticatorFactory.java +++ b/services/src/main/java/org/keycloak/authentication/AuthenticatorFactory.java @@ -9,7 +9,7 @@ import org.keycloak.provider.ProviderFactory; * @author Bill Burke * @version $Revision: 1 $ */ -public interface AuthenticatorFactory extends ProviderFactory, ConfiguredProvider, ConfigurableAuthenticatorFactory { +public interface AuthenticatorFactory extends ProviderFactory, ConfigurableAuthenticatorFactory { Authenticator create(); } diff --git a/services/src/main/java/org/keycloak/authentication/ConfigurableAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/ConfigurableAuthenticatorFactory.java index cca47c6d84..529767458f 100755 --- a/services/src/main/java/org/keycloak/authentication/ConfigurableAuthenticatorFactory.java +++ b/services/src/main/java/org/keycloak/authentication/ConfigurableAuthenticatorFactory.java @@ -1,12 +1,13 @@ package org.keycloak.authentication; import org.keycloak.models.AuthenticationExecutionModel; +import org.keycloak.provider.ConfiguredProvider; /** * @author Bill Burke * @version $Revision: 1 $ */ -public interface ConfigurableAuthenticatorFactory { +public interface ConfigurableAuthenticatorFactory extends ConfiguredProvider { String getDisplayType(); /** diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordFormFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordFormFactory.java index 123c4b405f..cee4f7df12 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordFormFactory.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/UsernamePasswordFormFactory.java @@ -57,7 +57,7 @@ public class UsernamePasswordFormFactory implements AuthenticatorFactory { @Override public boolean isConfigurable() { - return true; + return false; } public static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = { AuthenticationExecutionModel.Requirement.REQUIRED diff --git a/services/src/main/java/org/keycloak/authentication/forms/RegistrationPage.java b/services/src/main/java/org/keycloak/authentication/forms/RegistrationPage.java index 90657fe6e3..4b64333c9f 100755 --- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationPage.java +++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationPage.java @@ -8,8 +8,10 @@ import org.keycloak.login.LoginFormsProvider; import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; +import org.keycloak.provider.ProviderConfigProperty; import javax.ws.rs.core.Response; +import java.util.List; /** * @author Bill Burke @@ -41,6 +43,16 @@ public class RegistrationPage implements FormAuthenticator, FormAuthenticatorFac return "Registration Page"; } + @Override + public String getHelpText() { + return null; + } + + @Override + public List getConfigProperties() { + return null; + } + @Override public String getReferenceCategory() { return null; diff --git a/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java b/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java index f20b3ebdd2..648f9de97e 100755 --- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java +++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java @@ -16,6 +16,7 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.UserCredentialModel; import org.keycloak.models.UserModel; import org.keycloak.models.utils.FormMessage; +import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.services.messages.Messages; import org.keycloak.services.validation.Validation; @@ -31,6 +32,16 @@ import java.util.List; public class RegistrationPassword implements FormAction, FormActionFactory { public static final String PROVIDER_ID = "registration-password-action"; + @Override + public String getHelpText() { + return null; + } + + @Override + public List getConfigProperties() { + return null; + } + @Override public void validate(ValidationContext context) { MultivaluedMap formData = context.getHttpRequest().getDecodedFormParameters(); diff --git a/services/src/main/java/org/keycloak/authentication/forms/RegistrationProfile.java b/services/src/main/java/org/keycloak/authentication/forms/RegistrationProfile.java index f67fbeae86..5ac7341fb7 100755 --- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationProfile.java +++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationProfile.java @@ -14,6 +14,7 @@ import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.models.utils.FormMessage; +import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.services.messages.Messages; import org.keycloak.services.validation.Validation; @@ -28,6 +29,15 @@ import java.util.List; public class RegistrationProfile implements FormAction, FormActionFactory { public static final String PROVIDER_ID = "registration-profile-action"; + @Override + public String getHelpText() { + return null; + } + + @Override + public List getConfigProperties() { + return null; + } @Override public void validate(ValidationContext context) { diff --git a/services/src/main/java/org/keycloak/authentication/forms/RegistrationRecaptcha.java b/services/src/main/java/org/keycloak/authentication/forms/RegistrationRecaptcha.java index 3e8d19102a..7009704418 100755 --- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationRecaptcha.java +++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationRecaptcha.java @@ -23,6 +23,7 @@ import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.models.utils.FormMessage; +import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper; import org.keycloak.provider.ConfiguredProvider; import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.services.messages.Messages; @@ -43,6 +44,8 @@ import java.util.Map; public class RegistrationRecaptcha implements FormAction, FormActionFactory, ConfiguredProvider { public static final String G_RECAPTCHA_RESPONSE = "g-recaptcha-response"; public static final String RECAPTCHA_REFERENCE_CATEGORY = "recaptcha"; + public static final String SITE_KEY = "site.key"; + public static final String SITE_SECRET = "secret"; protected static Logger logger = Logger.getLogger(RegistrationRecaptcha.class); public static final String PROVIDER_ID = "registration-recaptcha-action"; @@ -74,13 +77,13 @@ public class RegistrationRecaptcha implements FormAction, FormActionFactory, Con public void buildPage(FormContext context, LoginFormsProvider form) { AuthenticatorConfigModel captchaConfig = context.getAuthenticatorConfig(); if (captchaConfig == null || captchaConfig.getConfig() == null - || captchaConfig.getConfig().get("site.key") == null - || captchaConfig.getConfig().get("secret") == null + || captchaConfig.getConfig().get(SITE_KEY) == null + || captchaConfig.getConfig().get(SITE_SECRET) == null ) { form.addError(new FormMessage(null, Messages.RECAPTCHA_NOT_CONFIGURED)); return; } - String siteKey = captchaConfig.getConfig().get("site.key"); + String siteKey = captchaConfig.getConfig().get(SITE_KEY); form.setAttribute("recaptchaRequired", true); form.setAttribute("recaptchaSiteKey", siteKey); List scripts = new LinkedList<>(); @@ -98,7 +101,7 @@ public class RegistrationRecaptcha implements FormAction, FormActionFactory, Con String captcha = formData.getFirst(G_RECAPTCHA_RESPONSE); if (!Validation.isBlank(captcha)) { AuthenticatorConfigModel captchaConfig = context.getAuthenticatorConfig(); - String secret = captchaConfig.getConfig().get("secret"); + String secret = captchaConfig.getConfig().get(SITE_SECRET); HttpClient httpClient = context.getSession().getProvider(HttpClientProvider.class).getHttpClient(); HttpPost post = new HttpPost("https://www.google.com/recaptcha/api/siteverify"); @@ -185,8 +188,28 @@ public class RegistrationRecaptcha implements FormAction, FormActionFactory, Con return null; } + private static final List configProperties = new ArrayList(); + + static { + ProviderConfigProperty property; + property = new ProviderConfigProperty(); + property.setName(SITE_KEY); + property.setLabel("Recaptcha Site Key"); + property.setType(ProviderConfigProperty.STRING_TYPE); + property.setHelpText("Google Recaptcha Site Key"); + configProperties.add(property); + property = new ProviderConfigProperty(); + property.setName(SITE_SECRET); + property.setLabel("Recaptcha Secret"); + property.setType(ProviderConfigProperty.STRING_TYPE); + property.setHelpText("Google Recaptcha Secret"); + configProperties.add(property); + + } + + @Override public List getConfigProperties() { - return null; + return configProperties; } } diff --git a/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java b/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java index 28d62392fb..75f2818f1f 100755 --- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java +++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java @@ -16,6 +16,7 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.models.utils.FormMessage; import org.keycloak.protocol.oidc.OIDCLoginProtocol; +import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.services.messages.Messages; import org.keycloak.services.resources.AttributeFormDataProcessor; import org.keycloak.services.validation.Validation; @@ -32,6 +33,16 @@ public class RegistrationUserCreation implements FormAction, FormActionFactory { public static final String PROVIDER_ID = "registration-user-creation"; + @Override + public String getHelpText() { + return null; + } + + @Override + public List getConfigProperties() { + return null; + } + @Override public void validate(ValidationContext context) { MultivaluedMap formData = context.getHttpRequest().getDecodedFormParameters(); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java b/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java index fa221c386c..39ef7c3914 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java @@ -8,24 +8,29 @@ import org.keycloak.authentication.Authenticator; import org.keycloak.authentication.AuthenticatorFactory; import org.keycloak.authentication.AuthenticatorUtil; import org.keycloak.authentication.ConfigurableAuthenticatorFactory; -import org.keycloak.authentication.DefaultAuthenticationFlow; import org.keycloak.authentication.FormAction; import org.keycloak.authentication.FormActionFactory; import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.AuthenticationFlowModel; +import org.keycloak.models.AuthenticatorConfigModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.RequiredActionProviderModel; +import org.keycloak.provider.ProviderConfigProperty; +import org.keycloak.representations.idm.ConfigPropertyRepresentation; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; +import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -42,6 +47,9 @@ public class AuthenticationManagementResource { private final KeycloakSession session; private RealmAuth auth; private AdminEventBuilder adminEvent; + @Context + private UriInfo uriInfo; + private static Logger logger = Logger.getLogger(AuthenticationManagementResource.class); public AuthenticationManagementResource(RealmModel realm, KeycloakSession session, RealmAuth auth, AdminEventBuilder adminEvent) { @@ -53,19 +61,21 @@ public class AuthenticationManagementResource { } public static class AuthenticationExecutionRepresentation { - protected String execution; + protected String id; protected String referenceType; protected String requirement; protected List requirementChoices; protected Boolean configurable; protected Boolean subFlow; + protected String providerId; + protected String authenticationConfig; - public String getExecution() { - return execution; + public String getId() { + return id; } - public void setExecution(String execution) { - this.execution = execution; + public void setId(String execution) { + this.id = execution; } public String getReferenceType() { @@ -107,6 +117,22 @@ public class AuthenticationManagementResource { public void setSubFlow(Boolean subFlow) { this.subFlow = subFlow; } + + public String getProviderId() { + return providerId; + } + + public void setProviderId(String providerId) { + this.providerId = providerId; + } + + public String getAuthenticationConfig() { + return authenticationConfig; + } + + public void setAuthenticationConfig(String authenticationConfig) { + this.authenticationConfig = authenticationConfig; + } } @Path("/flows") @@ -150,27 +176,30 @@ public class AuthenticationManagementResource { } else if (AuthenticationFlow.FORM_FLOW.equals(flowRef.getProviderId())) { rep.getRequirementChoices().add(AuthenticationExecutionModel.Requirement.REQUIRED.name()); rep.getRequirementChoices().add(AuthenticationExecutionModel.Requirement.DISABLED.name()); + rep.setProviderId(execution.getAuthenticator()); + rep.setAuthenticationConfig(execution.getAuthenticatorConfig()); + } rep.setReferenceType(flowRef.getAlias()); rep.setConfigurable(false); - rep.setExecution(execution.getId()); + rep.setId(execution.getId()); rep.setRequirement(execution.getRequirement().name()); result.add(rep); } else { if (!flow.getId().equals(execution.getParentFlow())) { rep.setSubFlow(true); } - ConfigurableAuthenticatorFactory factory = (AuthenticatorFactory)session.getKeycloakSessionFactory().getProviderFactory(Authenticator.class, execution.getAuthenticator()); - if (factory == null) { - factory = (FormActionFactory)session.getKeycloakSessionFactory().getProviderFactory(FormAction.class, execution.getAuthenticator()); - } + String providerId = execution.getAuthenticator(); + ConfigurableAuthenticatorFactory factory = getConfigurableAuthenticatorFactory(providerId); rep.setReferenceType(factory.getDisplayType()); rep.setConfigurable(factory.isConfigurable()); for (AuthenticationExecutionModel.Requirement choice : factory.getRequirementChoices()) { rep.getRequirementChoices().add(choice.name()); } - rep.setExecution(execution.getId()); + rep.setId(execution.getId()); rep.setRequirement(execution.getRequirement().name()); + rep.setProviderId(execution.getAuthenticator()); + rep.setAuthenticationConfig(execution.getAuthenticatorConfig()); result.add(rep); } @@ -179,6 +208,14 @@ public class AuthenticationManagementResource { return Response.ok(result).build(); } + public ConfigurableAuthenticatorFactory getConfigurableAuthenticatorFactory(String providerId) { + ConfigurableAuthenticatorFactory factory = (AuthenticatorFactory)session.getKeycloakSessionFactory().getProviderFactory(Authenticator.class, providerId); + if (factory == null) { + factory = (FormActionFactory)session.getKeycloakSessionFactory().getProviderFactory(FormAction.class, providerId); + } + return factory; + } + @Path("/flows/{flowAlias}/executions") @PUT @NoCache @@ -192,7 +229,7 @@ public class AuthenticationManagementResource { throw new NotFoundException("flow not found"); } - AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(rep.getExecution()); + AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(rep.getId()); if (model == null) { session.getTransaction().setRollbackOnly(); throw new NotFoundException("Illegal execution"); @@ -204,6 +241,39 @@ public class AuthenticationManagementResource { } } + @Path("/executions/{executionId}/config") + @POST + @NoCache + @Consumes(MediaType.APPLICATION_JSON) + public Response newExecutionConfig(@PathParam("executionId") String execution, AuthenticatorConfigModel config) { + this.auth.requireManage(); + + AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution); + if (model == null) { + session.getTransaction().setRollbackOnly(); + throw new NotFoundException("Illegal execution"); + + } + config = realm.addAuthenticatorConfig(config); + model.setAuthenticatorConfig(config.getId()); + realm.updateAuthenticatorExecution(model); + return Response.created(uriInfo.getAbsolutePathBuilder().path(config.getId()).build()).build(); + } + + @Path("/executions/{executionId}/config/{id}") + @GET + @Produces(MediaType.APPLICATION_JSON) + @NoCache + public AuthenticatorConfigModel getAuthenticatorConfig(@PathParam("executionId") String execution,@PathParam("id") String id) { + AuthenticatorConfigModel config = realm.getAuthenticatorConfigById(id); + if (config == null) { + throw new NotFoundException("Could not find authenticator config"); + + } + return config; + } + + public static class RequiredActionProviderRepresentation { private String alias; private String name; @@ -256,6 +326,7 @@ public class AuthenticationManagementResource { @Path("required-actions") @GET @Produces(MediaType.APPLICATION_JSON) + @NoCache public List getRequiredActions() { List list = new LinkedList<>(); for (RequiredActionProviderModel model : realm.getRequiredActionProviders()) { @@ -278,6 +349,7 @@ public class AuthenticationManagementResource { @Path("required-actions/{alias}") @GET @Produces(MediaType.APPLICATION_JSON) + @NoCache public RequiredActionProviderRepresentation getRequiredAction(@PathParam("alias") String alias) { RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias); if (model == null) { @@ -316,5 +388,131 @@ public class AuthenticationManagementResource { realm.removeRequiredActionProvider(model); } + public class AuthenticatorConfigDescription { + protected String name; + protected String providerId; + protected String helpText; + + protected List properties; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getHelpText() { + return helpText; + } + + public String getProviderId() { + return providerId; + } + + public void setProviderId(String providerId) { + this.providerId = providerId; + } + + public void setHelpText(String helpText) { + this.helpText = helpText; + } + + public List getProperties() { + return properties; + } + + public void setProperties(List properties) { + this.properties = properties; + } + } + + + @Path("config-description/{providerId}") + @GET + @Produces(MediaType.APPLICATION_JSON) + @NoCache + public AuthenticatorConfigDescription getAuthenticatorConfigDescription(@PathParam("providerId") String providerId) { + ConfigurableAuthenticatorFactory factory = getConfigurableAuthenticatorFactory(providerId); + if (factory == null) { + throw new NotFoundException("Could not find authenticator provider"); + } + AuthenticatorConfigDescription rep = new AuthenticatorConfigDescription(); + rep.setProviderId(providerId); + rep.setName(factory.getDisplayType()); + rep.setHelpText(factory.getHelpText()); + rep.setProperties(new LinkedList()); + List configProperties = factory.getConfigProperties(); + for (ProviderConfigProperty prop : configProperties) { + ConfigPropertyRepresentation propRep = new ConfigPropertyRepresentation(); + propRep.setName(prop.getName()); + propRep.setLabel(prop.getLabel()); + propRep.setType(prop.getType()); + propRep.setDefaultValue(prop.getDefaultValue()); + propRep.setHelpText(prop.getHelpText()); + rep.getProperties().add(propRep); + } + return rep; + } + + @Path("config") + @POST + @NoCache + public Response createAuthenticatorConfig(AuthenticatorConfigModel config) { + config = realm.addAuthenticatorConfig(config); + return Response.created(uriInfo.getAbsolutePathBuilder().path(config.getId()).build()).build(); + } + + @Path("config/{id}") + @GET + @Produces(MediaType.APPLICATION_JSON) + @NoCache + public AuthenticatorConfigModel getAuthenticatorConfig(@PathParam("id") String id) { + AuthenticatorConfigModel config = realm.getAuthenticatorConfigById(id); + if (config == null) { + throw new NotFoundException("Could not find authenticator config"); + + } + return config; + } + @Path("config/{id}") + @DELETE + @NoCache + public void removeAuthenticatorConfig(@PathParam("id") String id) { + AuthenticatorConfigModel config = realm.getAuthenticatorConfigById(id); + if (config == null) { + throw new NotFoundException("Could not find authenticator config"); + + } + List flows = new LinkedList<>(); + for (AuthenticationFlowModel flow : realm.getAuthenticationFlows()) { + for (AuthenticationExecutionModel exe : realm.getAuthenticationExecutions(flow.getId())) { + if (id.equals(exe.getAuthenticatorConfig())) { + exe.setAuthenticatorConfig(null); + realm.updateAuthenticatorExecution(exe); + } + } + } + + realm.removeAuthenticatorConfig(config); + } + @Path("config/{id}") + @PUT + @Consumes(MediaType.APPLICATION_JSON) + @NoCache + public void updateAuthenticatorConfig(@PathParam("id") String id, AuthenticatorConfigModel config) { + AuthenticatorConfigModel exists = realm.getAuthenticatorConfigById(id); + if (exists == null) { + throw new NotFoundException("Could not find authenticator config"); + + } + exists.setAlias(config.getAlias()); + exists.setConfig(config.getConfig()); + realm.updateAuthenticatorConfig(exists); + } + + + } \ No newline at end of file
+ Auth Type Requirement
+ Configure + Configure +
No executions available