keycloak-aplcache
Changes
forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js 24(+20 -4)
forms/common-themes/src/main/resources/theme/base/admin/resources/partials/authentication-flows.html 2(+1 -1)
forms/common-themes/src/main/resources/theme/base/admin/resources/partials/required-actions.html 19(+19 -0)
forms/common-themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html 2(+1 -1)
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java 6(+6 -0)
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java 6(+6 -0)
model/jpa/src/main/java/org/keycloak/models/jpa/entities/RequiredActionProviderEntity.java 11(+11 -0)
Details
diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.4.0.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.4.0.xml
index 460eac1..fa92731 100755
--- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.4.0.xml
+++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.4.0.xml
@@ -77,6 +77,7 @@
<constraints nullable="false"/>
</column>
<column name="ALIAS" type="VARCHAR(255)"/>
+ <column name="NAME" type="VARCHAR(255)"/>
<column name="REALM_ID" type="VARCHAR(36)"/>
<column name="ENABLED" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
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 f235700..61859e7 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
@@ -1611,13 +1611,28 @@ module.controller('AuthenticationFlowsCtrl', function($scope, realm, Authenticat
});
module.controller('RequiredActionsCtrl', function($scope, realm, RequiredActions, Notifications, Dialog, $location) {
+ console.log('RequiredActionsCtrl');
$scope.realm = realm;
+ $scope.requiredActions = [];
+ var setupRequiredActionsForm = function() {
+ console.log('setupRequiredActionsForm');
+ RequiredActions.query({id: realm.realm}, function(data) {
+ $scope.requiredActions = [];
+ for (var i = 0; i < data.length; i++) {
+ $scope.requiredActions.push(data[i]);
+ }
+ });
+ };
+ $scope.updateRequiredAction = function(action) {
+ RequiredActions.update({realm: realm.realm, alias: action.alias}, action, function() {
+ Notifications.success("Auth requirement updated");
+ setupForm();
+ setupRequiredActionsForm();
+ });
+ }
-});
-
-module.controller('DefaultRequiredActionsCtrl', function($scope, realm, RequiredActions, Notifications, Dialog, $location) {
- $scope.realm = realm;
+ setupRequiredActionsForm();
});
@@ -1627,3 +1642,4 @@ module.controller('DefaultRequiredActionsCtrl', function($scope, realm, Required
+
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
index a2573cb..09b0fb9 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
@@ -228,8 +228,8 @@ module.controller('UserDetailCtrl', function($scope, realm, user, User, UserFede
RequiredActions.query({id: realm.realm}, function(data) {
$scope.userReqActionList = [];
for (var i = 0; i < data.length; i++) {
- console.log("listed required action: " + data[i].text);
- item = { id: data[i].id, text: data[i].text };
+ console.log("listed required action: " + data[i].name);
+ item = data[i];
$scope.userReqActionList.push(item);
}
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 3a492bb..5ebc0a5 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
@@ -63,6 +63,14 @@ module.factory('UserListLoader', function(Loader, User, $route, $q) {
});
});
+module.factory('RequiredActionsListLoader', function(Loader, RequiredActions, $route, $q) {
+ return Loader.query(RequiredActions, function() {
+ return {
+ realm : $route.current.params.realm
+ }
+ });
+});
+
module.factory('RealmSessionStatsLoader', function(Loader, RealmSessionStats, $route, $q) {
return Loader.get(RealmSessionStats, 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 fa31158..8b641c1 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
@@ -187,8 +187,13 @@ module.factory('RealmAdminEvents', function($resource) {
});
module.factory('RequiredActions', function($resource) {
- return $resource(authUrl + '/admin/realms/:id/required-actions', {
- id : '@realm'
+ return $resource(authUrl + '/admin/realms/:id/authentication/required-actions/:alias', {
+ realm : '@realm',
+ alias : '@alias'
+ }, {
+ update : {
+ method : 'PUT'
+ }
});
});
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 0c83cdf..cfc4f89 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
@@ -27,7 +27,7 @@
</tr>
</thead>
<tbody>
- <tr ng-repeat="execution in executions">
+ <tr ng-repeat="execution in executions" data-ng-show="executions.length > 0">
<td ng-show="execution.subFlow"></td>
<td><h2>{{execution.referenceType}}</h2></td>
<td ng-hide="execution.subFlow"></td>
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/required-actions.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/required-actions.html
index bf891c6..ab49b59 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/required-actions.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/required-actions.html
@@ -2,6 +2,25 @@
<h1>Authentication</h1>
<kc-tabs-authentication></kc-tabs-authentication>
+ <table class="table table-striped table-bordered">
+ <thead>
+ <tr data-ng-hide="requiredActions.length == 0">
+ <th>Required Action</th>
+ <th>Enabled</th>
+ <th>Default Action</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr ng-repeat="requiredAction in requiredActions" data-ng-show="requiredActions.length > 0">
+ <td>{{requiredAction.name}}</td>
+ <td>{{requiredAction.enabled}}</td>
+ <td>{{requiredAction.defaultAction}}</td>
+ </tr>
+ <tr data-ng-show="requiredActions.length == 0">
+ <td>No required actions configured</td>
+ </tr>
+ </tbody>
+ </table>
</div>
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html
index 09a3fc4..9c851ee 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html
@@ -80,7 +80,7 @@
<div class="col-md-6">
<select ui-select2 id="reqActions" ng-model="user.requiredActions" data-placeholder="Select an action..." multiple>
- <option ng-repeat="action in userReqActionList" value="{{action.id}}">{{action.text}}</option>
+ <option ng-repeat="action in userReqActionList" value="{{action.alias}}">{{action.name}}</option>
</select>
</div>
<kc-tooltip>Require an action when the user logs in. 'Verify email' sends an email to the user to verify their email address. 'Update profile' requires user to enter in new personal information. 'Update password' requires user to enter in a new password. 'Configure TOTP' requires setup of a mobile password generator.</kc-tooltip>
diff --git a/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_3_0.java b/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_3_0.java
index 1b68528..43209a8 100755
--- a/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_3_0.java
+++ b/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_3_0.java
@@ -10,6 +10,7 @@ import org.keycloak.models.UserFederationProvider;
import org.keycloak.models.UserFederationProviderFactory;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.utils.DefaultAuthenticationFlows;
+import org.keycloak.models.utils.DefaultRequiredActions;
import java.util.List;
import java.util.Map;
@@ -28,10 +29,6 @@ public class MigrateTo1_3_0 {
public void migrate(KeycloakSession session) {
List<RealmModel> realms = session.realms().getRealms();
for (RealmModel realm : realms) {
- if (realm.getAuthenticationFlows().size() == 0) {
- DefaultAuthenticationFlows.addFlows(realm);
- }
-
migrateLDAPProviders(session, realm);
}
diff --git a/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_4_0.java b/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_4_0.java
index cc15d00..0b7e8f8 100755
--- a/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_4_0.java
+++ b/model/api/src/main/java/org/keycloak/migration/migrators/MigrateTo1_4_0.java
@@ -4,6 +4,7 @@ import org.keycloak.migration.ModelVersion;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.DefaultAuthenticationFlows;
+import org.keycloak.models.utils.DefaultRequiredActions;
import java.util.List;
@@ -20,6 +21,7 @@ public class MigrateTo1_4_0 {
for (RealmModel realm : realms) {
if (realm.getAuthenticationFlows().size() == 0) {
DefaultAuthenticationFlows.addFlows(realm);
+ DefaultRequiredActions.addActions(realm);
}
}
diff --git a/model/api/src/main/java/org/keycloak/models/entities/RequiredActionProviderEntity.java b/model/api/src/main/java/org/keycloak/models/entities/RequiredActionProviderEntity.java
index 3aff7a9..30fcf3e 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/RequiredActionProviderEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/RequiredActionProviderEntity.java
@@ -9,6 +9,7 @@ import java.util.Map;
public class RequiredActionProviderEntity {
protected String id;
protected String alias;
+ protected String name;
protected String providerId;
protected boolean enabled;
protected boolean defaultAction;
@@ -30,6 +31,14 @@ public class RequiredActionProviderEntity {
this.alias = alias;
}
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
public boolean isEnabled() {
return enabled;
}
diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java
index 48c2b16..8aaec24 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java
@@ -204,6 +204,7 @@ public interface RealmModel extends RoleContainerModel {
void updateRequiredActionProvider(RequiredActionProviderModel model);
void removeRequiredActionProvider(RequiredActionProviderModel model);
RequiredActionProviderModel getRequiredActionProviderById(String id);
+ RequiredActionProviderModel getRequiredActionProviderByAlias(String alias);
List<IdentityProviderModel> getIdentityProviders();
IdentityProviderModel getIdentityProviderByAlias(String alias);
diff --git a/model/api/src/main/java/org/keycloak/models/RequiredActionProviderModel.java b/model/api/src/main/java/org/keycloak/models/RequiredActionProviderModel.java
index f7d304e..a32a23c 100755
--- a/model/api/src/main/java/org/keycloak/models/RequiredActionProviderModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RequiredActionProviderModel.java
@@ -11,6 +11,7 @@ public class RequiredActionProviderModel {
private String id;
private String alias;
+ private String name;
private String providerId;
private boolean enabled;
private boolean defaultAction;
@@ -33,6 +34,20 @@ public class RequiredActionProviderModel {
this.alias = alias;
}
+ /**
+ * Used for display purposes. Probably should clean this code up and make alias and name the same, but
+ * the old code references an Enum and the admin console creates a "friendly" name for each enum.
+ *
+ * @return
+ */
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
public boolean isEnabled() {
return enabled;
}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/DefaultRequiredActions.java b/model/api/src/main/java/org/keycloak/models/utils/DefaultRequiredActions.java
new file mode 100755
index 0000000..ab5468c
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/utils/DefaultRequiredActions.java
@@ -0,0 +1,69 @@
+package org.keycloak.models.utils;
+
+import org.keycloak.models.AuthenticationExecutionModel;
+import org.keycloak.models.AuthenticationFlowModel;
+import org.keycloak.models.AuthenticatorModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RequiredActionProviderModel;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class DefaultRequiredActions {
+ public static void addActions(RealmModel realm) {
+ if (realm.getRequiredActionProviderByAlias(UserModel.RequiredAction.VERIFY_EMAIL.name()) == null) {
+ RequiredActionProviderModel verifyEmail = new RequiredActionProviderModel();
+ verifyEmail.setEnabled(true);
+ verifyEmail.setAlias(UserModel.RequiredAction.VERIFY_EMAIL.name());
+ verifyEmail.setName("Verify Email");
+ verifyEmail.setProviderId(UserModel.RequiredAction.VERIFY_EMAIL.name());
+ verifyEmail.setDefaultAction(false);
+ realm.addRequiredActionProvider(verifyEmail);
+
+ }
+
+ if (realm.getRequiredActionProviderByAlias(UserModel.RequiredAction.UPDATE_PROFILE.name()) == null) {
+ RequiredActionProviderModel updateProfile = new RequiredActionProviderModel();
+ updateProfile.setEnabled(true);
+ updateProfile.setAlias(UserModel.RequiredAction.UPDATE_PROFILE.name());
+ updateProfile.setName("Update Profile");
+ updateProfile.setProviderId(UserModel.RequiredAction.UPDATE_PROFILE.name());
+ updateProfile.setDefaultAction(false);
+ realm.addRequiredActionProvider(updateProfile);
+ }
+
+ if (realm.getRequiredActionProviderByAlias(UserModel.RequiredAction.CONFIGURE_TOTP.name()) == null) {
+ RequiredActionProviderModel totp = new RequiredActionProviderModel();
+ totp.setEnabled(true);
+ totp.setAlias(UserModel.RequiredAction.CONFIGURE_TOTP.name());
+ totp.setName("Configure Totp");
+ totp.setProviderId(UserModel.RequiredAction.CONFIGURE_TOTP.name());
+ totp.setDefaultAction(false);
+ realm.addRequiredActionProvider(totp);
+ }
+
+ if (realm.getRequiredActionProviderByAlias(UserModel.RequiredAction.UPDATE_PASSWORD.name()) == null) {
+ RequiredActionProviderModel updatePassword = new RequiredActionProviderModel();
+ updatePassword.setEnabled(true);
+ updatePassword.setAlias(UserModel.RequiredAction.UPDATE_PASSWORD.name());
+ updatePassword.setName("Update Password");
+ updatePassword.setProviderId(UserModel.RequiredAction.UPDATE_PASSWORD.name());
+ updatePassword.setDefaultAction(false);
+ realm.addRequiredActionProvider(updatePassword);
+ }
+
+ if (realm.getRequiredActionProviderByAlias("terms_and_conditions") == null) {
+ RequiredActionProviderModel termsAndConditions = new RequiredActionProviderModel();
+ termsAndConditions.setEnabled(false);
+ termsAndConditions.setAlias("terms_and_conditions");
+ termsAndConditions.setName("Terms and Conditions");
+ termsAndConditions.setProviderId("terms_and_conditions");
+ termsAndConditions.setDefaultAction(false);
+ realm.addRequiredActionProvider(termsAndConditions);
+ }
+
+
+ }
+}
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 9e6f286..c5b49d0 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
@@ -1449,6 +1449,7 @@ public class RealmAdapter implements RealmModel {
RequiredActionProviderEntity auth = new RequiredActionProviderEntity();
auth.setId(KeycloakModelUtils.generateId());
auth.setAlias(model.getAlias());
+ auth.setName(model.getName());
auth.setProviderId(model.getProviderId());
auth.setConfig(model.getConfig());
auth.setEnabled(model.isEnabled());
@@ -1477,6 +1478,7 @@ public class RealmAdapter implements RealmModel {
model.setId(entity.getId());
model.setProviderId(entity.getProviderId());
model.setAlias(entity.getAlias());
+ model.setName(entity.getName());
model.setEnabled(entity.isEnabled());
model.setDefaultAction(entity.isDefaultAction());
Map<String, String> config = new HashMap<>();
@@ -1492,6 +1494,7 @@ public class RealmAdapter implements RealmModel {
entity.setAlias(model.getAlias());
entity.setProviderId(model.getProviderId());
entity.setEnabled(model.isEnabled());
+ entity.setName(model.getName());
entity.setDefaultAction(model.isDefaultAction());
if (entity.getConfig() == null) {
entity.setConfig(model.getConfig());
@@ -1521,6 +1524,15 @@ public class RealmAdapter implements RealmModel {
return entity;
}
+ @Override
+ public RequiredActionProviderModel getRequiredActionProviderByAlias(String alias) {
+ for (RequiredActionProviderModel action : getRequiredActionProviders()) {
+ if (action.getAlias().equals(alias)) return action;
+ }
+ return null;
+ }
+
+
@Override
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 331b020..acaea88 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
@@ -83,6 +83,7 @@ public class CachedRealm {
private Map<String, AuthenticationFlowModel> authenticationFlows = new HashMap<>();
private Map<String, AuthenticatorModel> authenticators = new HashMap<>();
private Map<String, RequiredActionProviderModel> requiredActionProviders = new HashMap<>();
+ private Map<String, RequiredActionProviderModel> requiredActionProvidersByAlias = new HashMap<>();
private MultivaluedHashMap<String, AuthenticationExecutionModel> authenticationExecutions = new MultivaluedHashMap<>();
private Map<String, AuthenticationExecutionModel> executionsById = new HashMap<>();
@@ -204,6 +205,7 @@ public class CachedRealm {
}
for (RequiredActionProviderModel action : model.getRequiredActionProviders()) {
requiredActionProviders.put(action.getId(), action);
+ requiredActionProvidersByAlias.put(action.getAlias(), action);
}
}
@@ -447,4 +449,8 @@ public class CachedRealm {
public Map<String, RequiredActionProviderModel> getRequiredActionProviders() {
return requiredActionProviders;
}
+
+ public Map<String, RequiredActionProviderModel> getRequiredActionProvidersByAlias() {
+ return requiredActionProvidersByAlias;
+ }
}
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 f21d120..cf1bcb1 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
@@ -1161,4 +1161,10 @@ public class RealmAdapter implements RealmModel {
if (updated != null) return updated.getRequiredActionProviderById(id);
return cached.getRequiredActionProviders().get(id);
}
+
+ @Override
+ public RequiredActionProviderModel getRequiredActionProviderByAlias(String alias) {
+ if (updated != null) return updated.getRequiredActionProviderByAlias(alias);
+ return cached.getRequiredActionProvidersByAlias().get(alias);
+ }
}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RequiredActionProviderEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RequiredActionProviderEntity.java
index 103f76b..4c5ecdd 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RequiredActionProviderEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RequiredActionProviderEntity.java
@@ -30,6 +30,9 @@ public class RequiredActionProviderEntity {
@Column(name="ALIAS")
protected String alias;
+ @Column(name="NAME")
+ protected String name;
+
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "REALM_ID")
protected RealmEntity realm;
@@ -104,4 +107,12 @@ public class RequiredActionProviderEntity {
public void setConfig(Map<String, String> config) {
this.config = config;
}
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
}
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 eb7eec3..5c62dcd 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
@@ -1732,6 +1732,7 @@ public class RealmAdapter implements RealmModel {
RequiredActionProviderEntity auth = new RequiredActionProviderEntity();
auth.setId(KeycloakModelUtils.generateId());
auth.setAlias(model.getAlias());
+ auth.setName(model.getName());
auth.setRealm(realm);
auth.setProviderId(model.getProviderId());
auth.setConfig(model.getConfig());
@@ -1767,6 +1768,7 @@ public class RealmAdapter implements RealmModel {
model.setAlias(entity.getAlias());
model.setEnabled(entity.isEnabled());
model.setDefaultAction(entity.isDefaultAction());
+ model.setName(entity.getName());
Map<String, String> config = new HashMap<>();
if (entity.getConfig() != null) config.putAll(entity.getConfig());
model.setConfig(config);
@@ -1781,6 +1783,7 @@ public class RealmAdapter implements RealmModel {
entity.setProviderId(model.getProviderId());
entity.setEnabled(model.isEnabled());
entity.setDefaultAction(model.isDefaultAction());
+ entity.setName(model.getName());
if (entity.getConfig() == null) {
entity.setConfig(model.getConfig());
} else {
@@ -1799,4 +1802,12 @@ public class RealmAdapter implements RealmModel {
}
return actions;
}
+
+ @Override
+ public RequiredActionProviderModel getRequiredActionProviderByAlias(String alias) {
+ for (RequiredActionProviderModel action : getRequiredActionProviders()) {
+ if (action.getAlias().equals(alias)) return action;
+ }
+ return null;
+ }
}
\ No newline at end of file
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 b9f1ec8..bf1627f 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
@@ -1607,6 +1607,15 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
return entity;
}
+ @Override
+ public RequiredActionProviderModel getRequiredActionProviderByAlias(String alias) {
+ for (RequiredActionProviderModel action : getRequiredActionProviders()) {
+ if (action.getAlias().equals(alias)) return action;
+ }
+ return null;
+ }
+
+
diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index 56aface..9695a4e 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -17,6 +17,7 @@ import org.keycloak.jose.jws.JWSBuilder;
import org.keycloak.login.LoginFormsProvider;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.RequiredActionProviderModel;
import org.keycloak.models.UserConsentModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
@@ -483,8 +484,9 @@ public class AuthenticationManager {
};
// see if any required actions need triggering, i.e. an expired password
- for (ProviderFactory factory : session.getKeycloakSessionFactory().getProviderFactories(RequiredActionProvider.class)) {
- RequiredActionProvider provider = ((RequiredActionFactory)factory).create(session);
+ for (RequiredActionProviderModel model : realm.getRequiredActionProviders()) {
+ if (!model.isEnabled()) continue;
+ RequiredActionProvider provider = session.getProvider(RequiredActionProvider.class, model.getProviderId());
provider.evaluateTriggers(context);
}
@@ -495,7 +497,8 @@ public class AuthenticationManager {
Set<String> requiredActions = user.getRequiredActions();
for (String action : requiredActions) {
- RequiredActionProvider actionProvider = session.getProvider(RequiredActionProvider.class, action);
+ RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(action);
+ RequiredActionProvider actionProvider = session.getProvider(RequiredActionProvider.class, model.getProviderId());
Response challenge = actionProvider.invokeRequiredAction(context);
if (challenge != null) {
return challenge;
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
index 41f5ac6..99b893c 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -17,6 +17,7 @@ import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.utils.DefaultAuthenticationFlows;
+import org.keycloak.models.utils.DefaultRequiredActions;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.ClientRepresentation;
@@ -88,6 +89,7 @@ public class RealmManager {
setupBrokerService(realm);
setupAdminConsole(realm);
setupAuthenticationFlows(realm);
+ setupRequiredActions(realm);
return realm;
}
@@ -96,6 +98,10 @@ public class RealmManager {
if (realm.getAuthenticationFlows().size() == 0) DefaultAuthenticationFlows.addFlows(realm);
}
+ protected void setupRequiredActions(RealmModel realm) {
+ if (realm.getRequiredActionProviders().size() == 0) DefaultRequiredActions.addActions(realm);
+ }
+
protected void setupAdminConsole(RealmModel realm) {
ClientModel adminConsole = realm.getClientByClientId(Constants.ADMIN_CONSOLE_CLIENT_ID);
if (adminConsole == null) adminConsole = new ClientManager(this).createClient(realm, Constants.ADMIN_CONSOLE_CLIENT_ID);
@@ -261,6 +267,7 @@ public class RealmManager {
RepresentationToModel.importRealm(session, rep, realm);
setupAuthenticationFlows(realm);
+ setupRequiredActions(realm);
// Refresh periodic sync tasks for configured federationProviders
List<UserFederationProviderModel> federationProviders = realm.getUserFederationProviders();
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 3380731..ebab2ae 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
@@ -6,13 +6,18 @@ import org.jboss.resteasy.spi.NotFoundException;
import org.keycloak.authentication.Authenticator;
import org.keycloak.authentication.AuthenticatorFactory;
import org.keycloak.authentication.AuthenticatorUtil;
+import org.keycloak.authentication.RequiredActionFactory;
+import org.keycloak.authentication.RequiredActionProvider;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.AuthenticationFlowModel;
import org.keycloak.models.AuthenticatorModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
+import org.keycloak.models.RequiredActionProviderModel;
+import org.keycloak.provider.ProviderFactory;
import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
@@ -20,8 +25,10 @@ import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import static javax.ws.rs.core.Response.Status.NOT_FOUND;
@@ -176,4 +183,118 @@ public class AuthenticationManagementResource {
realm.updateAuthenticatorExecution(model);
}
}
+
+ public static class RequiredActionProviderRepresentation {
+ private String alias;
+ private String name;
+ private boolean enabled;
+ private boolean defaultAction;
+ private Map<String, String> config = new HashMap<String, String>();
+
+ public String getAlias() {
+ return alias;
+ }
+
+ public void setAlias(String alias) {
+ this.alias = alias;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public boolean isDefaultAction() {
+ return defaultAction;
+ }
+
+ public void setDefaultAction(boolean defaultAction) {
+ this.defaultAction = defaultAction;
+ }
+
+ public Map<String, String> getConfig() {
+ return config;
+ }
+
+ public void setConfig(Map<String, String> config) {
+ this.config = config;
+ }
+ }
+
+
+ @Path("required-actions")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public List<RequiredActionProviderRepresentation> getRequiredActions() {
+ List<RequiredActionProviderRepresentation> list = new LinkedList<>();
+ for (RequiredActionProviderModel model : realm.getRequiredActionProviders()) {
+ RequiredActionProviderRepresentation rep = toRepresentation(model);
+ list.add(rep);
+ }
+ return list;
+ }
+
+ public static RequiredActionProviderRepresentation toRepresentation(RequiredActionProviderModel model) {
+ RequiredActionProviderRepresentation rep = new RequiredActionProviderRepresentation();
+ rep.setAlias(model.getAlias());
+ rep.setName(model.getName());
+ rep.setDefaultAction(model.isDefaultAction());
+ rep.setEnabled(model.isEnabled());
+ rep.setConfig(model.getConfig());
+ return rep;
+ }
+
+ @Path("required-actions/{alias}")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public RequiredActionProviderRepresentation getRequiredAction(@PathParam("alias") String alias) {
+ RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias);
+ if (model == null) {
+ throw new NotFoundException("Failed to find required action: " + alias);
+ }
+ return toRepresentation(model);
+ }
+
+
+ @Path("required-actions/{alias}")
+ @PUT
+ @Consumes(MediaType.APPLICATION_JSON)
+ public void updateRequiredAction(@PathParam("alias") String alias, RequiredActionProviderRepresentation rep) {
+ RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias);
+ if (model == null) {
+ throw new NotFoundException("Failed to find required action: " + alias);
+ }
+ RequiredActionProviderModel update = new RequiredActionProviderModel();
+ update.setId(update.getId());
+ update.setName(rep.getName());
+ update.setAlias(rep.getAlias());
+ update.setProviderId(model.getProviderId());
+ update.setDefaultAction(rep.isDefaultAction());
+ update.setEnabled(rep.isEnabled());
+ update.setConfig(rep.getConfig());
+ realm.updateRequiredActionProvider(update);
+ }
+
+ @Path("required-actions/{alias}")
+ @DELETE
+ public void updateRequiredAction(@PathParam("alias") String alias) {
+ RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(alias);
+ if (model == null) {
+ throw new NotFoundException("Failed to find required action: " + alias);
+ }
+ realm.removeRequiredActionProvider(model);
+ }
+
+
}
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index 1853698..5280a97 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -565,18 +565,4 @@ public class RealmAdminResource {
return new IdentityProvidersResource(realm, session, this.auth, adminEvent);
}
- @Path("required-actions")
- @GET
- @Produces(MediaType.APPLICATION_JSON)
- public List<Map<String, String>> getRequiredActions() {
- List<Map<String, String>> list = new LinkedList<>();
- for (ProviderFactory factory : session.getKeycloakSessionFactory().getProviderFactories(RequiredActionProvider.class)) {
- RequiredActionFactory actionFactory = (RequiredActionFactory)factory;
- Map<String, String> data = new HashMap<>();
- data.put("id", actionFactory.getId());
- data.put("text", actionFactory.getDisplayText());
- list.add(data);
- }
- return list;
- }
}