KEYCLOAK-1371 - Perform "Update Profile on First Login" only if some of

mandatory user profile fields is missing from identity provider
This commit is contained in:
Vlastimil Elias 2015-06-03 15:24:25 +02:00
parent fb60ca115f
commit dcc19a39d7
27 changed files with 293 additions and 127 deletions

View file

@ -112,7 +112,17 @@
</addColumn>
<addColumn tableName="IDENTITY_PROVIDER">
<column name="TRUST_EMAIL" type="BOOLEAN" defaultValueBoolean="false"/>
<column name="UPDATE_PROFILE_FIRST_LOGIN_MODE" type="VARCHAR(10)" defaultValue="on">
<constraints nullable="false"/>
</column>
</addColumn>
<!-- migrate value from UPDATE_PROFILE_FIRST_LOGIN to UPDATE_PROFILE_FIRST_LOGIN_MODE then drop it -->
<update tableName="IDENTITY_PROVIDER">
<column name="UPDATE_PROFILE_FIRST_LOGIN_MODE" value="off"/>
<where>UPDATE_PROFILE_FIRST_LOGIN = false</where>
</update>
<dropColumn tableName="IDENTITY_PROVIDER" columnName="UPDATE_PROFILE_FIRST_LOGIN"/>
<addColumn tableName="USER_REQUIRED_ACTION">
<column name="REQUIRED_ACTION" type="VARCHAR(36)">
<constraints nullable="false"/>

View file

@ -29,7 +29,25 @@ public class IdentityProviderRepresentation {
protected String internalId;
protected String providerId;
protected boolean enabled = true;
protected boolean updateProfileFirstLogin = true;
public static final String UPFLM_ON = "on";
public static final String UPFLM_MISSING = "missing";
public static final String UPFLM_OFF = "off";
/**
* Mode of profile update after first login when user is created over this identity provider. Possible values:
* <ul>
* <li><code>on</code> - update profile page is presented for all users
* <li><code>missing</code> - update profile page is presented for users with missing some of mandatory user profile fields
* <li><code>off</code> - update profile page is newer shown after first login
* </ul>
*
* @see #UPFLM_ON
* @see #UPFLM_MISSING
* @see #UPFLM_OFF
*/
protected String updateProfileFirstLoginMode = UPFLM_ON;
protected boolean trustEmail;
protected boolean storeToken;
protected boolean addReadTokenRoleOnCreate;
@ -76,12 +94,29 @@ public class IdentityProviderRepresentation {
this.enabled = enabled;
}
public boolean isUpdateProfileFirstLogin() {
return this.updateProfileFirstLogin;
/**
*
* Deprecated because replaced by {@link #updateProfileFirstLoginMode}. Kept here to allow import of old realms.
*
* @deprecated {@link #setUpdateProfileFirstLoginMode(String)}
*/
@Deprecated
public void setUpdateProfileFirstLogin(boolean updateProfileFirstLogin) {
this.updateProfileFirstLoginMode = updateProfileFirstLogin ? UPFLM_ON : UPFLM_OFF;
}
public void setUpdateProfileFirstLogin(boolean updateProfileFirstLogin) {
this.updateProfileFirstLogin = updateProfileFirstLogin;
/**
* @return see {@link #updateProfileFirstLoginMode}
*/
public String getUpdateProfileFirstLoginMode() {
return updateProfileFirstLoginMode;
}
/**
* @param updateProfileFirstLoginMode see {@link #updateProfileFirstLoginMode}
*/
public void setUpdateProfileFirstLoginMode(String updateProfileFirstLoginMode) {
this.updateProfileFirstLoginMode = updateProfileFirstLoginMode;
}
public boolean isAuthenticateByDefault() {

View file

@ -299,9 +299,11 @@
</entry>
<entry>
Allows you to force users to update their profile right after the authentication finishes and
before the account is actually created in Keycloak. When enabled, users will be presented with the
before the account is actually created in Keycloak. When "On", users will be always presented with the
<emphasis>update profile page</emphasis> asking for additional information in order to federate their identities.
If disabled, the account will be created with the minimal information obtained from the identity provider
When "On missing info", users will be presented with the <emphasis>update profile page</emphasis> only if some
mandatory information (email, first name, last name) is not provided by identity provider.
If "Off", the account will be created with the minimal information obtained from the identity provider
during the authentication process.
</entry>
</row>

View file

@ -597,7 +597,7 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
if (instance && instance.alias) {
} else {
$scope.identityProvider.updateProfileFirstLogin = false;
$scope.identityProvider.updateProfileFirstLoginMode = "on";
}
};
@ -645,7 +645,7 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
} else {
$scope.identityProvider.config.nameIDPolicyFormat = $scope.nameIdFormats[0].format;
$scope.identityProvider.updateProfileFirstLogin = false;
$scope.identityProvider.updateProfileFirstLoginMode = "off";
}
}
@ -663,7 +663,7 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
$scope.identityProvider.alias = providerFactory.id;
$scope.identityProvider.providerId = providerFactory.id;
$scope.identityProvider.enabled = true;
$scope.identityProvider.updateProfileFirstLogin = false;
$scope.identityProvider.updateProfileFirstLoginMode = "off";
$scope.identityProvider.authenticateByDefault = false;
$scope.newIdentityProvider = true;
}

View file

@ -59,11 +59,17 @@
<kc-tooltip>Enable/disable new users can read any stored tokens. This assigns the broker.read-token role.</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="updateProfileFirstLogin">Update Profile on First Login</label>
<div class="col-md-6">
<input ng-model="identityProvider.updateProfileFirstLogin" name="identityProvider.updateProfileFirstLogin" id="updateProfileFirstLogin" onoffswitch />
<label class="col-md-2 control-label" for="updateProfileFirstLoginMode">Update Profile on First Login</label>
<div class="col-md-2">
<div>
<select id="updateProfileFirstLoginMode" ng-model="identityProvider.updateProfileFirstLoginMode" class="form-control">
<option value="on">On</option>
<option value="missing">On missing info</option>
<option value="off">Off</option>
</select>
</div>
<kc-tooltip>Indicates if user must update his profile right after the first login.</kc-tooltip>
</div>
<kc-tooltip>Define under which conditions must user update his profile right after the first login.</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="trustEmail">Trust email</label>

