From de940ccff90067ac670afa66b1aa19ed234c6638 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Sun, 2 Aug 2015 19:03:33 -0400 Subject: [PATCH 1/3] auth flow editing --- .../theme/base/admin/resources/js/app.js | 18 ++ .../admin/resources/js/controllers/realm.js | 73 ++++- .../theme/base/admin/resources/js/services.js | 63 +++- .../partials/authentication-flows.html | 54 ++-- .../partials/modal/role-selector.html | 7 +- .../admin/resources/templates/kc-copy.html | 18 ++ .../models/AuthenticationExecutionModel.java | 10 +- .../utils/DefaultAuthenticationFlows.java | 30 +- .../models/utils/ModelToRepresentation.java | 2 +- .../models/utils/RepresentationToModel.java | 2 +- .../models/file/adapter/RealmAdapter.java | 6 +- .../keycloak/models/cache/RealmAdapter.java | 1 - .../models/cache/entities/CachedRealm.java | 1 + .../org/keycloak/models/jpa/RealmAdapter.java | 6 +- .../mongo/keycloak/adapters/RealmAdapter.java | 6 +- .../authentication/AuthenticatorUtil.java | 9 +- .../DefaultAuthenticationFlow.java | 4 +- .../protocol/oidc/mappers/RoleNameMapper.java | 2 +- .../AuthenticationManagementResource.java | 272 ++++++++++++++++-- 19 files changed, 483 insertions(+), 101 deletions(-) create mode 100755 forms/common-themes/src/main/resources/theme/base/admin/resources/templates/kc-copy.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 5e01598199..1ad241164f 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 @@ -1080,6 +1080,24 @@ module.config([ '$routeProvider', function($routeProvider) { }, flows : function(AuthenticationFlowsLoader) { return AuthenticationFlowsLoader(); + }, + selectedFlow : function() { + return null; + } + }, + controller : 'AuthenticationFlowsCtrl' + }) + .when('/realms/:realm/authentication/flows/:flow', { + templateUrl : resourceUrl + '/partials/authentication-flows.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + flows : function(AuthenticationFlowsLoader) { + return AuthenticationFlowsLoader(); + }, + selectedFlow : function($route) { + return $route.current.params.flow; } }, controller : 'AuthenticationFlowsCtrl' 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 15a8fa9223..d4db267f65 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 @@ -1616,41 +1616,102 @@ module.controller('IdentityProviderMapperCreateCtrl', function($scope, realm, id }); -module.controller('AuthenticationFlowsCtrl', function($scope, realm, flows, AuthenticationExecutions, Notifications, Dialog, $location) { +module.controller('AuthenticationFlowsCtrl', function($scope, realm, flows, selectedFlow, + AuthenticationFlowsCopy, AuthenticationFlowExecutions, + AuthenticationExecution, AuthenticationExecutionRaisePriority, AuthenticationExecutionLowerPriority, + $modal, Notifications, CopyDialog, $location) { $scope.realm = realm; $scope.flows = flows; if (flows.length > 0) { $scope.flow = flows[0]; + if (selectedFlow) { + for (var i = 0; i < flows.length; i++) { + if (flows[i].alias == selectedFlow) { + $scope.flow = flows[i]; + break; + } + } + } } + var setupForm = function() { - AuthenticationExecutions.query({realm: realm.realm, alias: $scope.flow.alias}, function(data) { + AuthenticationFlowExecutions.query({realm: realm.realm, alias: $scope.flow.alias}, function(data) { $scope.executions = data; $scope.flowmax = 0; + $scope.levelmax = 0; for (var i = 0; i < $scope.executions.length; i++ ) { - execution = $scope.executions[i]; + var execution = $scope.executions[i]; if (execution.requirementChoices.length > $scope.flowmax) { $scope.flowmax = execution.requirementChoices.length; } + if (execution.level > $scope.levelmax) { + $scope.levelmax = execution.level; + } + } + console.log("levelmax: " + $scope.levelmax); + $scope.levelmaxempties = []; + for (j = 0; j < $scope.levelmax; j++) { + $scope.levelmaxempties.push(j); + } for (var i = 0; i < $scope.executions.length; i++ ) { - execution = $scope.executions[i]; + var execution = $scope.executions[i]; execution.empties = []; for (j = 0; j < $scope.flowmax - execution.requirementChoices.length; j++) { execution.empties.push(j); } + execution.levels = []; + for (j = 0; j < execution.level; j++) { + execution.levels.push(j); + } } }) }; + $scope.copyFlow = function() { + CopyDialog.open('Copy AuthenticationFlow', $scope.flow.alias, function(name) { + AuthenticationFlowsCopy.save({realm: realm.realm, alias: $scope.flow.alias}, { + newName: name + }, function() { + $location.url("/realms/" + realm.realm + '/authentication/flows/' + name); + Notifications.success("Flow copied."); + }) + }) + }; + $scope.updateExecution = function(execution) { var copy = angular.copy(execution); delete copy.empties; - AuthenticationExecutions.update({realm: realm.realm, alias: $scope.flow.alias}, copy, function() { + delete copy.levels; + AuthenticationFlowExecutions.update({realm: realm.realm, alias: $scope.flow.alias}, copy, function() { Notifications.success("Auth requirement updated"); setupForm(); }); }; + + $scope.removeExecution = function(execution) { + console.log('removeExecution: ' + execution.id); + AuthenticationExecution.remove({realm: realm.realm, execution: execution.id}, function() { + Notifications.success("Execution removed"); + setupForm(); + }) + } + + $scope.raisePriority = function(execution) { + AuthenticationExecutionRaisePriority.save({realm: realm.realm, execution: execution.id}, function() { + Notifications.success("Priority raised"); + setupForm(); + }) + } + + $scope.lowerPriority = function(execution) { + AuthenticationExecutionLowerPriority.save({realm: realm.realm, execution: execution.id}, function() { + Notifications.success("Priority lowered"); + setupForm(); + }) + } + $scope.setupForm = setupForm; setupForm(); @@ -1658,7 +1719,7 @@ module.controller('AuthenticationFlowsCtrl', function($scope, realm, flows, Auth }); -module.controller('RequiredActionsCtrl', function($scope, realm, RequiredActions, Notifications, Dialog, $location) { +module.controller('RequiredActionsCtrl', function($scope, realm, RequiredActions, Notifications) { console.log('RequiredActionsCtrl'); $scope.realm = realm; $scope.requiredActions = []; 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 04929ef7f1..479702e9a9 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 @@ -94,6 +94,34 @@ module.service('Dialog', function($modal) { return dialog }); +module.service('CopyDialog', function($modal) { + var dialog = {}; + dialog.open = function (title, suggested, success) { + var controller = function($scope, $modalInstance, title) { + $scope.title = title; + $scope.name = { value: 'Copy of ' + suggested }; + $scope.ok = function () { + console.log('ok with name: ' + $scope.name); + $modalInstance.close(); + success($scope.name.value); + }; + $scope.cancel = function () { + $modalInstance.dismiss('cancel'); + }; + } + $modal.open({ + templateUrl: resourceUrl + '/templates/kc-copy.html', + controller: controller, + resolve: { + title: function() { + return title; + } + } + }); + }; + return dialog; +}); + module.factory('Notifications', function($rootScope, $timeout) { // time (in ms) the notifications are shown var delay = 5000; @@ -1133,7 +1161,7 @@ module.factory('IdentityProviderMapper', function($resource) { }); }); -module.factory('AuthenticationExecutions', function($resource) { +module.factory('AuthenticationFlowExecutions', function($resource) { return $resource(authUrl + '/admin/realms/:realm/authentication/flows/:alias/executions', { realm : '@realm', alias : '@alias' @@ -1149,6 +1177,12 @@ module.factory('AuthenticationFlows', function($resource) { realm : '@realm' }); }); +module.factory('AuthenticationFlowsCopy', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/flows/:alias/copy', { + realm : '@realm', + alias : '@alias' + }); +}); module.factory('AuthenticationConfigDescription', function($resource) { return $resource(authUrl + '/admin/realms/:realm/authentication/config-description/:provider', { realm : '@realm', @@ -1173,6 +1207,33 @@ module.factory('AuthenticationExecutionConfig', function($resource) { }); }); +module.factory('AuthenticationExecution', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/executions/:execution', { + realm : '@realm', + execution : '@execution' + }, { + update : { + method : 'PUT' + } + }); +}); + +module.factory('AuthenticationExecutionRaisePriority', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/executions/:execution/raise-priority', { + realm : '@realm', + execution : '@execution' + }); +}); + +module.factory('AuthenticationExecutionLowerPriority', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/executions/:execution/lower-priority', { + realm : '@realm', + execution : '@execution' + }); +}); + + + module.service('SelectRoleDialog', function($modal) { var dialog = {}; 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 50f01b9b3e..7f98234ef7 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,43 +6,34 @@ - - + - + - + - - - + + + - + + + + diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/modal/role-selector.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/modal/role-selector.html index 55c5430c71..866ecf09ff 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/modal/role-selector.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/modal/role-selector.html @@ -1,5 +1,10 @@ +
-

Role Selector

diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/templates/kc-copy.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/templates/kc-copy.html new file mode 100755 index 0000000000..e0744322cb --- /dev/null +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/templates/kc-copy.html @@ -0,0 +1,18 @@ + + + \ No newline at end of file diff --git a/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java b/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java index f390d1f666..c4f1b6bc57 100755 --- a/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java +++ b/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java @@ -23,7 +23,7 @@ public class AuthenticationExecutionModel implements Serializable { private String authenticatorConfig; private String authenticator; private String flowId; - private boolean autheticatorFlow; + private boolean authenticatorFlow; private Requirement requirement; private boolean userSetupAllowed; private int priority; @@ -103,12 +103,12 @@ public class AuthenticationExecutionModel implements Serializable { * * @return */ - public boolean isAutheticatorFlow() { - return autheticatorFlow; + public boolean isAuthenticatorFlow() { + return authenticatorFlow; } - public void setAutheticatorFlow(boolean autheticatorFlow) { - this.autheticatorFlow = autheticatorFlow; + public void setAuthenticatorFlow(boolean authenticatorFlow) { + this.authenticatorFlow = authenticatorFlow; } public enum Requirement { diff --git a/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java b/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java index 1733c06850..a2c6422a87 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java +++ b/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java @@ -2,13 +2,9 @@ package org.keycloak.models.utils; import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.AuthenticationFlowModel; -import org.keycloak.models.AuthenticatorConfigModel; import org.keycloak.models.RealmModel; import org.keycloak.models.RequiredCredentialModel; -import java.util.HashMap; -import java.util.Map; - /** * @author Bill Burke * @version $Revision: 1 $ @@ -60,7 +56,7 @@ public class DefaultAuthenticationFlows { execution.setAuthenticator("registration-page-form"); execution.setPriority(10); execution.setUserSetupAllowed(false); - execution.setAutheticatorFlow(true); + execution.setAuthenticatorFlow(true); execution.setFlowId(registrationFormFlow.getId()); realm.addAuthenticatorExecution(execution); @@ -70,7 +66,7 @@ public class DefaultAuthenticationFlows { execution.setAuthenticator("registration-user-creation"); execution.setPriority(20); execution.setUserSetupAllowed(false); - execution.setAutheticatorFlow(false); + execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); execution = new AuthenticationExecutionModel(); @@ -79,7 +75,7 @@ public class DefaultAuthenticationFlows { execution.setAuthenticator("registration-profile-action"); execution.setPriority(40); execution.setUserSetupAllowed(false); - execution.setAutheticatorFlow(false); + execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); execution = new AuthenticationExecutionModel(); @@ -88,7 +84,7 @@ public class DefaultAuthenticationFlows { execution.setAuthenticator("registration-password-action"); execution.setPriority(50); execution.setUserSetupAllowed(false); - execution.setAutheticatorFlow(false); + execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); //AuthenticatorConfigModel captchaConfig = new AuthenticatorConfigModel(); @@ -104,7 +100,7 @@ public class DefaultAuthenticationFlows { execution.setAuthenticator("registration-recaptcha-action"); execution.setPriority(60); execution.setUserSetupAllowed(false); - execution.setAutheticatorFlow(false); + execution.setAuthenticatorFlow(false); //execution.setAuthenticatorConfig(captchaConfig.getId()); realm.addAuthenticatorExecution(execution); @@ -142,7 +138,7 @@ public class DefaultAuthenticationFlows { execution.setAuthenticator("direct-grant-validate-username"); execution.setPriority(10); execution.setUserSetupAllowed(false); - execution.setAutheticatorFlow(false); + execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); // password @@ -155,7 +151,7 @@ public class DefaultAuthenticationFlows { execution.setAuthenticator("direct-grant-validate-password"); execution.setPriority(20); execution.setUserSetupAllowed(false); - execution.setAutheticatorFlow(false); + execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); // otp @@ -168,7 +164,7 @@ public class DefaultAuthenticationFlows { execution.setAuthenticator("direct-grant-validate-otp"); execution.setPriority(30); execution.setUserSetupAllowed(false); - execution.setAutheticatorFlow(false); + execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); @@ -189,7 +185,7 @@ public class DefaultAuthenticationFlows { execution.setAuthenticator("auth-cookie"); execution.setPriority(10); execution.setUserSetupAllowed(false); - execution.setAutheticatorFlow(false); + execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); execution = new AuthenticationExecutionModel(); execution.setParentFlow(browser.getId()); @@ -201,7 +197,7 @@ public class DefaultAuthenticationFlows { execution.setAuthenticator("auth-spnego"); execution.setPriority(20); execution.setUserSetupAllowed(false); - execution.setAutheticatorFlow(false); + execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); @@ -218,7 +214,7 @@ public class DefaultAuthenticationFlows { execution.setFlowId(forms.getId()); execution.setPriority(30); execution.setUserSetupAllowed(false); - execution.setAutheticatorFlow(true); + execution.setAuthenticatorFlow(true); realm.addAuthenticatorExecution(execution); // forms @@ -229,7 +225,7 @@ public class DefaultAuthenticationFlows { execution.setAuthenticator("auth-username-password-form"); execution.setPriority(10); execution.setUserSetupAllowed(false); - execution.setAutheticatorFlow(false); + execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); // otp processing @@ -244,7 +240,7 @@ public class DefaultAuthenticationFlows { execution.setAuthenticator("auth-otp-form"); execution.setPriority(20); execution.setUserSetupAllowed(true); - execution.setAutheticatorFlow(false); + execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); } } 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 c2b14cdc2c..9e1b44e758 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 @@ -462,7 +462,7 @@ public class ModelToRepresentation { rep.setAuthenticatorConfig(config.getAlias()); } rep.setAuthenticator(model.getAuthenticator()); - rep.setAutheticatorFlow(model.isAutheticatorFlow()); + rep.setAutheticatorFlow(model.isAuthenticatorFlow()); if (model.getFlowId() != null) { AuthenticationFlowModel flow = realm.getAuthenticationFlowById(model.getFlowId()); rep.setFlowAlias(flow.getAlias()); 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 83c8273acf..fe08937966 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 @@ -1077,7 +1077,7 @@ public class RepresentationToModel { model.setAuthenticatorConfig(config.getId()); } model.setAuthenticator(rep.getAuthenticator()); - model.setAutheticatorFlow(rep.isAutheticatorFlow()); + model.setAuthenticatorFlow(rep.isAutheticatorFlow()); if (rep.getFlowAlias() != null) { AuthenticationFlowModel flow = realm.getFlowByAlias(rep.getFlowAlias()); model.setFlowId(flow.getId()); diff --git a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java index 09d43042d7..3d67e93e1f 100755 --- a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java +++ b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java @@ -1314,7 +1314,7 @@ public class RealmAdapter implements RealmModel { model.setAuthenticator(entity.getAuthenticator()); model.setParentFlow(entity.getParentFlow()); model.setFlowId(entity.getFlowId()); - model.setAutheticatorFlow(entity.isAuthenticatorFlow()); + model.setAuthenticatorFlow(entity.isAuthenticatorFlow()); model.setAuthenticatorConfig(entity.getAuthenticatorConfig()); return model; } @@ -1346,7 +1346,7 @@ public class RealmAdapter implements RealmModel { entity.setPriority(model.getPriority()); entity.setRequirement(model.getRequirement()); entity.setUserSetupAllowed(model.isUserSetupAllowed()); - entity.setAuthenticatorFlow(model.isAutheticatorFlow()); + entity.setAuthenticatorFlow(model.isAuthenticatorFlow()); entity.setFlowId(model.getFlowId()); entity.setAuthenticatorConfig(model.getAuthenticatorConfig()); AuthenticationFlowEntity flow = getFlowEntity(model.getId()); @@ -1366,7 +1366,7 @@ public class RealmAdapter implements RealmModel { } } if (entity == null) return; - entity.setAuthenticatorFlow(model.isAutheticatorFlow()); + entity.setAuthenticatorFlow(model.isAuthenticatorFlow()); entity.setAuthenticator(model.getAuthenticator()); entity.setPriority(model.getPriority()); entity.setRequirement(model.getRequirement()); diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java index fe2ded8329..84938bfd34 100755 --- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java +++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java @@ -1075,7 +1075,6 @@ public class RealmAdapter implements RealmModel { @Override public List getAuthenticationExecutions(String flowId) { if (updated != null) return updated.getAuthenticationExecutions(flowId); - List models = new ArrayList<>(); return cached.getAuthenticationExecutions().get(flowId); } diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java index dd6e2e7705..f4b1e35d24 100755 --- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java +++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java @@ -197,6 +197,7 @@ public class CachedRealm implements Serializable { defaultLocale = model.getDefaultLocale(); for (AuthenticationFlowModel flow : model.getAuthenticationFlows()) { authenticationFlows.put(flow.getId(), flow); + authenticationExecutions.put(flow.getId(), new LinkedList()); for (AuthenticationExecutionModel execution : model.getAuthenticationExecutions(flow.getId())) { authenticationExecutions.add(flow.getId(), execution); executionsById.put(execution.getId(), execution); diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java index 51148f0558..f3d44b19d5 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java @@ -1628,7 +1628,7 @@ public class RealmAdapter implements RealmModel { model.setAuthenticator(entity.getAuthenticator()); model.setFlowId(entity.getFlowId()); model.setParentFlow(entity.getParentFlow().getId()); - model.setAutheticatorFlow(entity.isAutheticatorFlow()); + model.setAuthenticatorFlow(entity.isAutheticatorFlow()); model.setAuthenticatorConfig(entity.getAuthenticatorConfig()); return model; } @@ -1655,7 +1655,7 @@ public class RealmAdapter implements RealmModel { flow.getExecutions().add(entity); entity.setRealm(realm); entity.setUserSetupAllowed(model.isUserSetupAllowed()); - entity.setAutheticatorFlow(model.isAutheticatorFlow()); + entity.setAutheticatorFlow(model.isAuthenticatorFlow()); em.persist(entity); em.flush(); model.setId(entity.getId()); @@ -1667,7 +1667,7 @@ public class RealmAdapter implements RealmModel { public void updateAuthenticatorExecution(AuthenticationExecutionModel model) { AuthenticationExecutionEntity entity = em.find(AuthenticationExecutionEntity.class, model.getId()); if (entity == null) return; - entity.setAutheticatorFlow(model.isAutheticatorFlow()); + entity.setAutheticatorFlow(model.isAuthenticatorFlow()); entity.setAuthenticator(model.getAuthenticator()); entity.setPriority(model.getPriority()); entity.setRequirement(model.getRequirement()); diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java index 823a51b3c7..28b1c4ddd9 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java @@ -1390,7 +1390,7 @@ public class RealmAdapter extends AbstractMongoAdapter impleme model.setAuthenticator(entity.getAuthenticator()); model.setFlowId(entity.getFlowId()); model.setParentFlow(entity.getParentFlow()); - model.setAutheticatorFlow(entity.isAuthenticatorFlow()); + model.setAuthenticatorFlow(entity.isAuthenticatorFlow()); model.setAuthenticatorConfig(entity.getAuthenticatorConfig()); return model; } @@ -1422,7 +1422,7 @@ public class RealmAdapter extends AbstractMongoAdapter impleme entity.setPriority(model.getPriority()); entity.setRequirement(model.getRequirement()); entity.setUserSetupAllowed(model.isUserSetupAllowed()); - entity.setAuthenticatorFlow(model.isAutheticatorFlow()); + entity.setAuthenticatorFlow(model.isAuthenticatorFlow()); entity.setFlowId(model.getFlowId()); entity.setParentFlow(model.getParentFlow()); entity.setAuthenticatorConfig(model.getAuthenticatorConfig()); @@ -1444,7 +1444,7 @@ public class RealmAdapter extends AbstractMongoAdapter impleme } } if (entity == null) return; - entity.setAuthenticatorFlow(model.isAutheticatorFlow()); + entity.setAuthenticatorFlow(model.isAuthenticatorFlow()); entity.setAuthenticator(model.getAuthenticator()); entity.setPriority(model.getPriority()); entity.setRequirement(model.getRequirement()); diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticatorUtil.java b/services/src/main/java/org/keycloak/authentication/AuthenticatorUtil.java index 45e8c3a123..aa8a3a8682 100755 --- a/services/src/main/java/org/keycloak/authentication/AuthenticatorUtil.java +++ b/services/src/main/java/org/keycloak/authentication/AuthenticatorUtil.java @@ -1,7 +1,6 @@ package org.keycloak.authentication; import org.keycloak.models.AuthenticationExecutionModel; -import org.keycloak.models.AuthenticatorConfigModel; import org.keycloak.models.RealmModel; import java.util.LinkedList; @@ -21,9 +20,11 @@ public class AuthenticatorUtil { } public static void recurseExecutions(RealmModel realm, String flowId, List executions) { - for (AuthenticationExecutionModel model : realm.getAuthenticationExecutions(flowId)) { + List authenticationExecutions = realm.getAuthenticationExecutions(flowId); + if (authenticationExecutions == null) return; + for (AuthenticationExecutionModel model : authenticationExecutions) { executions.add(model); - if (model.isAutheticatorFlow() && model.isEnabled()) { + if (model.isAuthenticatorFlow() && model.isEnabled()) { recurseExecutions(realm, model.getFlowId(), executions); } } @@ -31,7 +32,7 @@ public class AuthenticatorUtil { public static AuthenticationExecutionModel findExecutionByAuthenticator(RealmModel realm, String flowId, String authProviderId) { for (AuthenticationExecutionModel model : realm.getAuthenticationExecutions(flowId)) { - if (model.isAutheticatorFlow()) { + if (model.isAuthenticatorFlow()) { AuthenticationExecutionModel recurse = findExecutionByAuthenticator(realm, model.getFlowId(), authProviderId); if (recurse != null) return recurse; diff --git a/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java b/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java index 524d7a9f6d..be92d6ee02 100755 --- a/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java +++ b/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java @@ -49,7 +49,7 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow { alternativeSuccessful = true; continue; } - if (model.isAutheticatorFlow()) { + if (model.isAuthenticatorFlow()) { AuthenticationFlow authenticationFlow = processor.createFlowExecution(model.getFlowId(), model); return authenticationFlow.processAction(actionExecution); } else if (model.getId().equals(actionExecution)) { @@ -79,7 +79,7 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow { processor.getClientSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SKIPPED); continue; } - if (model.isAutheticatorFlow()) { + if (model.isAuthenticatorFlow()) { AuthenticationFlow authenticationFlow = processor.createFlowExecution(model.getFlowId(), model); Response flowChallenge = authenticationFlow.processFlow(); if (flowChallenge == null) { diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java index c4618eac25..3ce1e19d5f 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java @@ -35,7 +35,7 @@ public class RoleNameMapper extends AbstractOIDCProtocolMapper implements OIDCAc property.setName(ROLE_CONFIG); property.setLabel("Role"); property.setHelpText("Role name you want changed. Click 'Select Role' button to browse roles, or just type it in the textbox. To reference an application role the syntax is appname.approle, i.e. myapp.myrole"); - property.setType(ProviderConfigProperty.STRING_TYPE); + property.setType(ProviderConfigProperty.ROLE_TYPE); configProperties.add(property); property = new ProviderConfigProperty(); property.setName(NEW_ROLE_NAME); 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 5f55c765dd..41380abf20 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 @@ -2,6 +2,7 @@ package org.keycloak.services.resources.admin; import org.jboss.logging.Logger; import org.jboss.resteasy.annotations.cache.NoCache; +import org.jboss.resteasy.spi.BadRequestException; import org.jboss.resteasy.spi.NotFoundException; import org.keycloak.authentication.AuthenticationFlow; import org.keycloak.authentication.AuthenticatorUtil; @@ -28,6 +29,7 @@ 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.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -59,13 +61,15 @@ public class AuthenticationManagementResource { public static class AuthenticationExecutionRepresentation { protected String id; - protected String referenceType; protected String requirement; + protected String displayName; protected List requirementChoices; protected Boolean configurable; - protected Boolean subFlow; + protected Boolean authenticationFlow; protected String providerId; protected String authenticationConfig; + protected int level; + protected int index; public String getId() { return id; @@ -75,12 +79,12 @@ public class AuthenticationManagementResource { this.id = execution; } - public String getReferenceType() { - return referenceType; + public String getDisplayName() { + return displayName; } - public void setReferenceType(String referenceType) { - this.referenceType = referenceType; + public void setDisplayName(String displayName) { + this.displayName = displayName; } public String getRequirement() { @@ -107,14 +111,6 @@ public class AuthenticationManagementResource { this.configurable = configurable; } - public Boolean getSubFlow() { - return subFlow; - } - - public void setSubFlow(Boolean subFlow) { - this.subFlow = subFlow; - } - public String getProviderId() { return providerId; } @@ -130,6 +126,30 @@ public class AuthenticationManagementResource { public void setAuthenticationConfig(String authenticationConfig) { this.authenticationConfig = authenticationConfig; } + + public Boolean getAuthenticationFlow() { + return authenticationFlow; + } + + public void setAuthenticationFlow(Boolean authenticationFlow) { + this.authenticationFlow = authenticationFlow; + } + + public int getLevel() { + return level; + } + + public void setLevel(int level) { + this.level = level; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } } @Path("/flows") @@ -147,6 +167,72 @@ public class AuthenticationManagementResource { return flows; } + @Path("/flows") + @POST + @NoCache + @Consumes(MediaType.APPLICATION_JSON) + public Response createFlow(AuthenticationFlowModel model) { + this.auth.requireManage(); + + if (realm.getFlowByAlias(model.getAlias()) != null) { + return Response.status(Response.Status.CONFLICT).build(); + } + + realm.addAuthenticationFlow(model); + return Response.status(201).build(); + + } + + @Path("/flows/{flowAlias}/copy") + @POST + @NoCache + @Consumes(MediaType.APPLICATION_JSON) + public Response copy(@PathParam("flowAlias") String flowAlias, Map data) { + this.auth.requireManage(); + + String newName = data.get("newName"); + if (realm.getFlowByAlias(newName) != null) { + return Response.status(Response.Status.CONFLICT).build(); + } + + AuthenticationFlowModel flow = realm.getFlowByAlias(flowAlias); + if (flow == null) { + logger.debug("flow not found: " + flowAlias); + return Response.status(NOT_FOUND).build(); + } + AuthenticationFlowModel copy = new AuthenticationFlowModel(); + copy.setAlias(newName); + copy.setDescription(flow.getDescription()); + copy.setProviderId(flow.getProviderId()); + copy.setBuiltIn(false); + copy.setTopLevel(flow.isTopLevel()); + copy = realm.addAuthenticationFlow(copy); + copy(newName, flow, copy); + + return Response.status(201).build(); + + } + + protected void copy(String newName, AuthenticationFlowModel from, AuthenticationFlowModel to) { + for (AuthenticationExecutionModel execution : realm.getAuthenticationExecutions(from.getId())) { + if (execution.isAuthenticatorFlow()) { + AuthenticationFlowModel subFlow = realm.getAuthenticationFlowById(execution.getFlowId()); + AuthenticationFlowModel copy = new AuthenticationFlowModel(); + copy.setAlias(newName + " " + subFlow.getAlias()); + copy.setDescription(subFlow.getDescription()); + copy.setProviderId(subFlow.getProviderId()); + copy.setBuiltIn(false); + copy.setTopLevel(false); + copy = realm.addAuthenticationFlow(copy); + execution.setFlowId(copy.getId()); + copy(newName, subFlow, copy); + } + execution.setId(null); + execution.setParentFlow(to.getId()); + realm.addAuthenticatorExecution(execution); + } + } + @Path("/flows/{flowAlias}/executions") @GET @NoCache @@ -160,12 +246,22 @@ public class AuthenticationManagementResource { return Response.status(NOT_FOUND).build(); } List result = new LinkedList<>(); - List executions = AuthenticatorUtil.getEnabledExecutionsRecursively(realm, flow.getId()); + + int level = 0; + + recurseExecutions(flow, result, level); + return Response.ok(result).build(); + } + + public void recurseExecutions(AuthenticationFlowModel flow, List result, int level) { + int index = 0; + List executions = realm.getAuthenticationExecutions(flow.getId()); for (AuthenticationExecutionModel execution : executions) { AuthenticationExecutionRepresentation rep = new AuthenticationExecutionRepresentation(); - rep.setSubFlow(false); + rep.setLevel(level); + rep.setIndex(index++); rep.setRequirementChoices(new LinkedList()); - if (execution.isAutheticatorFlow()) { + if (execution.isAuthenticatorFlow()) { AuthenticationFlowModel flowRef = realm.getAuthenticationFlowById(execution.getFlowId()); if (AuthenticationFlow.BASIC_FLOW.equals(flowRef.getProviderId())) { rep.getRequirementChoices().add(AuthenticationExecutionModel.Requirement.ALTERNATIVE.name()); @@ -176,20 +272,19 @@ public class AuthenticationManagementResource { rep.getRequirementChoices().add(AuthenticationExecutionModel.Requirement.DISABLED.name()); rep.setProviderId(execution.getAuthenticator()); rep.setAuthenticationConfig(execution.getAuthenticatorConfig()); - } - rep.setReferenceType(flowRef.getAlias()); + rep.setDisplayName(flowRef.getAlias()); rep.setConfigurable(false); rep.setId(execution.getId()); + rep.setAuthenticationFlow(execution.isAuthenticatorFlow()); rep.setRequirement(execution.getRequirement().name()); result.add(rep); + AuthenticationFlowModel subFlow = realm.getAuthenticationFlowById(execution.getFlowId()); + recurseExecutions(subFlow, result, level + 1); } else { - if (!flow.getId().equals(execution.getParentFlow())) { - rep.setSubFlow(true); - } String providerId = execution.getAuthenticator(); ConfigurableAuthenticatorFactory factory = CredentialHelper.getConfigurableAuthenticatorFactory(session, providerId); - rep.setReferenceType(factory.getDisplayType()); + rep.setDisplayName(factory.getDisplayType()); rep.setConfigurable(factory.isConfigurable()); for (AuthenticationExecutionModel.Requirement choice : factory.getRequirementChoices()) { rep.getRequirementChoices().add(choice.name()); @@ -199,11 +294,8 @@ public class AuthenticationManagementResource { rep.setProviderId(execution.getAuthenticator()); rep.setAuthenticationConfig(execution.getAuthenticatorConfig()); result.add(rep); - } - } - return Response.ok(result).build(); } @Path("/flows/{flowAlias}/executions") @@ -231,6 +323,134 @@ public class AuthenticationManagementResource { } } + @Path("/executions") + @POST + @NoCache + @Consumes(MediaType.APPLICATION_JSON) + public Response addExecution(AuthenticationExecutionModel model) { + this.auth.requireManage(); + AuthenticationFlowModel parentFlow = getParentFlow(model); + if (parentFlow.isBuiltIn()) { + throw new BadRequestException("It is illegal to add execution to a built in flow"); + } + int priority = 0; + List executions = getSortedExecutions(parentFlow); + for (AuthenticationExecutionModel execution : executions) { + priority = execution.getPriority(); + } + if (priority > 0) priority += 10; + model.setPriority(priority); + model = realm.addAuthenticatorExecution(model); + return Response.created(uriInfo.getAbsolutePathBuilder().path(model.getId()).build()).build(); + } + + public AuthenticationFlowModel getParentFlow(AuthenticationExecutionModel model) { + if (model.getParentFlow() == null) { + throw new BadRequestException("parent flow not set on new execution"); + } + AuthenticationFlowModel parentFlow = realm.getAuthenticationFlowById(model.getParentFlow()); + if (parentFlow == null) { + throw new BadRequestException("execution parent flow does not exist"); + + } + return parentFlow; + } + + @Path("/executions/{executionId}/raise-priority") + @POST + @NoCache + public void raisePriority(@PathParam("executionId") String execution) { + this.auth.requireManage(); + + AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution); + if (model == null) { + session.getTransaction().setRollbackOnly(); + throw new NotFoundException("Illegal execution"); + + } + AuthenticationFlowModel parentFlow = getParentFlow(model); + if (parentFlow.isBuiltIn()) { + throw new BadRequestException("It is illegal to modify execution in a built in flow"); + } + List executions = getSortedExecutions(parentFlow); + AuthenticationExecutionModel previous = null; + for (AuthenticationExecutionModel exe : executions) { + if (exe.getId().equals(model.getId())) { + break; + } + previous = exe; + + } + if (previous == null) return; + int tmp = previous.getPriority(); + previous.setPriority(model.getPriority()); + realm.updateAuthenticatorExecution(previous); + model.setPriority(tmp); + realm.updateAuthenticatorExecution(model); + } + + public List getSortedExecutions(AuthenticationFlowModel parentFlow) { + List executions = realm.getAuthenticationExecutions(parentFlow.getId()); + Collections.sort(executions, AuthenticationExecutionModel.ExecutionComparator.SINGLETON); + return executions; + } + + @Path("/executions/{executionId}/lower-priority") + @POST + @NoCache + public void lowerPriority(@PathParam("executionId") String execution) { + this.auth.requireManage(); + + AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution); + if (model == null) { + session.getTransaction().setRollbackOnly(); + throw new NotFoundException("Illegal execution"); + + } + AuthenticationFlowModel parentFlow = getParentFlow(model); + if (parentFlow.isBuiltIn()) { + throw new BadRequestException("It is illegal to modify execution in a built in flow"); + } + List executions = getSortedExecutions(parentFlow); + int i = 0; + for (i = 0; i < executions.size(); i++) { + if (executions.get(i).getId().equals(model.getId())) { + break; + } + } + if (i + 1 >= executions.size()) return; + AuthenticationExecutionModel next = executions.get(i + 1); + int tmp = model.getPriority(); + model.setPriority(next.getPriority()); + realm.updateAuthenticatorExecution(model); + next.setPriority(tmp); + realm.updateAuthenticatorExecution(next); + } + + + @Path("/executions/{executionId}") + @DELETE + @NoCache + public void removeExecution(@PathParam("executionId") String execution) { + this.auth.requireManage(); + + AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution); + if (model == null) { + session.getTransaction().setRollbackOnly(); + throw new NotFoundException("Illegal execution"); + + } + AuthenticationFlowModel parentFlow = getParentFlow(model); + if (parentFlow.isBuiltIn()) { + throw new BadRequestException("It is illegal to remove execution from a built in flow"); + } + realm.removeAuthenticatorExecution(model); + } + + + + + @Path("/executions/{executionId}/config") @POST @NoCache From 04d3d26cb1c7e724068f2790dafa045872f0cb1c Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Mon, 3 Aug 2015 09:52:56 -0400 Subject: [PATCH 2/3] refactor execution model --- .../resources/META-INF/jpa-changelog-1.5.0.xml | 14 ++++++++++++++ .../resources/META-INF/jpa-changelog-master.xml | 1 + .../jpa/updater/JpaUpdaterProvider.java | 2 +- .../models/AuthenticationExecutionModel.java | 9 --------- .../models/utils/DefaultAuthenticationFlows.java | 13 ------------- .../models/utils/ModelToRepresentation.java | 1 - .../models/utils/RepresentationToModel.java | 1 - .../keycloak/models/file/adapter/RealmAdapter.java | 3 --- .../java/org/keycloak/models/jpa/RealmAdapter.java | 3 --- .../entities/AuthenticationExecutionEntity.java | 11 ----------- .../mongo/keycloak/adapters/RealmAdapter.java | 3 --- .../ConfigurableAuthenticatorFactory.java | 10 ++++++++++ .../authentication/DefaultAuthenticationFlow.java | 2 +- .../authentication/FormAuthenticationFlow.java | 5 +++-- .../browser/CookieAuthenticatorFactory.java | 6 ++++++ .../browser/OTPFormAuthenticatorFactory.java | 5 +++++ .../browser/SpnegoAuthenticatorFactory.java | 6 ++++++ .../browser/UsernamePasswordFormFactory.java | 6 ++++++ .../authenticators/directgrant/ValidateOTP.java | 6 ++++++ .../directgrant/ValidatePassword.java | 6 ++++++ .../directgrant/ValidateUsername.java | 6 ++++++ .../authentication/forms/RegistrationPage.java | 5 +++++ .../authentication/forms/RegistrationPassword.java | 5 +++++ .../authentication/forms/RegistrationProfile.java | 6 ++++++ .../forms/RegistrationRecaptcha.java | 6 ++++++ .../forms/RegistrationUserCreation.java | 6 ++++++ 26 files changed, 99 insertions(+), 48 deletions(-) create mode 100755 connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.5.0.xml 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 new file mode 100755 index 0000000000..4f33cf7cfa --- /dev/null +++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.5.0.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-master.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-master.xml index efba42ce0f..ca5d0e9b38 100755 --- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-master.xml +++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-master.xml @@ -8,4 +8,5 @@ + diff --git a/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java b/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java index dbcc833245..c1f58433a4 100755 --- a/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java +++ b/connections/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java @@ -12,7 +12,7 @@ public interface JpaUpdaterProvider extends Provider { public String FIRST_VERSION = "1.0.0.Final"; - public String LAST_VERSION = "1.4.0"; + public String LAST_VERSION = "1.5.0"; public String getCurrentVersionSql(String defaultSchema); diff --git a/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java b/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java index c4f1b6bc57..acb3975e26 100755 --- a/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java +++ b/model/api/src/main/java/org/keycloak/models/AuthenticationExecutionModel.java @@ -25,7 +25,6 @@ public class AuthenticationExecutionModel implements Serializable { private String flowId; private boolean authenticatorFlow; private Requirement requirement; - private boolean userSetupAllowed; private int priority; private String parentFlow; @@ -69,14 +68,6 @@ public class AuthenticationExecutionModel implements Serializable { this.priority = priority; } - public boolean isUserSetupAllowed() { - return userSetupAllowed; - } - - public void setUserSetupAllowed(boolean userSetupAllowed) { - this.userSetupAllowed = userSetupAllowed; - } - public String getParentFlow() { return parentFlow; } diff --git a/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java b/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java index a2c6422a87..7995887b81 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java +++ b/model/api/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java @@ -55,7 +55,6 @@ public class DefaultAuthenticationFlows { execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED); execution.setAuthenticator("registration-page-form"); execution.setPriority(10); - execution.setUserSetupAllowed(false); execution.setAuthenticatorFlow(true); execution.setFlowId(registrationFormFlow.getId()); realm.addAuthenticatorExecution(execution); @@ -65,7 +64,6 @@ public class DefaultAuthenticationFlows { execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED); execution.setAuthenticator("registration-user-creation"); execution.setPriority(20); - execution.setUserSetupAllowed(false); execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); @@ -74,7 +72,6 @@ public class DefaultAuthenticationFlows { execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED); execution.setAuthenticator("registration-profile-action"); execution.setPriority(40); - execution.setUserSetupAllowed(false); execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); @@ -83,7 +80,6 @@ public class DefaultAuthenticationFlows { execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED); execution.setAuthenticator("registration-password-action"); execution.setPriority(50); - execution.setUserSetupAllowed(false); execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); @@ -99,7 +95,6 @@ public class DefaultAuthenticationFlows { execution.setRequirement(AuthenticationExecutionModel.Requirement.DISABLED); execution.setAuthenticator("registration-recaptcha-action"); execution.setPriority(60); - execution.setUserSetupAllowed(false); execution.setAuthenticatorFlow(false); //execution.setAuthenticatorConfig(captchaConfig.getId()); realm.addAuthenticatorExecution(execution); @@ -137,7 +132,6 @@ public class DefaultAuthenticationFlows { execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED); execution.setAuthenticator("direct-grant-validate-username"); execution.setPriority(10); - execution.setUserSetupAllowed(false); execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); @@ -150,7 +144,6 @@ public class DefaultAuthenticationFlows { } execution.setAuthenticator("direct-grant-validate-password"); execution.setPriority(20); - execution.setUserSetupAllowed(false); execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); @@ -163,7 +156,6 @@ public class DefaultAuthenticationFlows { } execution.setAuthenticator("direct-grant-validate-otp"); execution.setPriority(30); - execution.setUserSetupAllowed(false); execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); @@ -184,7 +176,6 @@ public class DefaultAuthenticationFlows { execution.setRequirement(AuthenticationExecutionModel.Requirement.ALTERNATIVE); execution.setAuthenticator("auth-cookie"); execution.setPriority(10); - execution.setUserSetupAllowed(false); execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); execution = new AuthenticationExecutionModel(); @@ -196,7 +187,6 @@ public class DefaultAuthenticationFlows { } execution.setAuthenticator("auth-spnego"); execution.setPriority(20); - execution.setUserSetupAllowed(false); execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); @@ -213,7 +203,6 @@ public class DefaultAuthenticationFlows { execution.setRequirement(AuthenticationExecutionModel.Requirement.ALTERNATIVE); execution.setFlowId(forms.getId()); execution.setPriority(30); - execution.setUserSetupAllowed(false); execution.setAuthenticatorFlow(true); realm.addAuthenticatorExecution(execution); @@ -224,7 +213,6 @@ public class DefaultAuthenticationFlows { execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED); execution.setAuthenticator("auth-username-password-form"); execution.setPriority(10); - execution.setUserSetupAllowed(false); execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); @@ -239,7 +227,6 @@ public class DefaultAuthenticationFlows { execution.setAuthenticator("auth-otp-form"); execution.setPriority(20); - execution.setUserSetupAllowed(true); execution.setAuthenticatorFlow(false); realm.addAuthenticatorExecution(execution); } 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 9e1b44e758..3fcde28996 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 @@ -468,7 +468,6 @@ public class ModelToRepresentation { rep.setFlowAlias(flow.getAlias()); } rep.setPriority(model.getPriority()); - rep.setUserSetupAllowed(model.isUserSetupAllowed()); rep.setRequirement(model.getRequirement().name()); return rep; } 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 fe08937966..92060b01ef 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 @@ -1083,7 +1083,6 @@ public class RepresentationToModel { model.setFlowId(flow.getId()); } model.setPriority(rep.getPriority()); - model.setUserSetupAllowed(rep.isUserSetupAllowed()); model.setRequirement(AuthenticationExecutionModel.Requirement.valueOf(rep.getRequirement())); return model; } diff --git a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java index 3d67e93e1f..c2d85d3ba0 100755 --- a/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java +++ b/model/file/src/main/java/org/keycloak/models/file/adapter/RealmAdapter.java @@ -1308,7 +1308,6 @@ public class RealmAdapter implements RealmModel { public AuthenticationExecutionModel entityToModel(AuthenticationExecutionEntity entity) { AuthenticationExecutionModel model = new AuthenticationExecutionModel(); model.setId(entity.getId()); - model.setUserSetupAllowed(entity.isUserSetupAllowed()); model.setRequirement(entity.getRequirement()); model.setPriority(entity.getPriority()); model.setAuthenticator(entity.getAuthenticator()); @@ -1345,7 +1344,6 @@ public class RealmAdapter implements RealmModel { entity.setAuthenticator(model.getAuthenticator()); entity.setPriority(model.getPriority()); entity.setRequirement(model.getRequirement()); - entity.setUserSetupAllowed(model.isUserSetupAllowed()); entity.setAuthenticatorFlow(model.isAuthenticatorFlow()); entity.setFlowId(model.getFlowId()); entity.setAuthenticatorConfig(model.getAuthenticatorConfig()); @@ -1371,7 +1369,6 @@ public class RealmAdapter implements RealmModel { entity.setPriority(model.getPriority()); entity.setRequirement(model.getRequirement()); entity.setFlowId(model.getFlowId()); - entity.setUserSetupAllowed(model.isUserSetupAllowed()); entity.setAuthenticatorConfig(model.getAuthenticatorConfig()); } diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java index f3d44b19d5..c7dcf5aef3 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java @@ -1622,7 +1622,6 @@ public class RealmAdapter implements RealmModel { public AuthenticationExecutionModel entityToModel(AuthenticationExecutionEntity entity) { AuthenticationExecutionModel model = new AuthenticationExecutionModel(); model.setId(entity.getId()); - model.setUserSetupAllowed(entity.isUserSetupAllowed()); model.setRequirement(entity.getRequirement()); model.setPriority(entity.getPriority()); model.setAuthenticator(entity.getAuthenticator()); @@ -1654,7 +1653,6 @@ public class RealmAdapter implements RealmModel { entity.setParentFlow(flow); flow.getExecutions().add(entity); entity.setRealm(realm); - entity.setUserSetupAllowed(model.isUserSetupAllowed()); entity.setAutheticatorFlow(model.isAuthenticatorFlow()); em.persist(entity); em.flush(); @@ -1671,7 +1669,6 @@ public class RealmAdapter implements RealmModel { entity.setAuthenticator(model.getAuthenticator()); entity.setPriority(model.getPriority()); entity.setRequirement(model.getRequirement()); - entity.setUserSetupAllowed(model.isUserSetupAllowed()); entity.setAuthenticatorConfig(model.getAuthenticatorConfig()); entity.setFlowId(model.getFlowId()); em.flush(); diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java index 60dfccd3de..574849f489 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationExecutionEntity.java @@ -51,9 +51,6 @@ public class AuthenticationExecutionEntity { @Column(name="PRIORITY") protected int priority; - @Column(name="USER_SETUP_ALLOWED") - private boolean userSetupAllowed; - @Column(name="AUTHENTICATOR_FLOW") private boolean autheticatorFlow; @@ -97,14 +94,6 @@ public class AuthenticationExecutionEntity { this.priority = priority; } - public boolean isUserSetupAllowed() { - return userSetupAllowed; - } - - public void setUserSetupAllowed(boolean userSetupAllowed) { - this.userSetupAllowed = userSetupAllowed; - } - public boolean isAutheticatorFlow() { return autheticatorFlow; } diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java index 28b1c4ddd9..795ccbf29d 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java @@ -1384,7 +1384,6 @@ public class RealmAdapter extends AbstractMongoAdapter impleme public AuthenticationExecutionModel entityToModel(AuthenticationExecutionEntity entity) { AuthenticationExecutionModel model = new AuthenticationExecutionModel(); model.setId(entity.getId()); - model.setUserSetupAllowed(entity.isUserSetupAllowed()); model.setRequirement(entity.getRequirement()); model.setPriority(entity.getPriority()); model.setAuthenticator(entity.getAuthenticator()); @@ -1421,7 +1420,6 @@ public class RealmAdapter extends AbstractMongoAdapter impleme entity.setAuthenticator(model.getAuthenticator()); entity.setPriority(model.getPriority()); entity.setRequirement(model.getRequirement()); - entity.setUserSetupAllowed(model.isUserSetupAllowed()); entity.setAuthenticatorFlow(model.isAuthenticatorFlow()); entity.setFlowId(model.getFlowId()); entity.setParentFlow(model.getParentFlow()); @@ -1449,7 +1447,6 @@ public class RealmAdapter extends AbstractMongoAdapter impleme entity.setPriority(model.getPriority()); entity.setRequirement(model.getRequirement()); entity.setFlowId(model.getFlowId()); - entity.setUserSetupAllowed(model.isUserSetupAllowed()); entity.setAuthenticatorConfig(model.getAuthenticatorConfig()); updateMongoEntity(); } diff --git a/services/src/main/java/org/keycloak/authentication/ConfigurableAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/ConfigurableAuthenticatorFactory.java index 9e8705af95..ab807ca28b 100755 --- a/services/src/main/java/org/keycloak/authentication/ConfigurableAuthenticatorFactory.java +++ b/services/src/main/java/org/keycloak/authentication/ConfigurableAuthenticatorFactory.java @@ -25,4 +25,14 @@ public interface ConfigurableAuthenticatorFactory extends ConfiguredProvider { * @return */ AuthenticationExecutionModel.Requirement[] getRequirementChoices(); + + /** + * + * Does this authenticator have required actions that can set if the user does not have + * this authenticator set up? + * + * + * @return + */ + boolean isUserSetupAllowed(); } diff --git a/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java b/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java index be92d6ee02..a84131a712 100755 --- a/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java +++ b/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java @@ -124,7 +124,7 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow { configuredFor = authenticator.configuredFor(processor.getSession(), processor.getRealm(), authUser); if (!configuredFor) { if (model.isRequired()) { - if (model.isUserSetupAllowed()) { + if (factory.isUserSetupAllowed()) { AuthenticationProcessor.logger.debugv("authenticator SETUP_REQUIRED: {0}", factory.getId()); processor.getClientSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SETUP_REQUIRED); authenticator.setRequiredActions(processor.getSession(), processor.getRealm(), processor.getClientSession().getAuthenticatedUser()); diff --git a/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java b/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java index 782c8629ff..d24474039c 100755 --- a/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java +++ b/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java @@ -152,7 +152,8 @@ public class FormAuthenticationFlow implements AuthenticationFlow { executionStatus.put(formActionExecution.getId(), ClientSessionModel.ExecutionStatus.SKIPPED); continue; } - FormAction action = processor.getSession().getProvider(FormAction.class, formActionExecution.getAuthenticator()); + FormActionFactory factory = (FormActionFactory)processor.getSession().getKeycloakSessionFactory().getProviderFactory(FormAction.class, formActionExecution.getAuthenticator()); + FormAction action = factory.create(processor.getSession()); UserModel authUser = processor.getClientSession().getAuthenticatedUser(); if (action.requiresUser() && authUser == null) { @@ -163,7 +164,7 @@ public class FormAuthenticationFlow implements AuthenticationFlow { configuredFor = action.configuredFor(processor.getSession(), processor.getRealm(), authUser); if (!configuredFor) { if (formActionExecution.isRequired()) { - if (formActionExecution.isUserSetupAllowed()) { + if (factory.isUserSetupAllowed()) { AuthenticationProcessor.logger.debugv("authenticator SETUP_REQUIRED: {0}", formExecution.getAuthenticator()); executionStatus.put(formActionExecution.getId(), ClientSessionModel.ExecutionStatus.SETUP_REQUIRED); requiredActions.add(action); diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/CookieAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/CookieAuthenticatorFactory.java index da9209dacb..4845b12a43 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/CookieAuthenticatorFactory.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/CookieAuthenticatorFactory.java @@ -78,4 +78,10 @@ public class CookieAuthenticatorFactory implements AuthenticatorFactory { public List getConfigProperties() { return null; } + + @Override + public boolean isUserSetupAllowed() { + return false; + } + } diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/OTPFormAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/OTPFormAuthenticatorFactory.java index 29b1c636cb..1a01e5a8f3 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/OTPFormAuthenticatorFactory.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/OTPFormAuthenticatorFactory.java @@ -59,6 +59,11 @@ public class OTPFormAuthenticatorFactory implements AuthenticatorFactory { return false; } + @Override + public boolean isUserSetupAllowed() { + return true; + } + public static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = { AuthenticationExecutionModel.Requirement.REQUIRED, AuthenticationExecutionModel.Requirement.OPTIONAL, diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticatorFactory.java index 462967580e..ecfa06863b 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticatorFactory.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticatorFactory.java @@ -84,4 +84,10 @@ public class SpnegoAuthenticatorFactory implements AuthenticatorFactory { public List getConfigProperties() { return null; } + + @Override + public boolean isUserSetupAllowed() { + return false; + } + } diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/UsernamePasswordFormFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/UsernamePasswordFormFactory.java index adc2815b48..392a02abae 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/UsernamePasswordFormFactory.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/UsernamePasswordFormFactory.java @@ -81,4 +81,10 @@ public class UsernamePasswordFormFactory implements AuthenticatorFactory { public List getConfigProperties() { return null; } + + @Override + public boolean isUserSetupAllowed() { + return false; + } + } diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateOTP.java b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateOTP.java index 8a71f52a87..7d4da65165 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateOTP.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateOTP.java @@ -82,6 +82,12 @@ public class ValidateOTP extends AbstractDirectGrantAuthenticator { } + @Override + public boolean isUserSetupAllowed() { + return false; + } + + @Override public String getDisplayType() { return "OTP"; diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidatePassword.java b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidatePassword.java index 55ba2f8278..792fd5ef76 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidatePassword.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidatePassword.java @@ -73,6 +73,12 @@ public class ValidatePassword extends AbstractDirectGrantAuthenticator { } + @Override + public boolean isUserSetupAllowed() { + return false; + } + + @Override public String getDisplayType() { return "Password"; diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateUsername.java b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateUsername.java index 330860b1a6..5a9cd800b2 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateUsername.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateUsername.java @@ -103,6 +103,12 @@ public class ValidateUsername extends AbstractDirectGrantAuthenticator { } + @Override + public boolean isUserSetupAllowed() { + return false; + } + + @Override public String getDisplayType() { return "Username Validation"; 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 37c0d238cc..8748b54803 100755 --- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationPage.java +++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationPage.java @@ -82,6 +82,11 @@ public class RegistrationPage implements FormAuthenticator, FormAuthenticatorFac } + @Override + public boolean isUserSetupAllowed() { + return false; + } + @Override public void postInit(KeycloakSessionFactory factory) { 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 92c87f67f1..9cf771dd57 100755 --- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java +++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java @@ -105,6 +105,11 @@ public class RegistrationPassword implements FormAction, FormActionFactory { } + @Override + public boolean isUserSetupAllowed() { + return false; + } + @Override public void close() { 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 46c4bdaf4c..2019db8026 100755 --- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationProfile.java +++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationProfile.java @@ -110,6 +110,12 @@ public class RegistrationProfile implements FormAction, FormActionFactory { } + @Override + public boolean isUserSetupAllowed() { + return false; + } + + @Override public void close() { 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 8f143ed742..b4bb3b0486 100755 --- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationRecaptcha.java +++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationRecaptcha.java @@ -158,6 +158,12 @@ public class RegistrationRecaptcha implements FormAction, FormActionFactory, Con } + @Override + public boolean isUserSetupAllowed() { + return false; + } + + @Override public void close() { 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 98659572bf..0a446dab15 100755 --- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java +++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java @@ -149,6 +149,12 @@ public class RegistrationUserCreation implements FormAction, FormActionFactory { } + @Override + public boolean isUserSetupAllowed() { + return false; + } + + @Override public void close() { From 930fc66ebf599d886cadab86fe1f9b337f089ef6 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Mon, 3 Aug 2015 18:58:14 -0400 Subject: [PATCH 3/3] flow editing --- .../theme/base/admin/resources/js/app.js | 42 +++++ .../admin/resources/js/controllers/realm.js | 136 +++++++++++++++- .../theme/base/admin/resources/js/loaders.js | 34 ++++ .../theme/base/admin/resources/js/services.js | 37 ++++- .../partials/authentication-flows.html | 42 ++--- .../resources/partials/create-execution.html | 29 ++++ .../partials/create-flow-execution.html | 55 +++++++ .../admin/resources/partials/create-flow.html | 30 ++++ .../forms/RegistrationPage.java | 2 +- .../forms/RegistrationPassword.java | 2 +- .../forms/RegistrationProfile.java | 2 +- .../forms/RegistrationRecaptcha.java | 2 +- .../forms/RegistrationUserCreation.java | 2 +- .../AuthenticationManagementResource.java | 149 ++++++++++++++++++ 14 files changed, 530 insertions(+), 34 deletions(-) create mode 100755 forms/common-themes/src/main/resources/theme/base/admin/resources/partials/create-execution.html create mode 100755 forms/common-themes/src/main/resources/theme/base/admin/resources/partials/create-flow-execution.html create mode 100755 forms/common-themes/src/main/resources/theme/base/admin/resources/partials/create-flow.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 1ad241164f..fbaefd18d2 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 @@ -1102,6 +1102,48 @@ module.config([ '$routeProvider', function($routeProvider) { }, controller : 'AuthenticationFlowsCtrl' }) + .when('/realms/:realm/authentication/flows/:flow/create/execution', { + templateUrl : resourceUrl + '/partials/create-execution.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + parentFlow : function(AuthenticationFlowLoader) { + return AuthenticationFlowLoader(); + }, + formActionProviders : function(AuthenticationFormActionProvidersLoader) { + return AuthenticationFormActionProvidersLoader(); + }, + authenticatorProviders : function(AuthenticatorProvidersLoader) { + return AuthenticatorProvidersLoader(); + } + }, + controller : 'CreateExecutionCtrl' + }) + .when('/realms/:realm/authentication/flows/:flow/create/flow/execution', { + templateUrl : resourceUrl + '/partials/create-flow-execution.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + }, + parentFlow : function(AuthenticationFlowLoader) { + return AuthenticationFlowLoader(); + }, + formProviders : function(AuthenticationFormProvidersLoader) { + return AuthenticationFormProvidersLoader(); + } + }, + controller : 'CreateExecutionFlowCtrl' + }) + .when('/realms/:realm/authentication/create/flow', { + templateUrl : resourceUrl + '/partials/create-flow.html', + resolve : { + realm : function(RealmLoader) { + return RealmLoader(); + } + }, + controller : 'CreateFlowCtrl' + }) .when('/realms/:realm/authentication/required-actions', { templateUrl : resourceUrl + '/partials/required-actions.html', resolve : { 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 d4db267f65..d17505c34b 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 @@ -1616,8 +1616,91 @@ module.controller('IdentityProviderMapperCreateCtrl', function($scope, realm, id }); -module.controller('AuthenticationFlowsCtrl', function($scope, realm, flows, selectedFlow, - AuthenticationFlowsCopy, AuthenticationFlowExecutions, +module.controller('CreateFlowCtrl', function($scope, realm, + AuthenticationFlows, + Notifications, $location) { + $scope.realm = realm; + $scope.flow = { + alias: "", + providerId: "basic-flow", + description: "", + topLevel: true, + builtIn: false + } + + $scope.save = function() { + AuthenticationFlows.save({realm: realm.realm, flow: ""}, $scope.flow, function() { + $location.url("/realms/" + realm.realm + "/authentication/flows/" + $scope.flow.alias); + Notifications.success("Flow Created."); + }) + } + $scope.cancel = function() { + $location.url("/realms/" + realm.realm + "/authentication/flows"); + }; +}); + +module.controller('CreateExecutionFlowCtrl', function($scope, realm, parentFlow, formProviders, + CreateExecutionFlow, + Notifications, $location) { + $scope.realm = realm; + $scope.formProviders = formProviders; + $scope.flow = { + alias: "", + type: "basic-flow", + description: "" + } + $scope.provider = {}; + if (formProviders.length > 0) { + $scope.provider = formProviders[0]; + } + + $scope.save = function() { + $scope.flow.provider = $scope.provider.id; + CreateExecutionFlow.save({realm: realm.realm, alias: parentFlow.alias}, $scope.flow, function() { + $location.url("/realms/" + realm.realm + "/authentication/flows/" + parentFlow.alias); + Notifications.success("Flow Created."); + }) + } + $scope.cancel = function() { + $location.url("/realms/" + realm.realm + "/authentication/flows/" + parentFlow.alias); + }; +}); + +module.controller('CreateExecutionCtrl', function($scope, realm, parentFlow, formActionProviders, authenticatorProviders, + CreateExecution, + Notifications, $location) { + $scope.realm = realm; + $scope.parentFlow = parentFlow; + console.log('parentFlow.providerId: ' + parentFlow.providerId); + if (parentFlow.providerId == 'form-flow') { + $scope.providers = formActionProviders; + } else { + $scope.providers = authenticatorProviders; + } + + $scope.provider = {}; + if ($scope.providers.length > 0) { + $scope.provider = $scope.providers[0]; + } + + $scope.save = function() { + var execution = { + provider: $scope.provider.id + } + CreateExecution.save({realm: realm.realm, alias: parentFlow.alias}, execution, function() { + $location.url("/realms/" + realm.realm + "/authentication/flows/" + parentFlow.alias); + Notifications.success("Execution Created."); + }) + } + $scope.cancel = function() { + $location.url("/realms/" + realm.realm + "/authentication/flows/" + parentFlow.alias); + }; +}); + + + +module.controller('AuthenticationFlowsCtrl', function($scope, $route, realm, flows, selectedFlow, + AuthenticationFlows, AuthenticationFlowsCopy, AuthenticationFlowExecutions, AuthenticationExecution, AuthenticationExecutionRaisePriority, AuthenticationExecutionLowerPriority, $modal, Notifications, CopyDialog, $location) { $scope.realm = realm; @@ -1637,12 +1720,12 @@ module.controller('AuthenticationFlowsCtrl', function($scope, realm, flows, sele var setupForm = function() { AuthenticationFlowExecutions.query({realm: realm.realm, alias: $scope.flow.alias}, function(data) { $scope.executions = data; - $scope.flowmax = 0; + $scope.choicesmax = 0; $scope.levelmax = 0; for (var i = 0; i < $scope.executions.length; i++ ) { var execution = $scope.executions[i]; - if (execution.requirementChoices.length > $scope.flowmax) { - $scope.flowmax = execution.requirementChoices.length; + if (execution.requirementChoices.length > $scope.choicesmax) { + $scope.choicesmax = execution.requirementChoices.length; } if (execution.level > $scope.levelmax) { $scope.levelmax = execution.level; @@ -1657,12 +1740,16 @@ module.controller('AuthenticationFlowsCtrl', function($scope, realm, flows, sele for (var i = 0; i < $scope.executions.length; i++ ) { var execution = $scope.executions[i]; execution.empties = []; - for (j = 0; j < $scope.flowmax - execution.requirementChoices.length; j++) { + for (j = 0; j < $scope.choicesmax - execution.requirementChoices.length; j++) { execution.empties.push(j); } - execution.levels = []; + execution.preLevels = []; for (j = 0; j < execution.level; j++) { - execution.levels.push(j); + execution.preLevels.push(j); + } + execution.postLevels = []; + for (j = execution.level; j < $scope.levelmax; j++) { + execution.postLevels.push(j); } } }) @@ -1679,6 +1766,39 @@ module.controller('AuthenticationFlowsCtrl', function($scope, realm, flows, sele }) }; + $scope.removeFlow = function() { + AuthenticationFlows.remove({realm: realm, flow: flow.id}, function() { + $route.reload(); + Notifications.success("Flow removed"); + + }) + + }; + + $scope.addFlow = function() { + $location.url("/realms/" + realm.realm + '/authentication/flows/' + $scope.flow.id + '/create/flow/execution'); + + } + + $scope.addSubFlow = function(execution) { + $location.url("/realms/" + realm.realm + '/authentication/flows/' + execution.flowId + '/create/flow/execution'); + + } + + $scope.addSubFlowExecution = function(execution) { + $location.url("/realms/" + realm.realm + '/authentication/flows/' + execution.flowId + '/create/execution'); + + } + + $scope.addExecution = function() { + $location.url("/realms/" + realm.realm + '/authentication/flows/' + $scope.flow.id + '/create/execution'); + + } + + $scope.createFlow = function() { + $location.url("/realms/" + realm.realm + '/authentication/create/flow'); + } + $scope.updateExecution = function(execution) { var copy = angular.copy(execution); delete copy.empties; 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 c347759413..2c30dd3646 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 @@ -353,12 +353,46 @@ module.factory('IdentityProviderMapperLoader', function(Loader, IdentityProvider module.factory('AuthenticationFlowsLoader', function(Loader, AuthenticationFlows, $route, $q) { return Loader.query(AuthenticationFlows, function() { + return { + realm : $route.current.params.realm, + flow: '' + } + }); +}); + +module.factory('AuthenticationFormProvidersLoader', function(Loader, AuthenticationFormProviders, $route, $q) { + return Loader.query(AuthenticationFormProviders, function() { return { realm : $route.current.params.realm } }); }); +module.factory('AuthenticationFormActionProvidersLoader', function(Loader, AuthenticationFormActionProviders, $route, $q) { + return Loader.query(AuthenticationFormActionProviders, function() { + return { + realm : $route.current.params.realm + } + }); +}); + +module.factory('AuthenticatorProvidersLoader', function(Loader, AuthenticatorProviders, $route, $q) { + return Loader.query(AuthenticatorProviders, function() { + return { + realm : $route.current.params.realm + } + }); +}); + +module.factory('AuthenticationFlowLoader', function(Loader, AuthenticationFlows, $route, $q) { + return Loader.get(AuthenticationFlows, function() { + return { + realm : $route.current.params.realm, + flow: $route.current.params.flow + } + }); +}); + module.factory('AuthenticationConfigDescriptionLoader', function(Loader, AuthenticationConfigDescription, $route, $q) { return Loader.get(AuthenticationConfigDescription, 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 479702e9a9..64a5ff5727 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 @@ -1172,11 +1172,46 @@ module.factory('AuthenticationFlowExecutions', function($resource) { }); }); +module.factory('CreateExecutionFlow', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/flows/:alias/executions/flow', { + realm : '@realm', + alias : '@alias' + }); +}); + +module.factory('CreateExecution', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/flows/:alias/executions/execution', { + realm : '@realm', + alias : '@alias' + }); +}); + module.factory('AuthenticationFlows', function($resource) { - return $resource(authUrl + '/admin/realms/:realm/authentication/flows', { + return $resource(authUrl + '/admin/realms/:realm/authentication/flows/:flow', { + realm : '@realm', + flow: '@flow' + }); +}); + +module.factory('AuthenticationFormProviders', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/form-providers', { realm : '@realm' }); }); + +module.factory('AuthenticationFormActionProviders', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/form-action-providers', { + realm : '@realm' + }); +}); + +module.factory('AuthenticatorProviders', function($resource) { + return $resource(authUrl + '/admin/realms/:realm/authentication/authenticator-providers', { + realm : '@realm' + }); +}); + + module.factory('AuthenticationFlowsCopy', function($resource) { return $resource(authUrl + '/admin/realms/:realm/authentication/flows/:alias/copy', { realm : '@realm', 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 7f98234ef7..4f2794bbff 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,15 +6,16 @@
+ +
+ + + + + +
Auth TypeAuth Type RequirementActions
{{execution.referenceType|capitalize}} {{execution.displayName|capitalize}} - - - Configure - Configure + + + + + + + + + +
- - - + + - + - + - - - - - diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/create-execution.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/create-execution.html new file mode 100755 index 0000000000..53c82d19e7 --- /dev/null +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/create-execution.html @@ -0,0 +1,29 @@ +
+
+

Create Authenticator Execution

+

Create Form Action Execution

+
+ +
+
+ +
+
+ +
+
+ {{provider.description}} +
+
+
+ + +
+
+ +
+ + \ No newline at end of file diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/create-flow-execution.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/create-flow-execution.html new file mode 100755 index 0000000000..c88d76b90a --- /dev/null +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/create-flow-execution.html @@ -0,0 +1,55 @@ +
+

Create Execution Flow

+ + + +
+
+ +
+ +
+ Specifies display name for the flow. +
+
+ + +
+ +
+
+
+ +
+
+ +
+
+ What kind of form is it +
+
+ +
+
+ +
+
+ {{provider.description}} +
+
+
+ + +
+
+ +
+ + \ No newline at end of file diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/create-flow.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/create-flow.html new file mode 100755 index 0000000000..a298b8592e --- /dev/null +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/create-flow.html @@ -0,0 +1,30 @@ +
+

Create Top Level Flow

+ + + +
+
+ +
+ +
+ Specifies display name for the flow. +
+
+ + +
+ +
+
+
+
+ + +
+
+ +
+ + \ No newline at end of file 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 8748b54803..9a0e9951a6 100755 --- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationPage.java +++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationPage.java @@ -45,7 +45,7 @@ public class RegistrationPage implements FormAuthenticator, FormAuthenticatorFac @Override public String getHelpText() { - return null; + return "This is the controller for the registration page"; } @Override 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 9cf771dd57..ade4e00a48 100755 --- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java +++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java @@ -34,7 +34,7 @@ public class RegistrationPassword implements FormAction, FormActionFactory { @Override public String getHelpText() { - return null; + return "Validates that password matches password confirmation field. It also will store password in user's credential store."; } @Override 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 2019db8026..2fd3c85f01 100755 --- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationProfile.java +++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationProfile.java @@ -31,7 +31,7 @@ public class RegistrationProfile implements FormAction, FormActionFactory { @Override public String getHelpText() { - return null; + return "Validates email, first name, and last name attributes and stores them in user data."; } @Override 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 b4bb3b0486..df75e4f3c3 100755 --- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationRecaptcha.java +++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationRecaptcha.java @@ -191,7 +191,7 @@ public class RegistrationRecaptcha implements FormAction, FormActionFactory, Con @Override public String getHelpText() { - return null; + return "Adds Google Recaptcha button. Recaptchas verify that the entity that is registering is a human. This can only be used on the internet and must be configured after you add it."; } private static final List configProperties = new ArrayList(); 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 0a446dab15..40d2fb075f 100755 --- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java +++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java @@ -35,7 +35,7 @@ public class RegistrationUserCreation implements FormAction, FormActionFactory { @Override public String getHelpText() { - return null; + return "This action must always be first! Validates the username of the user in validation phase. In success phase, this will create the user in the database."; } @Override 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 41380abf20..b7922134dc 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 @@ -5,15 +5,22 @@ import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.spi.BadRequestException; import org.jboss.resteasy.spi.NotFoundException; import org.keycloak.authentication.AuthenticationFlow; +import org.keycloak.authentication.Authenticator; import org.keycloak.authentication.AuthenticatorUtil; import org.keycloak.authentication.ConfigurableAuthenticatorFactory; +import org.keycloak.authentication.DefaultAuthenticationFlow; +import org.keycloak.authentication.FormAction; +import org.keycloak.authentication.FormAuthenticationFlow; +import org.keycloak.authentication.FormAuthenticator; 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.ConfiguredProvider; import org.keycloak.provider.ProviderConfigProperty; +import org.keycloak.provider.ProviderFactory; import org.keycloak.representations.idm.ConfigPropertyRepresentation; import org.keycloak.utils.CredentialHelper; @@ -68,6 +75,7 @@ public class AuthenticationManagementResource { protected Boolean authenticationFlow; protected String providerId; protected String authenticationConfig; + protected String flowId; protected int level; protected int index; @@ -150,8 +158,59 @@ public class AuthenticationManagementResource { public void setIndex(int index) { this.index = index; } + + public String getFlowId() { + return flowId; + } + + public void setFlowId(String flowId) { + this.flowId = flowId; + } } + @Path("/form-providers") + @GET + @NoCache + @Produces(MediaType.APPLICATION_JSON) + public List> getFormProviders() { + this.auth.requireView(); + List factories = session.getKeycloakSessionFactory().getProviderFactories(FormAuthenticator.class); + return buildProviderMetadata(factories); + } + + @Path("/authenticator-providers") + @GET + @NoCache + @Produces(MediaType.APPLICATION_JSON) + public List> getAuthenticatorProviders() { + this.auth.requireView(); + List factories = session.getKeycloakSessionFactory().getProviderFactories(Authenticator.class); + return buildProviderMetadata(factories); + } + + public List> buildProviderMetadata(List factories) { + List> providers = new LinkedList<>(); + for (ProviderFactory factory : factories) { + Map data = new HashMap<>(); + data.put("id", factory.getId()); + ConfiguredProvider configured = (ConfiguredProvider)factory; + data.put("description", configured.getHelpText()); + providers.add(data); + } + return providers; + } + + @Path("/form-action-providers") + @GET + @NoCache + @Produces(MediaType.APPLICATION_JSON) + public List> getFormActionProviders() { + this.auth.requireView(); + List factories = session.getKeycloakSessionFactory().getProviderFactories(FormAction.class); + return buildProviderMetadata(factories); + } + + @Path("/flows") @GET @NoCache @@ -183,6 +242,36 @@ public class AuthenticationManagementResource { } + @Path("/flows/{id}") + @GET + @NoCache + @Produces(MediaType.APPLICATION_JSON) + public AuthenticationFlowModel getFlow(@PathParam("id") String id) { + this.auth.requireView(); + + AuthenticationFlowModel flow = realm.getAuthenticationFlowById(id); + if (flow == null) { + throw new NotFoundException("Could not find flow with id"); + } + return flow; + } + + @Path("/flows/{id}") + @DELETE + @NoCache + public void deleteFlow(@PathParam("id") String id) { + this.auth.requireView(); + + AuthenticationFlowModel flow = realm.getAuthenticationFlowById(id); + if (flow == null) { + throw new NotFoundException("Could not find flow with id"); + } + if (flow.isBuiltIn()) { + throw new BadRequestException("Can't delete built in flow"); + } + realm.removeAuthenticationFlow(flow); + } + @Path("/flows/{flowAlias}/copy") @POST @NoCache @@ -233,6 +322,65 @@ public class AuthenticationManagementResource { } } + @Path("/flows/{flowAlias}/executions/flow") + @POST + @NoCache + @Consumes(MediaType.APPLICATION_JSON) + public void addExecutionFlow(@PathParam("flowAlias") String flowAlias, Map data) { + this.auth.requireManage(); + + AuthenticationFlowModel parentFlow = realm.getFlowByAlias(flowAlias); + if (parentFlow == null) { + throw new BadRequestException("Parent flow doesn't exists"); + } + String alias = data.get("alias"); + String type = data.get("type"); + String provider = data.get("provider"); + String description = data.get("description"); + + + AuthenticationFlowModel newFlow = realm.getFlowByAlias(alias); + if (newFlow != null) { + throw new BadRequestException("New flow alias name already exists"); + } + newFlow = new AuthenticationFlowModel(); + newFlow.setAlias(alias); + newFlow.setDescription(description); + newFlow.setProviderId(type); + newFlow = realm.addAuthenticationFlow(newFlow); + AuthenticationExecutionModel execution = new AuthenticationExecutionModel(); + execution.setParentFlow(parentFlow.getId()); + execution.setFlowId(newFlow.getId()); + execution.setRequirement(AuthenticationExecutionModel.Requirement.DISABLED); + execution.setAuthenticatorFlow(true); + execution.setAuthenticator(provider); + realm.addAuthenticatorExecution(execution); + } + + @Path("/flows/{flowAlias}/executions/execution") + @POST + @NoCache + @Consumes(MediaType.APPLICATION_JSON) + public void addExecution(@PathParam("flowAlias") String flowAlias, Map data) { + this.auth.requireManage(); + + AuthenticationFlowModel parentFlow = realm.getFlowByAlias(flowAlias); + if (parentFlow == null) { + throw new BadRequestException("Parent flow doesn't exists"); + } + String provider = data.get("provider"); + + + AuthenticationExecutionModel execution = new AuthenticationExecutionModel(); + execution.setParentFlow(parentFlow.getId()); + execution.setRequirement(AuthenticationExecutionModel.Requirement.DISABLED); + execution.setAuthenticatorFlow(false); + execution.setAuthenticator(provider); + realm.addAuthenticatorExecution(execution); + } + + + @Path("/flows/{flowAlias}/executions") @GET @NoCache @@ -278,6 +426,7 @@ public class AuthenticationManagementResource { rep.setId(execution.getId()); rep.setAuthenticationFlow(execution.isAuthenticatorFlow()); rep.setRequirement(execution.getRequirement().name()); + rep.setFlowId(execution.getFlowId()); result.add(rep); AuthenticationFlowModel subFlow = realm.getAuthenticationFlowById(execution.getFlowId()); recurseExecutions(subFlow, result, level + 1);
+ +   
- + @@ -24,15 +25,15 @@
Auth TypeRequirementActionsRequirement
{{execution.displayName|capitalize}} - - - - - - - - - + +