Merge pull request #1804 from mposolda/broker-reauthentication

KEYCLOAK-1750 First broker login changes
This commit is contained in:
Marek Posolda 2015-11-10 11:52:47 +01:00
commit caea1a3458
30 changed files with 277 additions and 272 deletions

View file

@ -7,6 +7,7 @@
<constraints nullable="false"/>
</column>
</addColumn>
<dropColumn tableName="IDENTITY_PROVIDER" columnName="UPDATE_PROFILE_FIRST_LGN_MD"/>
</changeSet>
</databaseChangeLog>

View file

@ -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;
}

View file

@ -79,16 +79,34 @@
<section>
<title>Version specific migration</title>
<section>
<title>Migrating to 1.7.0.CR1</title>
<simplesect>
<title>Option 'Update Profile On First Login' moved from Identity provider to Review Profile authenticator</title>
<para>
In this version, we added <literal>First Broker Login</literal>, 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 <literal>First Login Flow</literal> to identity providers where
you can specify the flow and then you can configure this flow under <literal>Authentication</literal> tab in admin console.
</para>
<para>
We also removed the option <literal>Update Profile On First Login</literal> from the Identity provider settings and moved it
to the configuration of <literal>Review Profile</literal> authenticator. So once you specify which flow should be used for your
Identity provider (by default it's <literal>First Broker Login</literal> flow), you go to <literal>Authentication</literal> tab, select the flow
and then you configure the option under <literal>Review Profile</literal> authenticator.
</para>
</simplesect>
</section>
<section>
<title>Migrating to 1.6.0.Final</title>
<simplesect>
<title>Refresh tokens are not reusable anymore</title>
<title>Option that refresh tokens are not reusable anymore</title>
<para>
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 <literal>Revoke refresh token</literal> 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.
</para>
</simplesect>
<simplesect>

View file

@ -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();
},

View file

@ -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.");

View file

@ -53,8 +53,8 @@
<li data-ng-hide="flow.builtIn"><a href="" ng-click="removeExecution(execution)">Delete</a></li>
<li data-ng-hide="flow.builtIn || !execution.authenticationFlow"><a href="" ng-click="addSubFlowExecution(execution)">Add Execution</a></li>
<li data-ng-hide="flow.builtIn || !execution.authenticationFlow"><a href="" ng-click="addSubFlow(execution)">Add Flow</a></li>
<li data-ng-show="execution.configurable && execution.authenticationConfig == null"><a href="#/create/authentication/{{realm.realm}}/execution/{{execution.id}}/provider/{{execution.providerId}}">Config</a></li>
<li data-ng-show="execution.configurable && execution.authenticationConfig != null"><a href="#/realms/{{realm.realm}}/authentication/config/{{execution.providerId}}/{{execution.authenticationConfig}}">Config</a></li>
<li data-ng-show="execution.configurable && execution.authenticationConfig == null"><a href="#/create/authentication/{{realm.realm}}/flows/{{flow.id}}/execution/{{execution.id}}/provider/{{execution.providerId}}">Config</a></li>
<li data-ng-show="execution.configurable && execution.authenticationConfig != null"><a href="#/realms/{{realm.realm}}/authentication/flows/{{flow.id}}/config/{{execution.providerId}}/{{execution.authenticationConfig}}">Config</a></li>
</ul>
</div>
</td>

View file

@ -2,6 +2,7 @@
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.realm}}/authentication/flows">Authentication Flows</a></li>
<li><a href="#/realms/{{realm.realm}}/authentication/flows/{{flow.alias}}">{{flow.alias | capitalize}}</a></li>
<li class="active" data-ng-show="create">Create Authenticator Config</li>
<li class="active" data-ng-hide="create">{{config.alias}}</li>
</ol>

View file