View file

@ -60,11 +60,17 @@
<kc-tooltip>Enable/disable new users can read any stored tokens. This assigns the broker.read-token role.</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="updateProfileFirstLogin">Update Profile on First Login</label>
<div class="col-md-6">
<input ng-model="identityProvider.updateProfileFirstLogin" name="identityProvider.updateProfileFirstLogin" id="updateProfileFirstLogin" onoffswitch />
<label class="col-md-2 control-label" for="updateProfileFirstLoginMode">Update Profile on First Login</label>
<div class="col-md-2">
<div>
<select id="updateProfileFirstLoginMode" ng-model="identityProvider.updateProfileFirstLoginMode" class="form-control">
<option value="on">On</option>
<option value="missing">On missing info</option>
<option value="off">Off</option>
</select>
</div>
<kc-tooltip>Indicates if user must update his profile right after the first login.</kc-tooltip>
</div>
<kc-tooltip>Define under which conditions must user update his profile right after the first login.</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="trustEmail">Trust email</label>

View file

@ -70,11 +70,17 @@
<kc-tooltip>Enable/disable this identity provider.</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="updateProfileFirstLogin">Update Profile on First Login</label>
<div class="col-md-6">
<input ng-model="identityProvider.updateProfileFirstLogin" name="identityProvider.updateProfileFirstLogin" id="updateProfileFirstLogin" onoffswitch />
<label class="col-md-2 control-label" for="updateProfileFirstLoginMode">Update Profile on First Login</label>
<div class="col-md-2">
<div>
<select id="updateProfileFirstLoginMode" ng-model="identityProvider.updateProfileFirstLoginMode" class="form-control">
<option value="on">On</option>
<option value="missing">On missing info</option>
<option value="off">Off</option>
</select>
</div>
<kc-tooltip>Indicates if user must update his profile right after the first login.</kc-tooltip>
</div>
<kc-tooltip>Define under which conditions must user update his profile right after the first login.</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="trustEmail">Trust email</label>

View file

@ -8,7 +8,7 @@
<caption class="hidden">Table of identity providers</caption>
<thead>
<tr>
<th colspan="3" class="kc-table-actions">
<th colspan="4" class="kc-table-actions">
<div class="dropdown pull-right">
<select class="form-control" ng-model="provider"
ng-options="p.name group by p.groupName for p in allProviders track by p.id"
@ -21,6 +21,7 @@
<tr ng-show="configuredProviders.length > 0">
<th>Name</th>
<th>Provider</th>
<th>Enabled</th>
<th width="15%">GUI order</th>
</tr>
</thead>
@ -30,6 +31,7 @@
<a href="#/realms/{{realm.realm}}/identity-provider-settings/provider/{{identityProvider.providerId}}/{{identityProvider.alias}}">{{identityProvider.alias}}</a>
</td>
<td>{{identityProvider.providerId}}</td>
<td>{{identityProvider.enabled}}</td>
<td>{{identityProvider.config.guiOrder}}</td>
</tr>
</tbody>

View file

