From 4ca442d1b20269dd1e733f7672016895d1f51ba3 Mon Sep 17 00:00:00 2001 From: mposolda Date: Mon, 9 Nov 2015 22:09:37 +0100 Subject: [PATCH] KEYCLOAK-1750 Option updateProfileOnFirstLogin moved from IdentityProvider to IdpReviewProfile authenticator --- .../META-INF/jpa-changelog-1.7.0.xml | 1 + .../idm/IdentityProviderRepresentation.java | 7 +- .../modules/MigrationFromOlderVersions.xml | 30 ++++- .../theme/base/admin/resources/js/app.js | 10 +- .../admin/resources/js/controllers/realm.js | 23 ++-- .../partials/authentication-flows.html | 4 +- .../partials/authenticator-config.html | 1 + .../realm-identity-provider-oidc.html | 15 +-- .../realm-identity-provider-saml.html | 13 --- .../realm-identity-provider-social.html | 15 +-- .../base/login/login-idp-link-confirm.ftl | 2 +- .../login/messages/messages_en.properties | 2 +- .../models/IdentityProviderModel.java | 23 ---- .../entities/IdentityProviderEntity.java | 9 -- .../utils/DefaultAuthenticationFlows.java | 28 ++++- .../models/utils/ModelToRepresentation.java | 1 - .../models/utils/RepresentationToModel.java | 1 - .../org/keycloak/models/jpa/RealmAdapter.java | 3 - .../jpa/entities/IdentityProviderEntity.java | 11 -- .../mongo/keycloak/adapters/RealmAdapter.java | 3 - ...ava => IdpReviewProfileAuthenticator.java} | 18 ++- .../IdpReviewProfileAuthenticatorFactory.java | 107 ++++++++++++++++++ .../IdpUpdateProfileAuthenticatorFactory.java | 84 -------------- ...ycloak.authentication.AuthenticatorFactory | 2 +- .../testsuite/admin/IdentityProviderTest.java | 1 - .../broker/AbstractIdentityProviderTest.java | 44 +++++-- .../broker/ImportIdentityProviderTest.java | 30 ++--- .../broker-test/test-realm-with-broker.json | 11 -- 28 files changed, 240 insertions(+), 259 deletions(-) rename services/src/main/java/org/keycloak/authentication/authenticators/broker/{IdpUpdateProfileAuthenticator.java => IdpReviewProfileAuthenticator.java} (83%) create mode 100644 services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticatorFactory.java delete mode 100644 services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpUpdateProfileAuthenticatorFactory.java diff --git a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.7.0.xml b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.7.0.xml index 4f7d5fcd9f..c5d7d5252d 100644 --- a/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.7.0.xml +++ b/connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.7.0.xml @@ -7,6 +7,7 @@ + \ No newline at end of file diff --git a/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java index 864d255dc0..0dc7f0a019 100755 --- a/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java @@ -46,6 +46,7 @@ public class IdentityProviderRepresentation { * @see #UPFLM_MISSING * @see #UPFLM_OFF */ + @Deprecated protected String updateProfileFirstLoginMode = UPFLM_ON; protected boolean trustEmail; @@ -107,15 +108,17 @@ public class IdentityProviderRepresentation { } /** - * @return see {@link #updateProfileFirstLoginMode} + * @deprecated deprecated and replaced by configuration on IdpReviewProfileAuthenticator */ + @Deprecated public String getUpdateProfileFirstLoginMode() { return updateProfileFirstLoginMode; } /** - * @param updateProfileFirstLoginMode see {@link #updateProfileFirstLoginMode} + * @deprecated deprecated and replaced by configuration on IdpReviewProfileAuthenticator */ + @Deprecated public void setUpdateProfileFirstLoginMode(String updateProfileFirstLoginMode) { this.updateProfileFirstLoginMode = updateProfileFirstLoginMode; } diff --git a/docbook/auth-server-docs/reference/en/en-US/modules/MigrationFromOlderVersions.xml b/docbook/auth-server-docs/reference/en/en-US/modules/MigrationFromOlderVersions.xml index 650ed769bd..b0a443dd41 100755 --- a/docbook/auth-server-docs/reference/en/en-US/modules/MigrationFromOlderVersions.xml +++ b/docbook/auth-server-docs/reference/en/en-US/modules/MigrationFromOlderVersions.xml @@ -79,16 +79,34 @@
Version specific migration +
+ Migrating to 1.7.0.CR1 + + Option 'Update Profile On First Login' moved from Identity provider to Review Profile authenticator + + In this version, we added First Broker Login, which allows you to specify what exactly should be done + when new user is logged through Identity provider (or Social provider), but there is no existing Keycloak user + yet linked to the social account. As part of this work, we added option First Login Flow to identity providers where + you can specify the flow and then you can configure this flow under Authentication tab in admin console. + + + We also removed the option Update Profile On First Login from the Identity provider settings and moved it + to the configuration of Review Profile authenticator. So once you specify which flow should be used for your + Identity provider (by default it's First Broker Login flow), you go to Authentication tab, select the flow + and then you configure the option under Review Profile authenticator. + + +
Migrating to 1.6.0.Final - Refresh tokens are not reusable anymore + Option that refresh tokens are not reusable anymore - Old versions of Keycloak allowed reusing refresh tokens multiple times. Keycloak no longer permits - this by default. When a refresh token is used to obtain a new access token a new refresh token is also - included. This new refresh token should be used next time the access token is refreshed. If this is - a problem for you it's possible to enable reuse of refresh tokens in the admin console under token - settings. + Old versions of Keycloak allowed reusing refresh tokens multiple times. Keycloak still permits this, + but also have an option Revoke refresh token to disallow it. Option is in in admin console under token settings. + When a refresh token is used to obtain a new access token a new refresh token is also + included. When option is enabled, then this new refresh token should be used next time the access token is refreshed. + It won't be possible to reuse old refresh token multiple times. 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 96ee94d8aa..7fbbc808e1 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 @@ -1348,12 +1348,15 @@ module.config([ '$routeProvider', function($routeProvider) { }, controller : 'RealmOtpPolicyCtrl' }) - .when('/realms/:realm/authentication/config/:provider/:config', { + .when('/realms/:realm/authentication/flows/:flow/config/:provider/:config', { templateUrl : resourceUrl + '/partials/authenticator-config.html', resolve : { realm : function(RealmLoader) { return RealmLoader(); }, + flow : function(AuthenticationFlowLoader) { + return AuthenticationFlowLoader(); + }, configType : function(AuthenticationConfigDescriptionLoader) { return AuthenticationConfigDescriptionLoader(); }, @@ -1363,12 +1366,15 @@ module.config([ '$routeProvider', function($routeProvider) { }, controller : 'AuthenticationConfigCtrl' }) - .when('/create/authentication/:realm/execution/:executionId/provider/:provider', { + .when('/create/authentication/:realm/flows/:flow/execution/:executionId/provider/:provider', { templateUrl : resourceUrl + '/partials/authenticator-config.html', resolve : { realm : function(RealmLoader) { return RealmLoader(); }, + flow : function(AuthenticationFlowLoader) { + return AuthenticationFlowLoader(); + }, configType : function(AuthenticationConfigDescriptionLoader) { return AuthenticationConfigDescriptionLoader(); }, 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 37ec3abed2..e21b50ef83 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 @@ -599,15 +599,6 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload $scope.realm = angular.copy(realm); - $scope.initProvider = function() { - if (instance && instance.alias) { - - } else { - $scope.identityProvider.updateProfileFirstLoginMode = "on"; - } - - }; - $scope.initSamlProvider = function() { $scope.nameIdFormats = [ /* @@ -658,7 +649,6 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload } else { $scope.identityProvider.config.nameIDPolicyFormat = $scope.nameIdFormats[0].format; $scope.identityProvider.config.signatureAlgorithm = $scope.signatureAlgorithms[1]; - $scope.identityProvider.updateProfileFirstLoginMode = "off"; } } @@ -676,7 +666,6 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload $scope.identityProvider.alias = providerFactory.id; $scope.identityProvider.providerId = providerFactory.id; $scope.identityProvider.enabled = true; - $scope.identityProvider.updateProfileFirstLoginMode = "off"; $scope.identityProvider.authenticateByDefault = false; $scope.identityProvider.firstBrokerLoginFlowAlias = 'first broker login'; $scope.newIdentityProvider = true; @@ -1909,8 +1898,9 @@ module.controller('RequiredActionsCtrl', function($scope, realm, unregisteredReq }); -module.controller('AuthenticationConfigCtrl', function($scope, realm, configType, config, AuthenticationConfig, Notifications, Dialog, $location) { +module.controller('AuthenticationConfigCtrl', function($scope, realm, flow, configType, config, AuthenticationConfig, Notifications, Dialog, $location) { $scope.realm = realm; + $scope.flow = flow; $scope.configType = configType; $scope.create = false; $scope.config = angular.copy(config); @@ -1935,7 +1925,7 @@ module.controller('AuthenticationConfigCtrl', function($scope, realm, configType }, $scope.config, function() { $scope.changed = false; config = angular.copy($scope.config); - $location.url("/realms/" + realm.realm + '/authentication/config/' + configType.providerId + "/" + config.id); + $location.url("/realms/" + realm.realm + '/authentication/flows/' + flow.id + '/config/' + configType.providerId + "/" + config.id); Notifications.success("Your changes have been saved."); }); }; @@ -1954,15 +1944,16 @@ module.controller('AuthenticationConfigCtrl', function($scope, realm, configType Dialog.confirmDelete($scope.config.alias, 'config', function() { AuthenticationConfig.remove({ realm: realm.realm, config : $scope.config.id }, function() { Notifications.success("The config has been deleted."); - $location.url("/realms/" + realm.realm + '/authentication/flows'); + $location.url("/realms/" + realm.realm + '/authentication/flows/' + flow.id); }); }); }; }); -module.controller('AuthenticationConfigCreateCtrl', function($scope, realm, configType, execution, AuthenticationExecutionConfig, Notifications, Dialog, $location) { +module.controller('AuthenticationConfigCreateCtrl', function($scope, realm, flow, configType, execution, AuthenticationExecutionConfig, Notifications, Dialog, $location) { $scope.realm = realm; + $scope.flow = flow; $scope.create = true; $scope.config = { config: {}}; $scope.configType = configType; @@ -1980,7 +1971,7 @@ module.controller('AuthenticationConfigCreateCtrl', function($scope, realm, conf }, $scope.config, function(data, headers) { var l = headers().location; var id = l.substring(l.lastIndexOf("/") + 1); - var url = "/realms/" + realm.realm + '/authentication/config/' + configType.providerId + "/" + id; + var url = "/realms/" + realm.realm + '/authentication/flows/' + flow.id + '/config/' + configType.providerId + "/" + id; console.log('redirect url: ' + url); $location.url(url); Notifications.success("Config has been created."); 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 e055978bd6..a77cf9f64d 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 @@ -53,8 +53,8 @@
  • Delete
  • Add Execution
  • Add Flow
  • -
  • Config
  • -
  • Config
  • +
  • Config
  • +
  • Config
  • diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/authenticator-config.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/authenticator-config.html index 585680616b..f5875683e7 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/authenticator-config.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/authenticator-config.html @@ -2,6 +2,7 @@ diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html index 317709eac2..4cbd12a09f 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html @@ -1,4 +1,4 @@ -
    +
    {{:: 'identity-provider.stored-tokens-readable.tooltip' | translate}}
    -
    - -
    -
    - -
    -
    - {{:: 'update-profile-on-first-login.tooltip' | translate}} -
    diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html index 53cbf3a159..c8f6c3771a 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html @@ -52,19 +52,6 @@
    {{:: 'identity-provider.stored-tokens-readable.tooltip' | translate}}
    -
    - -
    -
    - -
    -
    - {{:: 'update-profile-on-first-login.tooltip' | translate}} -
    diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html index a4e3f1331b..5897f9972b 100755 --- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html +++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html @@ -1,4 +1,4 @@ -
    +
    {{:: 'identity-provider.enabled.tooltip' | translate}}
    -
    - -
    -
    - -
    -
    - {{:: 'update-profile-on-first-login.tooltip' | translate}} -
    diff --git a/forms/common-themes/src/main/resources/theme/base/login/login-idp-link-confirm.ftl b/forms/common-themes/src/main/resources/theme/base/login/login-idp-link-confirm.ftl index 28b12d0789..02923d97b5 100644 --- a/forms/common-themes/src/main/resources/theme/base/login/login-idp-link-confirm.ftl +++ b/forms/common-themes/src/main/resources/theme/base/login/login-idp-link-confirm.ftl @@ -12,7 +12,7 @@
    - +
    diff --git a/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties b/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties index ca18e21f7d..803ef2dcc0 100644 --- a/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties +++ b/forms/common-themes/src/main/resources/theme/base/login/messages/messages_en.properties @@ -142,7 +142,7 @@ federatedIdentityExistsMessage=User with {0} {1} already exists. Please login to confirmLinkIdpTitle=Account already exists federatedIdentityConfirmLinkMessage=User with {0} {1} already exists. How do you want to continue? federatedIdentityConfirmReauthenticateMessage=Authenticate as {0} to link your account with {1} -confirmLinkIdpUpdateProfile=Update profile info +confirmLinkIdpReviewProfile=Review profile info confirmLinkIdpContinue=Link {0} with existing account configureTotpMessage=You need to set up Mobile Authenticator to activate your account. diff --git a/model/api/src/main/java/org/keycloak/models/IdentityProviderModel.java b/model/api/src/main/java/org/keycloak/models/IdentityProviderModel.java index 288b1f0369..862f7239a9 100755 --- a/model/api/src/main/java/org/keycloak/models/IdentityProviderModel.java +++ b/model/api/src/main/java/org/keycloak/models/IdentityProviderModel.java @@ -45,14 +45,6 @@ public class IdentityProviderModel implements Serializable { private String providerId; private boolean enabled; - - /** - * For possible values see {@link IdentityProviderRepresentation#getUpdateProfileFirstLoginMode()} - * @see IdentityProviderRepresentation#UPFLM_ON - * @see IdentityProviderRepresentation#UPFLM_MISSING - * @see IdentityProviderRepresentation#UPFLM_OFF - */ - protected String updateProfileFirstLoginMode = IdentityProviderRepresentation.UPFLM_ON; private boolean trustEmail; @@ -81,7 +73,6 @@ public class IdentityProviderModel implements Serializable { this.alias = model.getAlias(); this.config = new HashMap(model.getConfig()); this.enabled = model.isEnabled(); - this.updateProfileFirstLoginMode = model.getUpdateProfileFirstLoginMode(); this.trustEmail = model.isTrustEmail(); this.storeToken = model.isStoreToken(); this.authenticateByDefault = model.isAuthenticateByDefault(); @@ -121,20 +112,6 @@ public class IdentityProviderModel implements Serializable { this.enabled = enabled; } - /** - * @see IdentityProviderRepresentation#getUpdateProfileFirstLoginMode() - */ - public String getUpdateProfileFirstLoginMode() { - return updateProfileFirstLoginMode; - } - - /** - * @see IdentityProviderRepresentation#setUpdateProfileFirstLoginMode(String) - */ - public void setUpdateProfileFirstLoginMode(String updateProfileFirstLoginMode) { - this.updateProfileFirstLoginMode = updateProfileFirstLoginMode; - } - public boolean isStoreToken() { return this.storeToken; } diff --git a/model/api/src/main/java/org/keycloak/models/entities/IdentityProviderEntity.java b/model/api/src/main/java/org/keycloak/models/entities/IdentityProviderEntity.java index 4ea6602ae1..f92f1d29c0 100755 --- a/model/api/src/main/java/org/keycloak/models/entities/IdentityProviderEntity.java +++ b/model/api/src/main/java/org/keycloak/models/entities/IdentityProviderEntity.java @@ -30,7 +30,6 @@ public class IdentityProviderEntity { private String providerId; private String name; private boolean enabled; - private String updateProfileFirstLoginMode; private boolean trustEmail; private boolean storeToken; protected boolean addReadTokenRoleOnCreate; @@ -63,14 +62,6 @@ public class IdentityProviderEntity { this.enabled = enabled; } - public String getUpdateProfileFirstLoginMode() { - return updateProfileFirstLoginMode; - } - - public void setUpdateProfileFirstLoginMode(String updateProfileFirstLoginMode) { - this.updateProfileFirstLoginMode = updateProfileFirstLoginMode; - } - public boolean isAuthenticateByDefault() { return authenticateByDefault; } 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 572d6f6b04..a874f5eecb 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 @@ -1,9 +1,14 @@ package org.keycloak.models.utils; +import java.util.HashMap; +import java.util.Map; + 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 org.keycloak.representations.idm.IdentityProviderRepresentation; /** * @author Bill Burke @@ -21,6 +26,8 @@ public class DefaultAuthenticationFlows { public static final String CLIENT_AUTHENTICATION_FLOW = "clients"; public static final String FIRST_BROKER_LOGIN_FLOW = "first broker login"; + public static final String IDP_REVIEW_PROFILE_CONFIG_ALIAS = "review profile config"; + public static void addFlows(RealmModel realm) { if (realm.getFlowByAlias(BROWSER_FLOW) == null) browserFlow(realm); if (realm.getFlowByAlias(DIRECT_GRANT_FLOW) == null) directGrantFlow(realm, false); @@ -321,24 +328,41 @@ public class DefaultAuthenticationFlows { firstBrokerLogin.setTopLevel(true); firstBrokerLogin.setBuiltIn(true); firstBrokerLogin = realm.addAuthenticationFlow(firstBrokerLogin); - // realm.setClientAuthenticationFlow(clients); + + AuthenticatorConfigModel reviewProfileConfig = new AuthenticatorConfigModel(); + reviewProfileConfig.setAlias(IDP_REVIEW_PROFILE_CONFIG_ALIAS); + Map config = new HashMap<>(); + config.put("update.profile.on.first.login", IdentityProviderRepresentation.UPFLM_MISSING); + reviewProfileConfig.setConfig(config); + reviewProfileConfig = realm.addAuthenticatorConfig(reviewProfileConfig); AuthenticationExecutionModel execution = new AuthenticationExecutionModel(); execution.setParentFlow(firstBrokerLogin.getId()); execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED); - execution.setAuthenticator("idp-update-profile"); + execution.setAuthenticator("idp-review-profile"); execution.setPriority(10); execution.setAuthenticatorFlow(false); + execution.setAuthenticatorConfig(reviewProfileConfig.getId()); realm.addAuthenticatorExecution(execution); + + AuthenticatorConfigModel createUserIfUniqueConfig = new AuthenticatorConfigModel(); + createUserIfUniqueConfig.setAlias("create unique user config"); + config = new HashMap<>(); + config.put("require.password.update.after.registration", "false"); + createUserIfUniqueConfig.setConfig(config); + createUserIfUniqueConfig = realm.addAuthenticatorConfig(createUserIfUniqueConfig); + execution = new AuthenticationExecutionModel(); execution.setParentFlow(firstBrokerLogin.getId()); execution.setRequirement(AuthenticationExecutionModel.Requirement.ALTERNATIVE); execution.setAuthenticator("idp-create-user-if-unique"); execution.setPriority(20); execution.setAuthenticatorFlow(false); + execution.setAuthenticatorConfig(createUserIfUniqueConfig.getId()); realm.addAuthenticatorExecution(execution); + AuthenticationFlowModel linkExistingAccountFlow = new AuthenticationFlowModel(); linkExistingAccountFlow.setTopLevel(false); linkExistingAccountFlow.setBuiltIn(true); diff --git a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java index b975b56052..69fcc07799 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 @@ -389,7 +389,6 @@ public class ModelToRepresentation { providerRep.setAlias(identityProviderModel.getAlias()); providerRep.setEnabled(identityProviderModel.isEnabled()); providerRep.setStoreToken(identityProviderModel.isStoreToken()); - providerRep.setUpdateProfileFirstLoginMode(identityProviderModel.getUpdateProfileFirstLoginMode()); providerRep.setTrustEmail(identityProviderModel.isTrustEmail()); providerRep.setAuthenticateByDefault(identityProviderModel.isAuthenticateByDefault()); providerRep.setConfig(identityProviderModel.getConfig()); 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 110b376fde..a31d35592b 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 @@ -1080,7 +1080,6 @@ public class RepresentationToModel { identityProviderModel.setAlias(representation.getAlias()); identityProviderModel.setProviderId(representation.getProviderId()); identityProviderModel.setEnabled(representation.isEnabled()); - identityProviderModel.setUpdateProfileFirstLoginMode(representation.getUpdateProfileFirstLoginMode()); identityProviderModel.setTrustEmail(representation.isTrustEmail()); identityProviderModel.setAuthenticateByDefault(representation.isAuthenticateByDefault()); identityProviderModel.setStoreToken(representation.isStoreToken()); 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 1cd8b45fde..106eaf8b1d 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 @@ -1216,7 +1216,6 @@ public class RealmAdapter implements RealmModel { identityProviderModel.setInternalId(entity.getInternalId()); identityProviderModel.setConfig(entity.getConfig()); identityProviderModel.setEnabled(entity.isEnabled()); - identityProviderModel.setUpdateProfileFirstLoginMode(entity.getUpdateProfileFirstLoginMode()); identityProviderModel.setTrustEmail(entity.isTrustEmail()); identityProviderModel.setAuthenticateByDefault(entity.isAuthenticateByDefault()); identityProviderModel.setFirstBrokerLoginFlowId(entity.getFirstBrokerLoginFlowId()); @@ -1250,7 +1249,6 @@ public class RealmAdapter implements RealmModel { entity.setEnabled(identityProvider.isEnabled()); entity.setStoreToken(identityProvider.isStoreToken()); entity.setAddReadTokenRoleOnCreate(identityProvider.isAddReadTokenRoleOnCreate()); - entity.setUpdateProfileFirstLoginMode(identityProvider.getUpdateProfileFirstLoginMode()); entity.setTrustEmail(identityProvider.isTrustEmail()); entity.setAuthenticateByDefault(identityProvider.isAuthenticateByDefault()); entity.setFirstBrokerLoginFlowId(identityProvider.getFirstBrokerLoginFlowId()); @@ -1278,7 +1276,6 @@ public class RealmAdapter implements RealmModel { if (entity.getInternalId().equals(identityProvider.getInternalId())) { entity.setAlias(identityProvider.getAlias()); entity.setEnabled(identityProvider.isEnabled()); - entity.setUpdateProfileFirstLoginMode(identityProvider.getUpdateProfileFirstLoginMode()); entity.setTrustEmail(identityProvider.isTrustEmail()); entity.setAuthenticateByDefault(identityProvider.isAuthenticateByDefault()); entity.setFirstBrokerLoginFlowId(identityProvider.getFirstBrokerLoginFlowId()); diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java index 5071c9b8be..6bbc31c614 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java @@ -42,9 +42,6 @@ public class IdentityProviderEntity { @Column(name="ENABLED") private boolean enabled; - @Column(name = "UPDATE_PROFILE_FIRST_LGN_MD") - private String updateProfileFirstLoginMode; - @Column(name = "TRUST_EMAIL") private boolean trustEmail; @@ -106,14 +103,6 @@ public class IdentityProviderEntity { this.enabled = enabled; } - public String getUpdateProfileFirstLoginMode() { - return updateProfileFirstLoginMode; - } - - public void setUpdateProfileFirstLoginMode(String updateProfileFirstLoginMode) { - this.updateProfileFirstLoginMode = updateProfileFirstLoginMode; - } - public boolean isStoreToken() { return this.storeToken; } 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 479862c01d..989497768c 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 @@ -823,7 +823,6 @@ public class RealmAdapter extends AbstractMongoAdapter impleme identityProviderModel.setInternalId(entity.getInternalId()); identityProviderModel.setConfig(entity.getConfig()); identityProviderModel.setEnabled(entity.isEnabled()); - identityProviderModel.setUpdateProfileFirstLoginMode(entity.getUpdateProfileFirstLoginMode()); identityProviderModel.setTrustEmail(entity.isTrustEmail()); identityProviderModel.setAuthenticateByDefault(entity.isAuthenticateByDefault()); identityProviderModel.setFirstBrokerLoginFlowId(entity.getFirstBrokerLoginFlowId()); @@ -855,7 +854,6 @@ public class RealmAdapter extends AbstractMongoAdapter impleme entity.setAlias(identityProvider.getAlias()); entity.setProviderId(identityProvider.getProviderId()); entity.setEnabled(identityProvider.isEnabled()); - entity.setUpdateProfileFirstLoginMode(identityProvider.getUpdateProfileFirstLoginMode()); entity.setTrustEmail(identityProvider.isTrustEmail()); entity.setAddReadTokenRoleOnCreate(identityProvider.isAddReadTokenRoleOnCreate()); entity.setStoreToken(identityProvider.isStoreToken()); @@ -884,7 +882,6 @@ public class RealmAdapter extends AbstractMongoAdapter impleme if (entity.getInternalId().equals(identityProvider.getInternalId())) { entity.setAlias(identityProvider.getAlias()); entity.setEnabled(identityProvider.isEnabled()); - entity.setUpdateProfileFirstLoginMode(identityProvider.getUpdateProfileFirstLoginMode()); entity.setTrustEmail(identityProvider.isTrustEmail()); entity.setAuthenticateByDefault(identityProvider.isAuthenticateByDefault()); entity.setFirstBrokerLoginFlowId(identityProvider.getFirstBrokerLoginFlowId()); diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpUpdateProfileAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticator.java similarity index 83% rename from services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpUpdateProfileAuthenticator.java rename to services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticator.java index 35e10fd247..04eb77b520 100644 --- a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpUpdateProfileAuthenticator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticator.java @@ -14,6 +14,7 @@ import org.keycloak.events.Details; import org.keycloak.events.EventBuilder; import org.keycloak.events.EventType; import org.keycloak.login.LoginFormsProvider; +import org.keycloak.models.AuthenticatorConfigModel; import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; @@ -26,9 +27,9 @@ import org.keycloak.services.validation.Validation; /** * @author Marek Posolda */ -public class IdpUpdateProfileAuthenticator extends AbstractIdpAuthenticator { +public class IdpReviewProfileAuthenticator extends AbstractIdpAuthenticator { - protected static Logger logger = Logger.getLogger(IdpUpdateProfileAuthenticator.class); + protected static Logger logger = Logger.getLogger(IdpReviewProfileAuthenticator.class); @Override public boolean requiresUser() { @@ -61,10 +62,17 @@ public class IdpUpdateProfileAuthenticator extends AbstractIdpAuthenticator { return true; } - IdentityProviderModel idpConfig = brokerContext.getIdpConfig(); + String updateProfileFirstLogin; + AuthenticatorConfigModel authenticatorConfig = context.getAuthenticatorConfig(); + if (authenticatorConfig == null || !authenticatorConfig.getConfig().containsKey(IdpReviewProfileAuthenticatorFactory.UPDATE_PROFILE_ON_FIRST_LOGIN)) { + updateProfileFirstLogin = IdentityProviderRepresentation.UPFLM_MISSING; + } else { + updateProfileFirstLogin = authenticatorConfig.getConfig().get(IdpReviewProfileAuthenticatorFactory.UPDATE_PROFILE_ON_FIRST_LOGIN); + } + RealmModel realm = context.getRealm(); - return IdentityProviderRepresentation.UPFLM_ON.equals(idpConfig.getUpdateProfileFirstLoginMode()) - || (IdentityProviderRepresentation.UPFLM_MISSING.equals(idpConfig.getUpdateProfileFirstLoginMode()) && !Validation.validateUserMandatoryFields(realm, userCtx)); + return IdentityProviderRepresentation.UPFLM_ON.equals(updateProfileFirstLogin) + || (IdentityProviderRepresentation.UPFLM_MISSING.equals(updateProfileFirstLogin) && !Validation.validateUserMandatoryFields(realm, userCtx)); } @Override diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticatorFactory.java new file mode 100644 index 0000000000..e10c924c5a --- /dev/null +++ b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticatorFactory.java @@ -0,0 +1,107 @@ +package org.keycloak.authentication.authenticators.broker; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.keycloak.Config; +import org.keycloak.authentication.Authenticator; +import org.keycloak.authentication.AuthenticatorFactory; +import org.keycloak.models.AuthenticationExecutionModel; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionFactory; +import org.keycloak.provider.ProviderConfigProperty; +import org.keycloak.representations.idm.IdentityProviderRepresentation; + +/** + * @author Marek Posolda + */ +public class IdpReviewProfileAuthenticatorFactory implements AuthenticatorFactory { + + public static final String PROVIDER_ID = "idp-review-profile"; + static IdpReviewProfileAuthenticator SINGLETON = new IdpReviewProfileAuthenticator(); + + public static final String UPDATE_PROFILE_ON_FIRST_LOGIN = "update.profile.on.first.login"; + + @Override + public Authenticator create(KeycloakSession session) { + return SINGLETON; + } + + @Override + public void init(Config.Scope config) { + + } + + @Override + public void postInit(KeycloakSessionFactory factory) { + + } + + @Override + public void close() { + + } + + @Override + public String getId() { + return PROVIDER_ID; + } + + @Override + public String getReferenceCategory() { + return "reviewProfile"; + } + + @Override + public boolean isConfigurable() { + return true; + } + + public static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = { + AuthenticationExecutionModel.Requirement.REQUIRED, + AuthenticationExecutionModel.Requirement.DISABLED}; + + @Override + public AuthenticationExecutionModel.Requirement[] getRequirementChoices() { + return REQUIREMENT_CHOICES; + } + + @Override + public String getDisplayType() { + return "Review Profile"; + } + + @Override + public String getHelpText() { + return "User reviews and updates profile data retrieved from Identity Provider in the displayed form"; + } + + @Override + public boolean isUserSetupAllowed() { + return false; + } + + private static final List configProperties = new ArrayList(); + + static { + ProviderConfigProperty property; + property = new ProviderConfigProperty(); + property.setName(UPDATE_PROFILE_ON_FIRST_LOGIN); + property.setLabel("{{:: 'update-profile-on-first-login' | translate}}"); + property.setType(ProviderConfigProperty.LIST_TYPE); + List updateProfileValues = Arrays.asList(IdentityProviderRepresentation.UPFLM_ON, IdentityProviderRepresentation.UPFLM_MISSING, IdentityProviderRepresentation.UPFLM_OFF); + property.setDefaultValue(updateProfileValues); + property.setHelpText("Define conditions under which a user has to review and update his profile after first-time login. Value 'On' means that" + + " page for reviewing profile will be displayed and user can review and update his profile. Value 'off' means that page won't be displayed." + + " Value 'missing' means that page is displayed just when some required attribute is missing (wasn't downloaded from identity provider). Value 'missing' is the default one"); + + configProperties.add(property); + } + + + @Override + public List getConfigProperties() { + return configProperties; + } +} diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpUpdateProfileAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpUpdateProfileAuthenticatorFactory.java deleted file mode 100644 index d947c60fca..0000000000 --- a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpUpdateProfileAuthenticatorFactory.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.keycloak.authentication.authenticators.broker; - -import java.util.List; - -import org.keycloak.Config; -import org.keycloak.authentication.Authenticator; -import org.keycloak.authentication.AuthenticatorFactory; -import org.keycloak.models.AuthenticationExecutionModel; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.KeycloakSessionFactory; -import org.keycloak.provider.ProviderConfigProperty; - -/** - * @author Marek Posolda - */ -public class IdpUpdateProfileAuthenticatorFactory implements AuthenticatorFactory { - - public static final String PROVIDER_ID = "idp-update-profile"; - static IdpUpdateProfileAuthenticator SINGLETON = new IdpUpdateProfileAuthenticator(); - - @Override - public Authenticator create(KeycloakSession session) { - return SINGLETON; - } - - @Override - public void init(Config.Scope config) { - - } - - @Override - public void postInit(KeycloakSessionFactory factory) { - - } - - @Override - public void close() { - - } - - @Override - public String getId() { - return PROVIDER_ID; - } - - @Override - public String getReferenceCategory() { - return "updateProfile"; - } - - @Override - public boolean isConfigurable() { - return false; - } - - public static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = { - AuthenticationExecutionModel.Requirement.REQUIRED, - AuthenticationExecutionModel.Requirement.DISABLED}; - - @Override - public AuthenticationExecutionModel.Requirement[] getRequirementChoices() { - return REQUIREMENT_CHOICES; - } - - @Override - public String getDisplayType() { - return "Update Profile"; - } - - @Override - public String getHelpText() { - return "Updates profile data retrieved from Identity Provider in the displayed form"; - } - - @Override - public List getConfigProperties() { - return null; - } - - @Override - public boolean isUserSetupAllowed() { - return false; - } -} diff --git a/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory b/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory index 6c900668cd..70551a17e9 100755 --- a/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory +++ b/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory @@ -9,7 +9,7 @@ org.keycloak.authentication.authenticators.resetcred.ResetCredentialChooseUser org.keycloak.authentication.authenticators.resetcred.ResetCredentialEmail org.keycloak.authentication.authenticators.resetcred.ResetOTP org.keycloak.authentication.authenticators.resetcred.ResetPassword -org.keycloak.authentication.authenticators.broker.IdpUpdateProfileAuthenticatorFactory +org.keycloak.authentication.authenticators.broker.IdpReviewProfileAuthenticatorFactory org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticatorFactory org.keycloak.authentication.authenticators.broker.IdpConfirmLinkAuthenticatorFactory org.keycloak.authentication.authenticators.broker.IdpEmailVerificationAuthenticatorFactory diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java index a7bae96fa8..f88fb4ae48 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java @@ -52,7 +52,6 @@ public class IdentityProviderTest extends AbstractClientTest { assertEquals("clientSecret", representation.getConfig().get("clientSecret")); assertTrue(representation.isEnabled()); assertFalse(representation.isStoreToken()); - assertEquals(IdentityProviderRepresentation.UPFLM_ON, representation.getUpdateProfileFirstLoginMode()); assertFalse(representation.isTrustEmail()); } diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java index f1d4e10936..8af43b2b63 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java @@ -23,15 +23,20 @@ import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; +import org.keycloak.authentication.authenticators.broker.IdpReviewProfileAuthenticatorFactory; +import org.keycloak.models.AuthenticatorConfigModel; import org.keycloak.models.ClientModel; import org.keycloak.models.Constants; import org.keycloak.models.FederatedIdentityModel; import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionTask; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserModel.RequiredAction; +import org.keycloak.models.utils.DefaultAuthenticationFlows; +import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.representations.IDToken; import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.services.Urls; @@ -138,7 +143,7 @@ public abstract class AbstractIdentityProviderTest { @Test public void testSuccessfulAuthentication() { IdentityProviderModel identityProviderModel = getIdentityProviderModel(); - identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_ON); + setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_ON); UserModel user = assertSuccessfulAuthentication(identityProviderModel, "test-user", "new@email.com", true); Assert.assertEquals("617-666-7777", user.getFirstAttribute("mobile")); @@ -147,7 +152,7 @@ public abstract class AbstractIdentityProviderTest { @Test public void testSuccessfulAuthenticationUpdateProfileOnMissing_nothingMissing() { IdentityProviderModel identityProviderModel = getIdentityProviderModel(); - identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_MISSING); + setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_MISSING); assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost", false); } @@ -155,7 +160,7 @@ public abstract class AbstractIdentityProviderTest { @Test public void testSuccessfulAuthenticationUpdateProfileOnMissing_missingEmail() { IdentityProviderModel identityProviderModel = getIdentityProviderModel(); - identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_MISSING); + setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_MISSING); assertSuccessfulAuthentication(identityProviderModel, "test-user-noemail", "new@email.com", true); } @@ -163,7 +168,7 @@ public abstract class AbstractIdentityProviderTest { @Test public void testSuccessfulAuthenticationWithoutUpdateProfile() { IdentityProviderModel identityProviderModel = getIdentityProviderModel(); - identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF); + setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF); assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost", false); } @@ -182,7 +187,7 @@ public abstract class AbstractIdentityProviderTest { IdentityProviderModel identityProviderModel = getIdentityProviderModel(); try { - identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF); + setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF); identityProviderModel.setTrustEmail(false); UserModel federatedUser = assertSuccessfulAuthenticationWithEmailVerification(identityProviderModel, "test-user", "test-user@localhost", false); @@ -251,7 +256,7 @@ public abstract class AbstractIdentityProviderTest { try { IdentityProviderModel identityProviderModel = getIdentityProviderModel(); - identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF); + setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF); UserModel federatedUser = assertSuccessfulAuthentication(identityProviderModel, "test-user-noemail", null, false); @@ -268,12 +273,12 @@ public abstract class AbstractIdentityProviderTest { @Test public void testSuccessfulAuthenticationWithoutUpdateProfile_emailProvided_emailVerifyEnabled_emailTrustEnabled() { getRealm().setVerifyEmail(true); + setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF); brokerServerRule.stopSession(this.session, true); this.session = brokerServerRule.startSession(); IdentityProviderModel identityProviderModel = getIdentityProviderModel(); try { - identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF); identityProviderModel.setTrustEmail(true); UserModel federatedUser = assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost", false); @@ -300,7 +305,7 @@ public abstract class AbstractIdentityProviderTest { IdentityProviderModel identityProviderModel = getIdentityProviderModel(); try { - identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_ON); + setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_ON); identityProviderModel.setTrustEmail(true); UserModel user = assertSuccessfulAuthenticationWithEmailVerification(identityProviderModel, "test-user", "new@email.com", true); @@ -320,7 +325,7 @@ public abstract class AbstractIdentityProviderTest { try { IdentityProviderModel identityProviderModel = getIdentityProviderModel(); - identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF); + setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF); authenticateWithIdentityProvider(identityProviderModel, "test-user", false); @@ -368,7 +373,7 @@ public abstract class AbstractIdentityProviderTest { try { IdentityProviderModel identityProviderModel = getIdentityProviderModel(); - identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF); + setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF); authenticateWithIdentityProvider(identityProviderModel, "test-user-noemail", false); @@ -475,7 +480,7 @@ public abstract class AbstractIdentityProviderTest { public void testUserAlreadyExistsWhenNotUpdatingProfile() { IdentityProviderModel identityProviderModel = getIdentityProviderModel(); - identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF); + setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_OFF); this.driver.navigate().to("http://localhost:8081/test-app/"); @@ -509,6 +514,7 @@ public abstract class AbstractIdentityProviderTest { // Link my "pedroigor" identity with "test-user" from brokered Keycloak IdentityProviderModel identityProviderModel = getIdentityProviderModel(); + setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_ON); accountFederatedIdentityPage.clickAddProvider(identityProviderModel.getAlias()); assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8082/auth/")); @@ -609,6 +615,7 @@ public abstract class AbstractIdentityProviderTest { @Test public void testTokenStorageAndRetrievalByApplication() { + setUpdateProfileFirstLogin(IdentityProviderRepresentation.UPFLM_ON); IdentityProviderModel identityProviderModel = getIdentityProviderModel(); identityProviderModel.setStoreToken(true); @@ -774,7 +781,6 @@ public abstract class AbstractIdentityProviderTest { assertNotNull(identityProviderModel); - identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_ON); identityProviderModel.setEnabled(true); return identityProviderModel; @@ -851,4 +857,18 @@ public abstract class AbstractIdentityProviderTest { return htmlVerificationUrl; } + + private void setUpdateProfileFirstLogin(final String updateProfileFirstLogin) { + KeycloakModelUtils.runJobInTransaction(this.session.getKeycloakSessionFactory(), new KeycloakSessionTask() { + + @Override + public void run(KeycloakSession session) { + RealmModel realm = session.realms().getRealm("realm-with-broker"); + AuthenticatorConfigModel reviewProfileConfig = realm.getAuthenticatorConfigByAlias(DefaultAuthenticationFlows.IDP_REVIEW_PROFILE_CONFIG_ALIAS); + reviewProfileConfig.getConfig().put(IdpReviewProfileAuthenticatorFactory.UPDATE_PROFILE_ON_FIRST_LOGIN, updateProfileFirstLogin); + realm.updateAuthenticatorConfig(reviewProfileConfig); + } + + }); + } } diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java index b5bc056aa0..8e23f114d2 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java @@ -81,7 +81,6 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes identityProviderModel.getConfig().put("config-added", "value-added"); identityProviderModel.setEnabled(false); - identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF); identityProviderModel.setTrustEmail(true); identityProviderModel.setStoreToken(true); identityProviderModel.setAuthenticateByDefault(true); @@ -97,7 +96,6 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes assertEquals("value-added", identityProviderModel.getConfig().get("config-added")); assertFalse(identityProviderModel.isEnabled()); - assertEquals(IdentityProviderRepresentation.UPFLM_OFF, identityProviderModel.getUpdateProfileFirstLoginMode()); assertTrue(identityProviderModel.isTrustEmail()); assertTrue(identityProviderModel.isStoreToken()); assertTrue(identityProviderModel.isAuthenticateByDefault()); @@ -105,7 +103,6 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes identityProviderModel.getConfig().remove("config-added"); identityProviderModel.setEnabled(true); - identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_MISSING); identityProviderModel.setTrustEmail(false); identityProviderModel.setAuthenticateByDefault(false); @@ -118,7 +115,6 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes assertFalse(identityProviderModel.getConfig().containsKey("config-added")); assertTrue(identityProviderModel.isEnabled()); - assertEquals(IdentityProviderRepresentation.UPFLM_MISSING, identityProviderModel.getUpdateProfileFirstLoginMode()); assertFalse(identityProviderModel.isTrustEmail()); assertFalse(identityProviderModel.isAuthenticateByDefault()); this.realmManager.removeRealm(realm); @@ -167,7 +163,6 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes assertEquals("model-google", config.getAlias()); assertEquals(GoogleIdentityProviderFactory.PROVIDER_ID, config.getProviderId()); assertEquals(true, config.isEnabled()); - assertEquals(IdentityProviderRepresentation.UPFLM_ON, config.getUpdateProfileFirstLoginMode()); assertEquals(true, config.isTrustEmail()); assertEquals(false, config.isAuthenticateByDefault()); assertEquals(true, config.isStoreToken()); @@ -186,7 +181,6 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes assertEquals("model-saml-signed-idp", config.getAlias()); assertEquals(SAMLIdentityProviderFactory.PROVIDER_ID, config.getProviderId()); assertEquals(true, config.isEnabled()); - assertEquals(IdentityProviderRepresentation.UPFLM_ON, config.getUpdateProfileFirstLoginMode()); assertEquals(false, config.isAuthenticateByDefault()); assertEquals(false, config.isTrustEmail()); assertEquals(false, config.isStoreToken()); @@ -207,7 +201,6 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes assertEquals("model-oidc-idp", config.getAlias()); assertEquals(OIDCIdentityProviderFactory.PROVIDER_ID, config.getProviderId()); assertEquals(false, config.isEnabled()); - assertEquals(IdentityProviderRepresentation.UPFLM_OFF, config.getUpdateProfileFirstLoginMode()); assertEquals(false, config.isTrustEmail()); assertEquals(false, config.isAuthenticateByDefault()); assertEquals(false, config.isStoreToken()); @@ -222,7 +215,6 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes assertEquals("model-facebook", config.getAlias()); assertEquals(FacebookIdentityProviderFactory.PROVIDER_ID, config.getProviderId()); assertEquals(true, config.isEnabled()); - assertEquals(IdentityProviderRepresentation.UPFLM_OFF, config.getUpdateProfileFirstLoginMode()); assertEquals(false, config.isTrustEmail()); assertEquals(false, config.isAuthenticateByDefault()); assertEquals(false, config.isStoreToken()); @@ -241,7 +233,6 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes assertEquals("model-github", config.getAlias()); assertEquals(GitHubIdentityProviderFactory.PROVIDER_ID, config.getProviderId()); assertEquals(true, config.isEnabled()); - assertEquals(IdentityProviderRepresentation.UPFLM_ON, config.getUpdateProfileFirstLoginMode()); assertEquals(false, config.isTrustEmail()); assertEquals(false, config.isAuthenticateByDefault()); assertEquals(false, config.isStoreToken()); @@ -258,17 +249,16 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes OAuth2IdentityProviderConfig config = liIdentityProvider.getConfig(); assertEquals("model-linkedin", config.getAlias()); - assertEquals(LinkedInIdentityProviderFactory.PROVIDER_ID, config.getProviderId()); - assertEquals(true, config.isEnabled()); - assertEquals(IdentityProviderRepresentation.UPFLM_MISSING, config.getUpdateProfileFirstLoginMode()); + assertEquals(LinkedInIdentityProviderFactory.PROVIDER_ID, config.getProviderId()); + assertEquals(true, config.isEnabled()); assertEquals(false, config.isTrustEmail()); - assertEquals(false, config.isAuthenticateByDefault()); - assertEquals(false, config.isStoreToken()); - assertEquals("clientId", config.getClientId()); - assertEquals("clientSecret", config.getClientSecret()); - assertEquals(LinkedInIdentityProvider.AUTH_URL, config.getAuthorizationUrl()); - assertEquals(LinkedInIdentityProvider.TOKEN_URL, config.getTokenUrl()); - assertEquals(LinkedInIdentityProvider.PROFILE_URL, config.getUserInfoUrl()); + assertEquals(false, config.isAuthenticateByDefault()); + assertEquals(false, config.isStoreToken()); + assertEquals("clientId", config.getClientId()); + assertEquals("clientSecret", config.getClientSecret()); + assertEquals(LinkedInIdentityProvider.AUTH_URL, config.getAuthorizationUrl()); + assertEquals(LinkedInIdentityProvider.TOKEN_URL, config.getTokenUrl()); + assertEquals(LinkedInIdentityProvider.PROFILE_URL, config.getUserInfoUrl()); } private void assertStackoverflowIdentityProviderConfig(IdentityProviderModel identityProvider) { @@ -278,7 +268,6 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes assertEquals("model-stackoverflow", config.getAlias()); assertEquals(StackoverflowIdentityProviderFactory.PROVIDER_ID, config.getProviderId()); assertEquals(true, config.isEnabled()); - assertEquals(IdentityProviderRepresentation.UPFLM_OFF, config.getUpdateProfileFirstLoginMode()); assertEquals(false, config.isTrustEmail()); assertEquals(false, config.isAuthenticateByDefault()); assertEquals(false, config.isStoreToken()); @@ -297,7 +286,6 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes assertEquals("model-twitter", config.getAlias()); assertEquals(TwitterIdentityProviderFactory.PROVIDER_ID, config.getProviderId()); assertEquals(true, config.isEnabled()); - assertEquals(IdentityProviderRepresentation.UPFLM_OFF, config.getUpdateProfileFirstLoginMode()); assertEquals(false, config.isTrustEmail()); assertEquals(false, config.isAuthenticateByDefault()); assertEquals(true, config.isStoreToken()); diff --git a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json index a4f204d146..0b8b79e947 100755 --- a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json +++ b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json @@ -17,7 +17,6 @@ "alias" : "model-google", "providerId" : "google", "enabled": true, - "updateProfileFirstLogin" : "true", "trustEmail" : "true", "storeToken": "true", "config": { @@ -29,7 +28,6 @@ "alias" : "model-facebook", "providerId" : "facebook", "enabled": true, - "updateProfileFirstLogin" : "false", "firstBrokerLoginFlowAlias" : "browser", "config": { "authorizationUrl": "authorizationUrl", @@ -43,7 +41,6 @@ "alias" : "model-github", "providerId" : "github", "enabled": true, - "updateProfileFirstLoginMode" : "on", "storeToken": "false", "config": { "authorizationUrl": "authorizationUrl", @@ -57,7 +54,6 @@ "alias" : "model-twitter", "providerId" : "twitter", "enabled": true, - "updateProfileFirstLoginMode" : "off", "storeToken": true, "config": { "authorizationUrl": "authorizationUrl", @@ -71,7 +67,6 @@ "alias" : "model-linkedin", "providerId" : "linkedin", "enabled": true, - "updateProfileFirstLoginMode" : "missing", "storeToken": false, "config": { "authorizationUrl": "authorizationUrl", @@ -85,7 +80,6 @@ "alias" : "model-stackoverflow", "providerId" : "stackoverflow", "enabled": true, - "updateProfileFirstLoginMode" : "off", "storeToken": false, "config": { "key": "keyValue", @@ -100,7 +94,6 @@ "alias" : "model-saml-signed-idp", "providerId" : "saml", "enabled": true, - "updateProfileFirstLoginMode" : "on", "config": { "singleSignOnServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-identity-provider/protocol/saml", "nameIDPolicyFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", @@ -116,7 +109,6 @@ "alias" : "kc-saml-signed-idp", "providerId" : "saml", "enabled": true, - "updateProfileFirstLoginMode" : "on", "addReadTokenRoleOnCreate": true, "config": { "singleSignOnServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-signed-idp/protocol/saml", @@ -135,7 +127,6 @@ "alias" : "kc-saml-idp-basic", "providerId" : "saml", "enabled": true, - "updateProfileFirstLoginMode" : "on", "trustEmail" : false, "addReadTokenRoleOnCreate": true, "config": { @@ -151,7 +142,6 @@ "alias" : "model-oidc-idp", "providerId" : "oidc", "enabled": false, - "updateProfileFirstLoginMode" : "off", "authenticateByDefault" : "false", "config": { "clientId": "clientId", @@ -167,7 +157,6 @@ "alias" : "kc-oidc-idp", "providerId" : "keycloak-oidc", "enabled": true, - "updateProfileFirstLoginMode" : "off", "storeToken" : true, "addReadTokenRoleOnCreate": true, "config": {