@ -1,4 +1,4 @@
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2" data-ng-init="initProvider()">
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.realm}}/identity-provider-settings">{{:: 'identity-providers' | translate}}</a></li>
<li>{{identityProvider.alias}}</li>
@ -52,19 +52,6 @@
</div>
<kc-tooltip>{{:: 'identity-provider.stored-tokens-readable.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="updateProfileFirstLoginMode">{{:: 'update-profile-on-first-login' | translate}}</label>
<div class="col-md-2">
<div>
<select id="updateProfileFirstLoginMode" ng-model="identityProvider.updateProfileFirstLoginMode" class="form-control">
<option value="on">{{:: 'on' | translate}}</option>
<option value="missing">{{:: 'on-missing-info' | translate}}</option>
<option value="off">{{:: 'off' | translate}}</option>
</select>
</div>
</div>
<kc-tooltip>{{:: 'update-profile-on-first-login.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="trustEmail">{{:: 'trust-email' | translate}}</label>
<div class="col-md-6">

View file

@ -52,19 +52,6 @@
</div>
<kc-tooltip>{{:: 'identity-provider.stored-tokens-readable.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="updateProfileFirstLoginMode">{{:: 'update-profile-on-first-login' | translate}}</label>
<div class="col-md-2">
<div>
<select id="updateProfileFirstLoginMode" ng-model="identityProvider.updateProfileFirstLoginMode" class="form-control">
<option value="on">{{:: 'on' | translate}}</option>
<option value="missing">{{:: 'on-missing-info' | translate}}</option>
<option value="off">{{:: 'off' | translate}}</option>
</select>
</div>
</div>
<kc-tooltip>{{:: 'update-profile-on-first-login.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="trustEmail">{{:: 'trust-email' | translate}}</label>
<div class="col-md-6">

View file

@ -1,4 +1,4 @@
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2" data-ng-init="initProvider()">
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.realm}}/identity-provider-settings">{{:: 'identity-providers' | translate}}</a></li>
<li>{{identityProvider.alias}}</li>
@ -63,19 +63,6 @@
</div>
<kc-tooltip>{{:: 'identity-provider.enabled.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="updateProfileFirstLoginMode">{{:: 'update-profile-on-first-login' | translate}}</label>
<div class="col-md-2">
<div>
<select id="updateProfileFirstLoginMode" ng-model="identityProvider.updateProfileFirstLoginMode" class="form-control">
<option value="on">{{:: 'on' | translate}}</option>
<option value="missing">{{:: 'on-missing-info' | translate}}</option>
<option value="off">{{:: 'off' | translate}}</option>
</select>
</div>
</div>
<kc-tooltip>{{:: 'update-profile-on-first-login.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="trustEmail">{{:: 'trust-email' | translate}}</label>
<div class="col-md-6">

View file

@ -12,7 +12,7 @@
<form id="kc-register-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
<div id="kc-form-buttons" class="${properties.kcFormGroupClass!}">
<button type="submit" class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="submitAction" value="updateProfile">${msg("confirmLinkIdpUpdateProfile")}</button>
<button type="submit" class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="submitAction" value="updateProfile">${msg("confirmLinkIdpReviewProfile")}</button>
<button type="submit" class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="submitAction" value="linkAccount">${msg("confirmLinkIdpContinue", idpAlias)}</button>
</div>

View file

@ -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.

View file

@ -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<String, String>(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;
}

View file

@ -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;
}

View file

@ -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 <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -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<String, String> 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-detect-duplications");
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);

View file

@ -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());

View file

@ -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());

View file

@ -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());

View file

@ -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;
}

View file

@ -823,7 +823,6 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> 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<MongoRealmEntity> 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<MongoRealmEntity> 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());

View file

@ -10,17 +10,19 @@ import org.keycloak.authentication.AuthenticationFlowContext;
import org.keycloak.authentication.authenticators.broker.util.ExistingUserInfo;
import org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext;
import org.keycloak.broker.provider.BrokeredIdentityContext;
import org.keycloak.models.AuthenticatorConfigModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.FormMessage;
import org.keycloak.services.messages.Messages;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class IdpDetectDuplicationsAuthenticator extends AbstractIdpAuthenticator {
public class IdpCreateUserIfUniqueAuthenticator extends AbstractIdpAuthenticator {
protected static Logger logger = Logger.getLogger(IdpDetectDuplicationsAuthenticator.class);
protected static Logger logger = Logger.getLogger(IdpCreateUserIfUniqueAuthenticator.class);
@Override
@ -54,6 +56,12 @@ public class IdpDetectDuplicationsAuthenticator extends AbstractIdpAuthenticator
federatedUser.setAttribute(attr.getKey(), attr.getValue());
}
AuthenticatorConfigModel config = context.getAuthenticatorConfig();
if (config != null && Boolean.parseBoolean(config.getConfig().get(IdpCreateUserIfUniqueAuthenticatorFactory.REQUIRE_PASSWORD_UPDATE_AFTER_REGISTRATION))) {
logger.debugf("User '%s' required to update password", federatedUser.getUsername());
federatedUser.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
}
// TODO: Event
context.setUser(federatedUser);

View file

@ -1,5 +1,6 @@
package org.keycloak.authentication.authenticators.broker;
import java.util.ArrayList;
import java.util.List;
import org.keycloak.Config;
@ -13,10 +14,12 @@ import org.keycloak.provider.ProviderConfigProperty;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class IdpDetectDuplicationsAuthenticatorFactory implements AuthenticatorFactory {
public class IdpCreateUserIfUniqueAuthenticatorFactory implements AuthenticatorFactory {
public static final String PROVIDER_ID = "idp-detect-duplications";
static IdpDetectDuplicationsAuthenticator SINGLETON = new IdpDetectDuplicationsAuthenticator();
public static final String PROVIDER_ID = "idp-create-user-if-unique";
static IdpCreateUserIfUniqueAuthenticator SINGLETON = new IdpCreateUserIfUniqueAuthenticator();
public static final String REQUIRE_PASSWORD_UPDATE_AFTER_REGISTRATION = "require.password.update.after.registration";
@Override
public Authenticator create(KeycloakSession session) {
@ -50,7 +53,7 @@ public class IdpDetectDuplicationsAuthenticatorFactory implements AuthenticatorF
@Override
public boolean isConfigurable() {
return false;
return true;
}
public static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = {
@ -73,13 +76,26 @@ public class IdpDetectDuplicationsAuthenticatorFactory implements AuthenticatorF
return "Detect if there is existing Keycloak account with same email like identity provider. If no, create new user";
}
@Override
public List<ProviderConfigProperty> getConfigProperties() {
return null;
}
@Override
public boolean isUserSetupAllowed() {
return false;
}
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
static {
ProviderConfigProperty property;
property = new ProviderConfigProperty();
property.setName(REQUIRE_PASSWORD_UPDATE_AFTER_REGISTRATION);
property.setLabel("Require Password Update After Registration");
property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
property.setHelpText("If this option is true and new user is successfully imported from Identity Provider to Keycloak (there is no duplicated email or username detected in Keycloak DB), then this user is required to update his password");
configProperties.add(property);
}
@Override
public List<ProviderConfigProperty> getConfigProperties() {
return configProperties;
}
}

View file

@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
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

View file

@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
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<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
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<String> 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<ProviderConfigProperty> getConfigProperties() {
return configProperties;
}
}

View file

@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
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<ProviderConfigProperty> getConfigProperties() {
return null;
}
@Override
public boolean isUserSetupAllowed() {
return false;
}
}

View file

@ -9,8 +9,8 @@ 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.IdpDetectDuplicationsAuthenticatorFactory
org.keycloak.authentication.authenticators.broker.IdpReviewProfileAuthenticatorFactory
org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticatorFactory
org.keycloak.authentication.authenticators.broker.IdpConfirmLinkAuthenticatorFactory
org.keycloak.authentication.authenticators.broker.IdpEmailVerificationAuthenticatorFactory
org.keycloak.authentication.authenticators.broker.IdpUsernamePasswordFormFactory

View file

@ -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());
}

View file

@ -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);
}
});
}
}

View file

@ -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());

View file

@ -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": {