@ -20,6 +20,8 @@ package org.keycloak.models;
import java.util.HashMap;
import java.util.Map;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
/**
* <p>A model type representing the configuration for identity providers. It provides some common properties and also a {@link org.keycloak.models.IdentityProviderModel#config}
* for configuration options and properties specifics to a identity provider.</p>
@ -43,7 +45,13 @@ public class IdentityProviderModel {
private boolean enabled;
private boolean updateProfileFirstLogin = true;
/**
* 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;
@ -70,7 +78,7 @@ public class IdentityProviderModel {
this.alias = model.getAlias();
this.config = new HashMap<String, String>(model.getConfig());
this.enabled = model.isEnabled();
this.updateProfileFirstLogin = model.isUpdateProfileFirstLogin();
this.updateProfileFirstLoginMode = model.getUpdateProfileFirstLoginMode();
this.trustEmail = model.isTrustEmail();
this.storeToken = model.isStoreToken();
this.authenticateByDefault = model.isAuthenticateByDefault();
@ -109,12 +117,18 @@ public class IdentityProviderModel {
this.enabled = enabled;
}
public boolean isUpdateProfileFirstLogin() {
return this.updateProfileFirstLogin;
/**
* @see IdentityProviderRepresentation#getUpdateProfileFirstLoginMode()
*/
public String getUpdateProfileFirstLoginMode() {
return updateProfileFirstLoginMode;
}
public void setUpdateProfileFirstLogin(boolean updateProfileFirstLogin) {
this.updateProfileFirstLogin = updateProfileFirstLogin;
/**
* @see IdentityProviderRepresentation#setUpdateProfileFirstLoginMode(String)
*/
public void setUpdateProfileFirstLoginMode(String updateProfileFirstLoginMode) {
this.updateProfileFirstLoginMode = updateProfileFirstLoginMode;
}
public boolean isStoreToken() {

View file

@ -30,7 +30,7 @@ public class IdentityProviderEntity {
private String providerId;
private String name;
private boolean enabled;
private boolean updateProfileFirstLogin;
private String updateProfileFirstLoginMode;
private boolean trustEmail;
private boolean storeToken;
protected boolean addReadTokenRoleOnCreate;
@ -62,12 +62,12 @@ public class IdentityProviderEntity {
this.enabled = enabled;
}
public boolean isUpdateProfileFirstLogin() {
return updateProfileFirstLogin;
public String getUpdateProfileFirstLoginMode() {
return updateProfileFirstLoginMode;
}
public void setUpdateProfileFirstLogin(boolean updateProfileFirstLogin) {
this.updateProfileFirstLogin = updateProfileFirstLogin;
public void setUpdateProfileFirstLoginMode(String updateProfileFirstLoginMode) {
this.updateProfileFirstLoginMode = updateProfileFirstLoginMode;
}
public boolean isAuthenticateByDefault() {

View file

@ -325,7 +325,7 @@ public class ModelToRepresentation {
providerRep.setAlias(identityProviderModel.getAlias());
providerRep.setEnabled(identityProviderModel.isEnabled());
providerRep.setStoreToken(identityProviderModel.isStoreToken());
providerRep.setUpdateProfileFirstLogin(identityProviderModel.isUpdateProfileFirstLogin());
providerRep.setUpdateProfileFirstLoginMode(identityProviderModel.getUpdateProfileFirstLoginMode());
providerRep.setTrustEmail(identityProviderModel.isTrustEmail());
providerRep.setAuthenticateByDefault(identityProviderModel.isAuthenticateByDefault());
providerRep.setConfig(identityProviderModel.getConfig());

View file

@ -919,7 +919,7 @@ public class RepresentationToModel {
identityProviderModel.setAlias(representation.getAlias());
identityProviderModel.setProviderId(representation.getProviderId());
identityProviderModel.setEnabled(representation.isEnabled());
identityProviderModel.setUpdateProfileFirstLogin(representation.isUpdateProfileFirstLogin());
identityProviderModel.setUpdateProfileFirstLoginMode(representation.getUpdateProfileFirstLoginMode());
identityProviderModel.setTrustEmail(representation.isTrustEmail());
identityProviderModel.setAuthenticateByDefault(representation.isAuthenticateByDefault());
identityProviderModel.setStoreToken(representation.isStoreToken());

View file

@ -1164,7 +1164,7 @@ public class RealmAdapter implements RealmModel {
identityProviderModel.setInternalId(entity.getInternalId());
identityProviderModel.setConfig(entity.getConfig());
identityProviderModel.setEnabled(entity.isEnabled());
identityProviderModel.setUpdateProfileFirstLogin(entity.isUpdateProfileFirstLogin());
identityProviderModel.setUpdateProfileFirstLoginMode(entity.getUpdateProfileFirstLoginMode());
identityProviderModel.setTrustEmail(entity.isTrustEmail());
identityProviderModel.setAuthenticateByDefault(entity.isAuthenticateByDefault());
identityProviderModel.setStoreToken(entity.isStoreToken());
@ -1197,7 +1197,7 @@ public class RealmAdapter implements RealmModel {
entity.setEnabled(identityProvider.isEnabled());
entity.setStoreToken(identityProvider.isStoreToken());
entity.setAddReadTokenRoleOnCreate(identityProvider.isAddReadTokenRoleOnCreate());
entity.setUpdateProfileFirstLogin(identityProvider.isUpdateProfileFirstLogin());
entity.setUpdateProfileFirstLoginMode(identityProvider.getUpdateProfileFirstLoginMode());
entity.setTrustEmail(identityProvider.isTrustEmail());
entity.setAuthenticateByDefault(identityProvider.isAuthenticateByDefault());
entity.setConfig(identityProvider.getConfig());
@ -1224,7 +1224,7 @@ public class RealmAdapter implements RealmModel {
if (entity.getInternalId().equals(identityProvider.getInternalId())) {
entity.setAlias(identityProvider.getAlias());
entity.setEnabled(identityProvider.isEnabled());
entity.setUpdateProfileFirstLogin(identityProvider.isUpdateProfileFirstLogin());
entity.setUpdateProfileFirstLoginMode(identityProvider.getUpdateProfileFirstLoginMode());
entity.setTrustEmail(identityProvider.isTrustEmail());
entity.setAuthenticateByDefault(identityProvider.isAuthenticateByDefault());
entity.setAddReadTokenRoleOnCreate(identityProvider.isAddReadTokenRoleOnCreate());

View file

@ -41,8 +41,8 @@ public class IdentityProviderEntity {
@Column(name="ENABLED")
private boolean enabled;
@Column(name="UPDATE_PROFILE_FIRST_LOGIN")
private boolean updateProfileFirstLogin;
@Column(name = "UPDATE_PROFILE_FIRST_LOGIN_MODE")
private String updateProfileFirstLoginMode;
@Column(name = "TRUST_EMAIL")
private boolean trustEmail;
@ -102,12 +102,12 @@ public class IdentityProviderEntity {
this.enabled = enabled;
}
public boolean isUpdateProfileFirstLogin() {
return this.updateProfileFirstLogin;
public String getUpdateProfileFirstLoginMode() {
return updateProfileFirstLoginMode;
}
public void setUpdateProfileFirstLogin(boolean updateProfileFirstLogin) {
this.updateProfileFirstLogin = updateProfileFirstLogin;
public void setUpdateProfileFirstLoginMode(String updateProfileFirstLoginMode) {
this.updateProfileFirstLoginMode = updateProfileFirstLoginMode;
}
public boolean isStoreToken() {

View file

@ -782,7 +782,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
identityProviderModel.setInternalId(entity.getInternalId());
identityProviderModel.setConfig(entity.getConfig());
identityProviderModel.setEnabled(entity.isEnabled());
identityProviderModel.setUpdateProfileFirstLogin(entity.isUpdateProfileFirstLogin());
identityProviderModel.setUpdateProfileFirstLoginMode(entity.getUpdateProfileFirstLoginMode());
identityProviderModel.setTrustEmail(entity.isTrustEmail());
identityProviderModel.setAuthenticateByDefault(entity.isAuthenticateByDefault());
identityProviderModel.setStoreToken(entity.isStoreToken());
@ -813,7 +813,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
entity.setAlias(identityProvider.getAlias());
entity.setProviderId(identityProvider.getProviderId());
entity.setEnabled(identityProvider.isEnabled());
entity.setUpdateProfileFirstLogin(identityProvider.isUpdateProfileFirstLogin());
entity.setUpdateProfileFirstLoginMode(identityProvider.getUpdateProfileFirstLoginMode());
entity.setTrustEmail(identityProvider.isTrustEmail());
entity.setAddReadTokenRoleOnCreate(identityProvider.isAddReadTokenRoleOnCreate());
entity.setStoreToken(identityProvider.isStoreToken());
@ -826,7 +826,6 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
@Override
public void removeIdentityProviderByAlias(String alias) {
IdentityProviderEntity toRemove;
for (IdentityProviderEntity entity : realm.getIdentityProviders()) {
if (entity.getAlias().equals(alias)) {
realm.getIdentityProviders().remove(entity);
@ -842,7 +841,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
if (entity.getInternalId().equals(identityProvider.getInternalId())) {
entity.setAlias(identityProvider.getAlias());
entity.setEnabled(identityProvider.isEnabled());
entity.setUpdateProfileFirstLogin(identityProvider.isUpdateProfileFirstLogin());
entity.setUpdateProfileFirstLoginMode(identityProvider.getUpdateProfileFirstLoginMode());
entity.setTrustEmail(identityProvider.isTrustEmail());
entity.setAuthenticateByDefault(identityProvider.isAuthenticateByDefault());
entity.setAddReadTokenRoleOnCreate(identityProvider.isAddReadTokenRoleOnCreate());

View file

@ -443,7 +443,7 @@ public class AuthenticationManager {
Iterator<String> i = user.getRequiredActions().iterator();
String action = i.next();
if (action.equals(UserModel.RequiredAction.VERIFY_EMAIL.name()) && Validation.isEmpty(user.getEmail())) {
if (action.equals(UserModel.RequiredAction.VERIFY_EMAIL.name()) && Validation.isBlank(user.getEmail())) {
if (i.hasNext())
action = i.next();
else

View file

@ -580,7 +580,7 @@ public class AccountService {
String totp = formData.getFirst("totp");
String totpSecret = formData.getFirst("totpSecret");
if (Validation.isEmpty(totp)) {
if (Validation.isBlank(totp)) {
setReferrerOnPage();
return account.setError(Messages.MISSING_TOTP).createResponse(AccountPages.TOTP);
} else if (!new TimeBasedOTP().validate(totp, totpSecret.getBytes())) {
@ -640,7 +640,7 @@ public class AccountService {
String passwordConfirm = formData.getFirst("password-confirm");
if (requireCurrent) {
if (Validation.isEmpty(password)) {
if (Validation.isBlank(password)) {
setReferrerOnPage();
return account.setError(Messages.MISSING_PASSWORD).createResponse(AccountPages.PASSWORD);
}

View file

@ -44,10 +44,10 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.AuthenticationManager.AuthResult;
@ -71,6 +71,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -278,13 +279,14 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
try {
federatedUser = createUser(context);
if (identityProviderConfig.isUpdateProfileFirstLogin()) {
if (IdentityProviderRepresentation.UPFLM_ON.equals(identityProviderConfig.getUpdateProfileFirstLoginMode())
|| (IdentityProviderRepresentation.UPFLM_MISSING.equals(identityProviderConfig.getUpdateProfileFirstLoginMode()) && !Validation.validateUserMandatoryFields(realmModel, federatedUser))) {
if (isDebugEnabled()) {
LOGGER.debugf("Identity provider requires update profile action.", federatedUser);
}
federatedUser.addRequiredAction(UPDATE_PROFILE);
}
if(identityProviderConfig.isTrustEmail() && federatedUser.getEmail() != null && federatedUser.getEmail().trim().length()>0){
if(identityProviderConfig.isTrustEmail() && !Validation.isBlank(federatedUser.getEmail())){
federatedUser.setEmailVerified(true);
}
} catch (Exception e) {
@ -509,7 +511,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
String username = context.getModelUsername();
if (username == null) {
username = context.getUsername();
if (this.realmModel.isRegistrationEmailAsUsername() && !Validation.isEmpty(context.getEmail())) {
if (this.realmModel.isRegistrationEmailAsUsername() && !Validation.isBlank(context.getEmail())) {
username = context.getEmail();
} else if (username == null) {
username = context.getIdpConfig().getAlias() + "." + context.getId();

View file

@ -829,7 +829,7 @@ public class LoginActionsService {
String totpSecret = formData.getFirst("totpSecret");
LoginFormsProvider loginForms = session.getProvider(LoginFormsProvider.class).setUser(user);
if (Validation.isEmpty(totp)) {
if (Validation.isBlank(totp)) {
return loginForms.setError(Messages.MISSING_TOTP)
.setClientSessionCode(accessCode.getCode())
.createResponse(RequiredAction.CONFIGURE_TOTP);
@ -875,7 +875,7 @@ public class LoginActionsService {
LoginFormsProvider loginForms = session.getProvider(LoginFormsProvider.class)
.setUser(user);
if (Validation.isEmpty(passwordNew)) {
if (Validation.isBlank(passwordNew)) {
return loginForms.setError(Messages.MISSING_PASSWORD)
.setClientSessionCode(accessCode.getCode())
.createResponse(RequiredAction.UPDATE_PASSWORD);

View file

@ -2,11 +2,13 @@ package org.keycloak.services.validation;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.FormMessage;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.messages.Messages;
import javax.ws.rs.core.MultivaluedMap;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
@ -26,26 +28,26 @@ public class Validation {
public static List<FormMessage> validateRegistrationForm(RealmModel realm, MultivaluedMap<String, String> formData, List<String> requiredCredentialTypes, PasswordPolicy policy) {
List<FormMessage> errors = new ArrayList<>();
if (!realm.isRegistrationEmailAsUsername() && isEmpty(formData.getFirst(FIELD_USERNAME))) {
if (!realm.isRegistrationEmailAsUsername() && isBlank(formData.getFirst(FIELD_USERNAME))) {
addError(errors, FIELD_USERNAME, Messages.MISSING_USERNAME);
}
if (isEmpty(formData.getFirst(FIELD_FIRST_NAME))) {
if (isBlank(formData.getFirst(FIELD_FIRST_NAME))) {
addError(errors, FIELD_FIRST_NAME, Messages.MISSING_FIRST_NAME);
}
if (isEmpty(formData.getFirst(FIELD_LAST_NAME))) {
if (isBlank(formData.getFirst(FIELD_LAST_NAME))) {
addError(errors, FIELD_LAST_NAME, Messages.MISSING_LAST_NAME);
}
if (isEmpty(formData.getFirst(FIELD_EMAIL))) {
if (isBlank(formData.getFirst(FIELD_EMAIL))) {
addError(errors, FIELD_EMAIL, Messages.MISSING_EMAIL);
} else if (!isEmailValid(formData.getFirst(FIELD_EMAIL))) {
addError(errors, FIELD_EMAIL, Messages.INVALID_EMAIL);
}
if (requiredCredentialTypes.contains(CredentialRepresentation.PASSWORD)) {
if (isEmpty(formData.getFirst(FIELD_PASSWORD))) {
if (isBlank(formData.getFirst(FIELD_PASSWORD))) {
addError(errors, FIELD_PASSWORD, Messages.MISSING_PASSWORD);
} else if (!formData.getFirst(FIELD_PASSWORD).equals(formData.getFirst(FIELD_PASSWORD_CONFIRM))) {
addError(errors, FIELD_PASSWORD_CONFIRM, Messages.INVALID_PASSWORD_CONFIRM);
@ -72,19 +74,19 @@ public class Validation {
public static List<FormMessage> validateUpdateProfileForm(RealmModel realm, MultivaluedMap<String, String> formData) {
List<FormMessage> errors = new ArrayList<>();
if (realm != null && realm.isEditUsernameAllowed() && isEmpty(formData.getFirst(FIELD_USERNAME))) {
if (realm != null && realm.isEditUsernameAllowed() && isBlank(formData.getFirst(FIELD_USERNAME))) {
addError(errors, FIELD_USERNAME, Messages.MISSING_USERNAME);
}
if (isEmpty(formData.getFirst(FIELD_FIRST_NAME))) {
if (isBlank(formData.getFirst(FIELD_FIRST_NAME))) {
addError(errors, FIELD_FIRST_NAME, Messages.MISSING_FIRST_NAME);
}
if (isEmpty(formData.getFirst(FIELD_LAST_NAME))) {
if (isBlank(formData.getFirst(FIELD_LAST_NAME))) {
addError(errors, FIELD_LAST_NAME, Messages.MISSING_LAST_NAME);
}
if (isEmpty(formData.getFirst(FIELD_EMAIL))) {
if (isBlank(formData.getFirst(FIELD_EMAIL))) {
addError(errors, FIELD_EMAIL, Messages.MISSING_EMAIL);
} else if (!isEmailValid(formData.getFirst(FIELD_EMAIL))) {
addError(errors, FIELD_EMAIL, Messages.INVALID_EMAIL);
@ -93,10 +95,37 @@ public class Validation {
return errors;
}
/**
* Validate if user object contains all mandatory fields.
*
* @param realm user is for
* @param user to validate
* @return true if user object contains all mandatory values, false if some mandatory value is missing
*/
public static boolean validateUserMandatoryFields(RealmModel realm, UserModel user){
return!(isBlank(user.getFirstName()) || isBlank(user.getLastName()) || isBlank(user.getEmail()));
}
/**
* Check if string is empty (null or lenght is 0)
*
* @param s to check
* @return true if string is empty
*/
public static boolean isEmpty(String s) {
return s == null || s.length() == 0;
}
/**
* Check if string is blank (null or lenght is 0 or contains only white characters)
*
* @param s to check
* @return true if string is blank
*/
public static boolean isBlank(String s) {
return s == null || s.trim().length() == 0;
}
public static boolean isEmailValid(String email) {
return EMAIL_PATTERN.matcher(email).matches();
}

View file

@ -24,4 +24,26 @@ public class ValidationTest {
Assert.assertFalse(Validation.isEmailValid("abc@foo."));
Assert.assertFalse(Validation.isEmailValid("abc@foo..bar"));
}
@Test
public void testIsEmpty(){
Assert.assertTrue(Validation.isEmpty(null));
Assert.assertTrue(Validation.isEmpty(""));
Assert.assertFalse(Validation.isEmpty(" "));
Assert.assertFalse(Validation.isEmpty(" "));
Assert.assertFalse(Validation.isEmpty("a"));
Assert.assertFalse(Validation.isEmpty(" a "));
Assert.assertFalse(Validation.isEmpty("asgadfgedfs"));
}
@Test
public void testIsBlank(){
Assert.assertTrue(Validation.isBlank(null));
Assert.assertTrue(Validation.isBlank(""));
Assert.assertTrue(Validation.isBlank(" "));
Assert.assertTrue(Validation.isBlank(" \n "));
Assert.assertFalse(Validation.isBlank("a"));
Assert.assertFalse(Validation.isBlank(" a "));
Assert.assertFalse(Validation.isBlank("asgadfgedfs"));
}
}

View file

@ -52,7 +52,7 @@ public class IdentityProviderTest extends AbstractClientTest {
assertEquals("clientSecret", representation.getConfig().get("clientSecret"));
assertTrue(representation.isEnabled());
assertFalse(representation.isStoreToken());
assertTrue(representation.isUpdateProfileFirstLogin());
assertEquals(IdentityProviderRepresentation.UPFLM_ON, representation.getUpdateProfileFirstLoginMode());
assertFalse(representation.isTrustEmail());
}

View file

@ -34,6 +34,7 @@ import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserModel.RequiredAction;
import org.keycloak.representations.IDToken;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.services.Urls;
import org.keycloak.testsuite.MailUtil;
import org.keycloak.testsuite.OAuthClient;
@ -136,18 +137,34 @@ public abstract class AbstractIdentityProviderTest {
@Test
public void testSuccessfulAuthentication() {
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
identityProviderModel.setUpdateProfileFirstLogin(true);
identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_ON);
UserModel user = assertSuccessfulAuthentication(identityProviderModel, "test-user", "new@email.com");
UserModel user = assertSuccessfulAuthentication(identityProviderModel, "test-user", "new@email.com", true);
Assert.assertEquals("617-666-7777", user.getAttribute("mobile"));
}
@Test
public void testSuccessfulAuthenticationUpdateProfileOnMissing_nothingMissing() {
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_MISSING);
assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost", false);
}
@Test
public void testSuccessfulAuthenticationUpdateProfileOnMissing_missingEmail() {
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_MISSING);
assertSuccessfulAuthentication(identityProviderModel, "test-user-noemail", "new@email.com", true);
}
@Test
public void testSuccessfulAuthenticationWithoutUpdateProfile() {
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
identityProviderModel.setUpdateProfileFirstLogin(false);
identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF);
assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost");
assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost", false);
}
/**
@ -164,10 +181,10 @@ public abstract class AbstractIdentityProviderTest {
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
try {
identityProviderModel.setUpdateProfileFirstLogin(false);
identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF);
identityProviderModel.setTrustEmail(false);
UserModel federatedUser = assertSuccessfulAuthenticationWithEmailVerification(identityProviderModel, "test-user", "test-user@localhost");
UserModel federatedUser = assertSuccessfulAuthenticationWithEmailVerification(identityProviderModel, "test-user", "test-user@localhost", false);
// email is verified now
assertFalse(federatedUser.getRequiredActions().contains(RequiredAction.VERIFY_EMAIL.name()));
@ -177,9 +194,10 @@ public abstract class AbstractIdentityProviderTest {
}
}
private UserModel assertSuccessfulAuthenticationWithEmailVerification(IdentityProviderModel identityProviderModel, String username, String expectedEmail)
private UserModel assertSuccessfulAuthenticationWithEmailVerification(IdentityProviderModel identityProviderModel, String username, String expectedEmail,
boolean isProfileUpdateExpected)
throws IOException, MessagingException {
authenticateWithIdentityProvider(identityProviderModel, username);
authenticateWithIdentityProvider(identityProviderModel, username, isProfileUpdateExpected);
// verify email is sent
Assert.assertTrue(verifyEmailPage.isCurrent());
@ -199,7 +217,7 @@ public abstract class AbstractIdentityProviderTest {
assertNotNull(federatedUser);
doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail);
doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail, isProfileUpdateExpected);
brokerServerRule.stopSession(session, true);
session = brokerServerRule.startSession();
@ -233,9 +251,9 @@ public abstract class AbstractIdentityProviderTest {
try {
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
identityProviderModel.setUpdateProfileFirstLogin(false);
identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF);
UserModel federatedUser = assertSuccessfulAuthentication(identityProviderModel, "test-user-noemail", null);
UserModel federatedUser = assertSuccessfulAuthentication(identityProviderModel, "test-user-noemail", null, false);
assertTrue(federatedUser.getRequiredActions().contains(RequiredAction.VERIFY_EMAIL.name()));
@ -255,10 +273,10 @@ public abstract class AbstractIdentityProviderTest {
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
try {
identityProviderModel.setUpdateProfileFirstLogin(false);
identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF);
identityProviderModel.setTrustEmail(true);
UserModel federatedUser = assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost");
UserModel federatedUser = assertSuccessfulAuthentication(identityProviderModel, "test-user", "test-user@localhost", false);
assertFalse(federatedUser.getRequiredActions().contains(RequiredAction.VERIFY_EMAIL.name()));
@ -282,10 +300,10 @@ public abstract class AbstractIdentityProviderTest {
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
try {
identityProviderModel.setUpdateProfileFirstLogin(true);
identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_ON);
identityProviderModel.setTrustEmail(true);
UserModel user = assertSuccessfulAuthenticationWithEmailVerification(identityProviderModel, "test-user", "new@email.com");
UserModel user = assertSuccessfulAuthenticationWithEmailVerification(identityProviderModel, "test-user", "new@email.com", true);
Assert.assertEquals("617-666-7777", user.getAttribute("mobile"));
} finally {
identityProviderModel.setTrustEmail(false);
@ -302,9 +320,9 @@ public abstract class AbstractIdentityProviderTest {
try {
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
identityProviderModel.setUpdateProfileFirstLogin(false);
identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF);
authenticateWithIdentityProvider(identityProviderModel, "test-user");
authenticateWithIdentityProvider(identityProviderModel, "test-user", false);
// authenticated and redirected to app
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
@ -321,7 +339,7 @@ public abstract class AbstractIdentityProviderTest {
assertEquals("test-user@localhost", federatedUser.getUsername());
doAssertFederatedUser(federatedUser, identityProviderModel, "test-user@localhost");
doAssertFederatedUser(federatedUser, identityProviderModel, "test-user@localhost", false);
Set<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm);
@ -350,9 +368,9 @@ public abstract class AbstractIdentityProviderTest {
try {
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
identityProviderModel.setUpdateProfileFirstLogin(false);
identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF);
authenticateWithIdentityProvider(identityProviderModel, "test-user-noemail");
authenticateWithIdentityProvider(identityProviderModel, "test-user-noemail", false);
brokerServerRule.stopSession(session, true);
session = brokerServerRule.startSession();
@ -455,7 +473,7 @@ public abstract class AbstractIdentityProviderTest {
public void testUserAlreadyExistsWhenNotUpdatingProfile() {
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
identityProviderModel.setUpdateProfileFirstLogin(false);
identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF);
this.driver.navigate().to("http://localhost:8081/test-app/");
@ -593,7 +611,7 @@ public abstract class AbstractIdentityProviderTest {
identityProviderModel.setStoreToken(true);
authenticateWithIdentityProvider(identityProviderModel, "test-user");
authenticateWithIdentityProvider(identityProviderModel, "test-user", true);
UserModel federatedUser = getFederatedUser();
RealmModel realm = getRealm();
@ -658,17 +676,18 @@ public abstract class AbstractIdentityProviderTest {
protected abstract void doAssertTokenRetrieval(String pageSource);
private UserModel assertSuccessfulAuthentication(IdentityProviderModel identityProviderModel, String username, String expectedEmail) {
authenticateWithIdentityProvider(identityProviderModel, username);
private UserModel assertSuccessfulAuthentication(IdentityProviderModel identityProviderModel, String username, String expectedEmail, boolean isProfileUpdateExpected) {
authenticateWithIdentityProvider(identityProviderModel, username, isProfileUpdateExpected);
// authenticated and redirected to app
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
assertTrue("Bad current URL " + this.driver.getCurrentUrl() + " and page source: " + this.driver.getPageSource(),
this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
UserModel federatedUser = getFederatedUser();
assertNotNull(federatedUser);
doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail);
doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail, isProfileUpdateExpected);
brokerServerRule.stopSession(session, true);
session = brokerServerRule.startSession();
@ -691,11 +710,11 @@ public abstract class AbstractIdentityProviderTest {
return federatedUser;
}
private void authenticateWithIdentityProvider(IdentityProviderModel identityProviderModel, String username) {
private void authenticateWithIdentityProvider(IdentityProviderModel identityProviderModel, String username, boolean isProfileUpdateExpected) {
loginIDP(username);
if (identityProviderModel.isUpdateProfileFirstLogin()) {
if (isProfileUpdateExpected) {
String userEmail = "new@email.com";
String userFirstName = "New first";
String userLastName = "New last";
@ -704,6 +723,7 @@ public abstract class AbstractIdentityProviderTest {
this.updateProfilePage.assertCurrent();
this.updateProfilePage.update(userFirstName, userLastName, userEmail);
}
}
private void loginIDP(String username) {
@ -749,7 +769,7 @@ public abstract class AbstractIdentityProviderTest {
assertNotNull(identityProviderModel);
identityProviderModel.setUpdateProfileFirstLogin(true);
identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_ON);
identityProviderModel.setEnabled(true);
return identityProviderModel;
@ -759,8 +779,8 @@ public abstract class AbstractIdentityProviderTest {
return this.session.realms().getRealm("realm-with-broker");
}
protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail) {
if (identityProviderModel.isUpdateProfileFirstLogin()) {
protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail, boolean isProfileUpdateExpected) {
if (isProfileUpdateExpected) {
String userFirstName = "New first";
String userLastName = "New last";

View file

@ -33,6 +33,7 @@ import org.keycloak.broker.saml.SAMLIdentityProviderFactory;
import org.keycloak.models.ClientModel;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.RealmModel;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.social.facebook.FacebookIdentityProvider;
import org.keycloak.social.facebook.FacebookIdentityProviderFactory;
@ -80,7 +81,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
identityProviderModel.getConfig().put("config-added", "value-added");
identityProviderModel.setEnabled(false);
identityProviderModel.setUpdateProfileFirstLogin(false);
identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_OFF);
identityProviderModel.setTrustEmail(true);
identityProviderModel.setStoreToken(true);
identityProviderModel.setAuthenticateByDefault(true);
@ -95,14 +96,14 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertEquals("value-added", identityProviderModel.getConfig().get("config-added"));
assertFalse(identityProviderModel.isEnabled());
assertFalse(identityProviderModel.isUpdateProfileFirstLogin());
assertEquals(IdentityProviderRepresentation.UPFLM_OFF, identityProviderModel.getUpdateProfileFirstLoginMode());
assertTrue(identityProviderModel.isTrustEmail());
assertTrue(identityProviderModel.isStoreToken());
assertTrue(identityProviderModel.isAuthenticateByDefault());
identityProviderModel.getConfig().remove("config-added");
identityProviderModel.setEnabled(true);
identityProviderModel.setUpdateProfileFirstLogin(true);
identityProviderModel.setUpdateProfileFirstLoginMode(IdentityProviderRepresentation.UPFLM_MISSING);
identityProviderModel.setTrustEmail(false);
identityProviderModel.setAuthenticateByDefault(false);
@ -115,7 +116,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertFalse(identityProviderModel.getConfig().containsKey("config-added"));
assertTrue(identityProviderModel.isEnabled());
assertTrue(identityProviderModel.isUpdateProfileFirstLogin());
assertEquals(IdentityProviderRepresentation.UPFLM_MISSING, identityProviderModel.getUpdateProfileFirstLoginMode());
assertFalse(identityProviderModel.isTrustEmail());
assertFalse(identityProviderModel.isAuthenticateByDefault());
this.realmManager.removeRealm(realm);
@ -164,7 +165,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertEquals("model-google", config.getAlias());
assertEquals(GoogleIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
assertEquals(true, config.isEnabled());
assertEquals(true, config.isUpdateProfileFirstLogin());
assertEquals(IdentityProviderRepresentation.UPFLM_ON, config.getUpdateProfileFirstLoginMode());
assertEquals(true, config.isTrustEmail());
assertEquals(false, config.isAuthenticateByDefault());
assertEquals(true, config.isStoreToken());
@ -183,7 +184,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertEquals("model-saml-signed-idp", config.getAlias());
assertEquals(SAMLIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
assertEquals(true, config.isEnabled());
assertEquals(true, config.isUpdateProfileFirstLogin());
assertEquals(IdentityProviderRepresentation.UPFLM_ON, config.getUpdateProfileFirstLoginMode());
assertEquals(false, config.isAuthenticateByDefault());
assertEquals(false, config.isTrustEmail());
assertEquals(false, config.isStoreToken());
@ -204,7 +205,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertEquals("model-oidc-idp", config.getAlias());
assertEquals(OIDCIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
assertEquals(false, config.isEnabled());
assertEquals(false, config.isUpdateProfileFirstLogin());
assertEquals(IdentityProviderRepresentation.UPFLM_OFF, config.getUpdateProfileFirstLoginMode());
assertEquals(false, config.isTrustEmail());
assertEquals(false, config.isAuthenticateByDefault());
assertEquals(false, config.isStoreToken());
@ -219,7 +220,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertEquals("model-facebook", config.getAlias());
assertEquals(FacebookIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
assertEquals(true, config.isEnabled());
assertEquals(true, config.isUpdateProfileFirstLogin());
assertEquals(IdentityProviderRepresentation.UPFLM_OFF, config.getUpdateProfileFirstLoginMode());
assertEquals(false, config.isTrustEmail());
assertEquals(false, config.isAuthenticateByDefault());
assertEquals(false, config.isStoreToken());
@ -237,7 +238,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertEquals("model-github", config.getAlias());
assertEquals(GitHubIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
assertEquals(true, config.isEnabled());
assertEquals(true, config.isUpdateProfileFirstLogin());
assertEquals(IdentityProviderRepresentation.UPFLM_ON, config.getUpdateProfileFirstLoginMode());
assertEquals(false, config.isTrustEmail());
assertEquals(false, config.isAuthenticateByDefault());
assertEquals(false, config.isStoreToken());
@ -255,7 +256,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertEquals("model-linkedin", config.getAlias());
assertEquals(LinkedInIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
assertEquals(true, config.isEnabled());
assertEquals(true, config.isUpdateProfileFirstLogin());
assertEquals(IdentityProviderRepresentation.UPFLM_MISSING, config.getUpdateProfileFirstLoginMode());
assertEquals(false, config.isTrustEmail());
assertEquals(false, config.isAuthenticateByDefault());
assertEquals(false, config.isStoreToken());
@ -273,7 +274,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertEquals("model-stackoverflow", config.getAlias());
assertEquals(StackoverflowIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
assertEquals(true, config.isEnabled());
assertEquals(false, config.isUpdateProfileFirstLogin());
assertEquals(IdentityProviderRepresentation.UPFLM_OFF, config.getUpdateProfileFirstLoginMode());
assertEquals(false, config.isTrustEmail());
assertEquals(false, config.isAuthenticateByDefault());
assertEquals(false, config.isStoreToken());
@ -292,7 +293,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertEquals("model-twitter", config.getAlias());
assertEquals(TwitterIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
assertEquals(true, config.isEnabled());
assertEquals(true, config.isUpdateProfileFirstLogin());
assertEquals(IdentityProviderRepresentation.UPFLM_OFF, config.getUpdateProfileFirstLoginMode());
assertEquals(false, config.isTrustEmail());
assertEquals(false, config.isAuthenticateByDefault());
assertEquals(true, config.isStoreToken());

View file

@ -6,6 +6,7 @@ import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
import org.keycloak.testsuite.KeycloakServer;
@ -50,9 +51,9 @@ public class SAMLKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderT
}
@Override
protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail) {
if (identityProviderModel.isUpdateProfileFirstLogin()) {
super.doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail);
protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail, boolean isProfileUpdateExpected) {
if (isProfileUpdateExpected) {
super.doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail, isProfileUpdateExpected);
} else {
if (expectedEmail == null) {
// Need to handle differences for various databases (like Oracle)
@ -114,4 +115,9 @@ public class SAMLKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderT
public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername() {
super.testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername();
}
@Test
public void testSuccessfulAuthenticationUpdateProfileOnMissing_nothingMissing() {
// skip this test as this provider do not return name and surname so something is missing always
}
}

View file

@ -6,6 +6,7 @@ import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
import org.keycloak.testsuite.KeycloakServer;
@ -50,9 +51,9 @@ public class SAMLKeyCloakServerBrokerWithSignatureTest extends AbstractIdentityP
}
@Override
protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail) {
if (identityProviderModel.isUpdateProfileFirstLogin()) {
super.doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail);
protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail, boolean isProfileUpdateExpected) {
if (isProfileUpdateExpected) {
super.doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail, isProfileUpdateExpected);
} else {
if (expectedEmail == null) {
// Need to handle differences for various databases (like Oracle)
@ -102,4 +103,9 @@ public class SAMLKeyCloakServerBrokerWithSignatureTest extends AbstractIdentityP
public void testAccountManagementLinkIdentity() {
super.testAccountManagementLinkIdentity();
}
@Test
public void testSuccessfulAuthenticationUpdateProfileOnMissing_nothingMissing() {
// skip this test as this provider do not return name and surname so something is missing always
}
}

View file

@ -29,7 +29,7 @@
"alias" : "model-facebook",
"providerId" : "facebook",
"enabled": true,
"updateProfileFirstLogin" : "true",
"updateProfileFirstLogin" : "false",
"config": {
"authorizationUrl": "authorizationUrl",
"tokenUrl": "tokenUrl",
@ -42,7 +42,7 @@
"alias" : "model-github",
"providerId" : "github",
"enabled": true,
"updateProfileFirstLogin" : "true",
"updateProfileFirstLoginMode" : "on",
"storeToken": "false",
"config": {
"authorizationUrl": "authorizationUrl",
@ -56,7 +56,7 @@
"alias" : "model-twitter",
"providerId" : "twitter",
"enabled": true,
"updateProfileFirstLogin" : "true",
"updateProfileFirstLoginMode" : "off",
"storeToken": true,
"config": {
"authorizationUrl": "authorizationUrl",
@ -70,7 +70,7 @@
"alias" : "model-linkedin",
"providerId" : "linkedin",
"enabled": true,
"updateProfileFirstLogin" : "true",
"updateProfileFirstLoginMode" : "missing",
"storeToken": false,
"config": {
"authorizationUrl": "authorizationUrl",
@ -84,7 +84,7 @@
"alias" : "model-stackoverflow",
"providerId" : "stackoverflow",
"enabled": true,
"updateProfileFirstLogin" : "false",
"updateProfileFirstLoginMode" : "off",
"storeToken": false,
"config": {
"key": "keyValue",
@ -99,7 +99,7 @@
"alias" : "model-saml-signed-idp",
"providerId" : "saml",
"enabled": true,
"updateProfileFirstLogin" : "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",
@ -115,7 +115,7 @@
"alias" : "kc-saml-signed-idp",
"providerId" : "saml",
"enabled": true,
"updateProfileFirstLogin" : true,
"updateProfileFirstLoginMode" : "on",
"addReadTokenRoleOnCreate": true,
"config": {
"singleSignOnServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-signed-idp/protocol/saml",
@ -134,7 +134,7 @@
"alias" : "kc-saml-idp-basic",
"providerId" : "saml",
"enabled": true,
"updateProfileFirstLogin" : true,
"updateProfileFirstLoginMode" : "on",
"trustEmail" : false,
"addReadTokenRoleOnCreate": true,
"config": {
@ -150,7 +150,7 @@
"alias" : "model-oidc-idp",
"providerId" : "oidc",
"enabled": false,
"updateProfileFirstLogin" : "false",
"updateProfileFirstLoginMode" : "off",
"authenticateByDefault" : "false",
"config": {
"clientId": "clientId",
@ -166,7 +166,7 @@
"alias" : "kc-oidc-idp",
"providerId" : "keycloak-oidc",
"enabled": true,
"updateProfileFirstLogin" : "false",
"updateProfileFirstLoginMode" : "off",
"storeToken" : true,
"addReadTokenRoleOnCreate": true,
"config": {