KEYCLOAK-1372 - do not perform email verification if email is provided

by trusted Identity provider
This commit is contained in:
Vlastimil Elias 2015-06-02 14:59:29 +02:00
parent 483ac69c47
commit b86d091ad1
18 changed files with 106 additions and 2 deletions

View file

@ -107,6 +107,9 @@
<addColumn tableName="CLIENT_SESSION">
<column name="AUTH_USER_ID" type="VARCHAR(36)"/>
</addColumn>
<addColumn tableName="IDENTITY_PROVIDER">
<column name="TRUST_EMAIL" type="BOOLEAN" defaultValueBoolean="false"/>
</addColumn>
<addColumn tableName="USER_REQUIRED_ACTION">
<column name="REQUIRED_ACTION" type="VARCHAR(36)">
<constraints nullable="false"/>

View file

@ -30,6 +30,7 @@ public class IdentityProviderRepresentation {
protected String providerId;
protected boolean enabled = true;
protected boolean updateProfileFirstLogin = true;
protected boolean trustEmail;
protected boolean storeToken;
protected boolean addReadTokenRoleOnCreate;
protected boolean authenticateByDefault;
@ -106,4 +107,13 @@ public class IdentityProviderRepresentation {
public void setAddReadTokenRoleOnCreate(boolean addReadTokenRoleOnCreate) {
this.addReadTokenRoleOnCreate = addReadTokenRoleOnCreate;
}
public boolean isTrustEmail() {
return trustEmail;
}
public void setTrustEmail(boolean trustEmail) {
this.trustEmail = trustEmail;
}
}

View file

@ -305,6 +305,16 @@
during the authentication process.
</entry>
</row>
<row>
<entry>
<literal>Trust email</literal>
</entry>
<entry>
Allows you to trust email address returned from the social provider. If enabled then email address returned by the provider
is marked as 'verified' in the Keycloak user profile. This means that email verification step is skipped even
if "Verify email" feature is enabled in realm settings.
</entry>
</row>
<row>
<entry>
<literal>GUI order</literal>

View file

@ -65,6 +65,13 @@
</div>
<kc-tooltip>Indicates if user must 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>
<div class="col-md-6">
<input ng-model="identityProvider.trustEmail" name="identityProvider.trustEmail" id="trustEmail" onoffswitch />
</div>
<kc-tooltip>If enabled then email provided by this provider is not verified even if verification is enabled for the realm.</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="guiOrder">GUI order</label>
<div class="col-md-6">

View file

@ -66,6 +66,13 @@
</div>
<kc-tooltip>Indicates if user must 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>
<div class="col-md-6">
<input ng-model="identityProvider.trustEmail" name="identityProvider.trustEmail" id="trustEmail" onoffswitch />
</div>
<kc-tooltip>If enabled then email provided by this provider is not verified even if verification is enabled for the realm.</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="guiOrder">GUI order</label>
<div class="col-md-6">

View file

@ -76,6 +76,13 @@
</div>
<kc-tooltip>Indicates if user must 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>
<div class="col-md-6">
<input ng-model="identityProvider.trustEmail" name="identityProvider.trustEmail" id="trustEmail" onoffswitch />
</div>
<kc-tooltip>If enabled then email provided by this provider is not verified even if verification is enabled for the realm.</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="authenticateByDefault">Authenticate By Default</label>
<div class="col-md-6">

View file

@ -45,6 +45,8 @@ public class IdentityProviderModel {
private boolean updateProfileFirstLogin = true;
private boolean trustEmail;
private boolean storeToken;
protected boolean addReadTokenRoleOnCreate;
@ -69,6 +71,7 @@ public class IdentityProviderModel {
this.config = new HashMap<String, String>(model.getConfig());
this.enabled = model.isEnabled();
this.updateProfileFirstLogin = model.isUpdateProfileFirstLogin();
this.trustEmail = model.isTrustEmail();
this.storeToken = model.isStoreToken();
this.authenticateByDefault = model.isAuthenticateByDefault();
this.addReadTokenRoleOnCreate = model.addReadTokenRoleOnCreate;
@ -145,4 +148,13 @@ public class IdentityProviderModel {
public void setAddReadTokenRoleOnCreate(boolean addReadTokenRoleOnCreate) {
this.addReadTokenRoleOnCreate = addReadTokenRoleOnCreate;
}
public boolean isTrustEmail() {
return trustEmail;
}
public void setTrustEmail(boolean trustEmail) {
this.trustEmail = trustEmail;
}
}

View file

@ -31,6 +31,7 @@ public class IdentityProviderEntity {
private String name;
private boolean enabled;
private boolean updateProfileFirstLogin;
private boolean trustEmail;
private boolean storeToken;
protected boolean addReadTokenRoleOnCreate;
private boolean authenticateByDefault;
@ -116,4 +117,12 @@ public class IdentityProviderEntity {
public void setAddReadTokenRoleOnCreate(boolean addReadTokenRoleOnCreate) {
this.addReadTokenRoleOnCreate = addReadTokenRoleOnCreate;
}
public boolean isTrustEmail() {
return trustEmail;
}
public void setTrustEmail(boolean trustEmail) {
this.trustEmail = trustEmail;
}
}

View file

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

View file

@ -918,6 +918,7 @@ public class RepresentationToModel {
identityProviderModel.setProviderId(representation.getProviderId());
identityProviderModel.setEnabled(representation.isEnabled());
identityProviderModel.setUpdateProfileFirstLogin(representation.isUpdateProfileFirstLogin());
identityProviderModel.setTrustEmail(representation.isTrustEmail());
identityProviderModel.setAuthenticateByDefault(representation.isAuthenticateByDefault());
identityProviderModel.setStoreToken(representation.isStoreToken());
identityProviderModel.setAddReadTokenRoleOnCreate(representation.isAddReadTokenRoleOnCreate());

View file

@ -1154,6 +1154,7 @@ public class RealmAdapter implements RealmModel {
identityProviderModel.setConfig(entity.getConfig());
identityProviderModel.setEnabled(entity.isEnabled());
identityProviderModel.setUpdateProfileFirstLogin(entity.isUpdateProfileFirstLogin());
identityProviderModel.setTrustEmail(entity.isTrustEmail());
identityProviderModel.setAuthenticateByDefault(entity.isAuthenticateByDefault());
identityProviderModel.setStoreToken(entity.isStoreToken());
identityProviderModel.setAddReadTokenRoleOnCreate(entity.isAddReadTokenRoleOnCreate());
@ -1186,6 +1187,7 @@ public class RealmAdapter implements RealmModel {
entity.setStoreToken(identityProvider.isStoreToken());
entity.setAddReadTokenRoleOnCreate(identityProvider.isAddReadTokenRoleOnCreate());
entity.setUpdateProfileFirstLogin(identityProvider.isUpdateProfileFirstLogin());
entity.setTrustEmail(identityProvider.isTrustEmail());
entity.setAuthenticateByDefault(identityProvider.isAuthenticateByDefault());
entity.setConfig(identityProvider.getConfig());
@ -1212,6 +1214,7 @@ public class RealmAdapter implements RealmModel {
entity.setAlias(identityProvider.getAlias());
entity.setEnabled(identityProvider.isEnabled());
entity.setUpdateProfileFirstLogin(identityProvider.isUpdateProfileFirstLogin());
entity.setTrustEmail(identityProvider.isTrustEmail());
entity.setAuthenticateByDefault(identityProvider.isAuthenticateByDefault());
entity.setAddReadTokenRoleOnCreate(identityProvider.isAddReadTokenRoleOnCreate());
entity.setStoreToken(identityProvider.isStoreToken());

View file

@ -44,6 +44,9 @@ public class IdentityProviderEntity {
@Column(name="UPDATE_PROFILE_FIRST_LOGIN")
private boolean updateProfileFirstLogin;
@Column(name = "TRUST_EMAIL")
private boolean trustEmail;
@Column(name="STORE_TOKEN")
private boolean storeToken;
@ -138,4 +141,12 @@ public class IdentityProviderEntity {
public void setAddReadTokenRoleOnCreate(boolean addReadTokenRoleOnCreate) {
this.addReadTokenRoleOnCreate = addReadTokenRoleOnCreate;
}
public boolean isTrustEmail() {
return trustEmail;
}
public void setTrustEmail(boolean trustEmail) {
this.trustEmail = trustEmail;
}
}

View file

@ -772,6 +772,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
identityProviderModel.setConfig(entity.getConfig());
identityProviderModel.setEnabled(entity.isEnabled());
identityProviderModel.setUpdateProfileFirstLogin(entity.isUpdateProfileFirstLogin());
identityProviderModel.setTrustEmail(entity.isTrustEmail());
identityProviderModel.setAuthenticateByDefault(entity.isAuthenticateByDefault());
identityProviderModel.setStoreToken(entity.isStoreToken());
identityProviderModel.setAddReadTokenRoleOnCreate(entity.isAddReadTokenRoleOnCreate());
@ -802,6 +803,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
entity.setProviderId(identityProvider.getProviderId());
entity.setEnabled(identityProvider.isEnabled());
entity.setUpdateProfileFirstLogin(identityProvider.isUpdateProfileFirstLogin());
entity.setTrustEmail(identityProvider.isTrustEmail());
entity.setAddReadTokenRoleOnCreate(identityProvider.isAddReadTokenRoleOnCreate());
entity.setStoreToken(identityProvider.isStoreToken());
entity.setAuthenticateByDefault(identityProvider.isAuthenticateByDefault());
@ -830,6 +832,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
entity.setAlias(identityProvider.getAlias());
entity.setEnabled(identityProvider.isEnabled());
entity.setUpdateProfileFirstLogin(identityProvider.isUpdateProfileFirstLogin());
entity.setTrustEmail(identityProvider.isTrustEmail());
entity.setAuthenticateByDefault(identityProvider.isAuthenticateByDefault());
entity.setAddReadTokenRoleOnCreate(identityProvider.isAddReadTokenRoleOnCreate());
entity.setStoreToken(identityProvider.isStoreToken());

View file

@ -284,6 +284,9 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
}
federatedUser.addRequiredAction(UPDATE_PROFILE);
}
if(identityProviderConfig.isTrustEmail() && federatedUser.getEmail() != null && federatedUser.getEmail().trim().length()>0){
federatedUser.setEmailVerified(true);
}
} catch (Exception e) {
return redirectToLoginPage(e, clientCode);
}

View file

@ -53,6 +53,7 @@ public class IdentityProviderTest extends AbstractClientTest {
assertTrue(representation.isEnabled());
assertFalse(representation.isStoreToken());
assertTrue(representation.isUpdateProfileFirstLogin());
assertFalse(representation.isTrustEmail());
}
@Test

View file

@ -81,6 +81,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
identityProviderModel.getConfig().put("config-added", "value-added");
identityProviderModel.setEnabled(false);
identityProviderModel.setUpdateProfileFirstLogin(false);
identityProviderModel.setTrustEmail(true);
identityProviderModel.setStoreToken(true);
identityProviderModel.setAuthenticateByDefault(true);
@ -95,12 +96,14 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertEquals("value-added", identityProviderModel.getConfig().get("config-added"));
assertFalse(identityProviderModel.isEnabled());
assertFalse(identityProviderModel.isUpdateProfileFirstLogin());
assertTrue(identityProviderModel.isTrustEmail());
assertTrue(identityProviderModel.isStoreToken());
assertTrue(identityProviderModel.isAuthenticateByDefault());
identityProviderModel.getConfig().remove("config-added");
identityProviderModel.setEnabled(true);
identityProviderModel.setUpdateProfileFirstLogin(true);
identityProviderModel.setTrustEmail(false);
identityProviderModel.setAuthenticateByDefault(false);
realm.updateIdentityProvider(identityProviderModel);
@ -113,6 +116,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertFalse(identityProviderModel.getConfig().containsKey("config-added"));
assertTrue(identityProviderModel.isEnabled());
assertTrue(identityProviderModel.isUpdateProfileFirstLogin());
assertFalse(identityProviderModel.isTrustEmail());
assertFalse(identityProviderModel.isAuthenticateByDefault());
this.realmManager.removeRealm(realm);
}
@ -161,6 +165,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertEquals(GoogleIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
assertEquals(true, config.isEnabled());
assertEquals(true, config.isUpdateProfileFirstLogin());
assertEquals(true, config.isTrustEmail());
assertEquals(false, config.isAuthenticateByDefault());
assertEquals(true, config.isStoreToken());
assertEquals("clientId", config.getClientId());
@ -180,6 +185,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertEquals(true, config.isEnabled());
assertEquals(true, config.isUpdateProfileFirstLogin());
assertEquals(false, config.isAuthenticateByDefault());
assertEquals(false, config.isTrustEmail());
assertEquals(false, config.isStoreToken());
assertEquals("http://localhost:8082/auth/realms/realm-with-saml-identity-provider/protocol/saml", config.getSingleSignOnServiceUrl());
assertEquals("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", config.getNameIDPolicyFormat());
@ -199,6 +205,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertEquals(OIDCIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
assertEquals(false, config.isEnabled());
assertEquals(false, config.isUpdateProfileFirstLogin());
assertEquals(false, config.isTrustEmail());
assertEquals(false, config.isAuthenticateByDefault());
assertEquals(false, config.isStoreToken());
assertEquals("clientId", config.getClientId());
@ -213,6 +220,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertEquals(FacebookIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
assertEquals(true, config.isEnabled());
assertEquals(true, config.isUpdateProfileFirstLogin());
assertEquals(false, config.isTrustEmail());
assertEquals(false, config.isAuthenticateByDefault());
assertEquals(false, config.isStoreToken());
assertEquals("clientId", config.getClientId());
@ -230,6 +238,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertEquals(GitHubIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
assertEquals(true, config.isEnabled());
assertEquals(true, config.isUpdateProfileFirstLogin());
assertEquals(false, config.isTrustEmail());
assertEquals(false, config.isAuthenticateByDefault());
assertEquals(false, config.isStoreToken());
assertEquals("clientId", config.getClientId());
@ -247,6 +256,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertEquals(LinkedInIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
assertEquals(true, config.isEnabled());
assertEquals(true, config.isUpdateProfileFirstLogin());
assertEquals(false, config.isTrustEmail());
assertEquals(false, config.isAuthenticateByDefault());
assertEquals(false, config.isStoreToken());
assertEquals("clientId", config.getClientId());
@ -263,7 +273,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertEquals("model-stackoverflow", config.getAlias());
assertEquals(StackoverflowIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
assertEquals(true, config.isEnabled());
assertEquals(true, config.isUpdateProfileFirstLogin());
assertEquals(false, config.isUpdateProfileFirstLogin());
assertEquals(false, config.isTrustEmail());
assertEquals(false, config.isAuthenticateByDefault());
assertEquals(false, config.isStoreToken());
assertEquals("clientId", config.getClientId());
@ -282,6 +293,7 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertEquals(TwitterIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
assertEquals(true, config.isEnabled());
assertEquals(true, config.isUpdateProfileFirstLogin());
assertEquals(false, config.isTrustEmail());
assertEquals(false, config.isAuthenticateByDefault());
assertEquals(true, config.isStoreToken());
assertEquals("clientId", config.getClientId());

View file

@ -57,8 +57,10 @@ public class SAMLKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderT
if (expectedEmail == null) {
// Need to handle differences for various databases (like Oracle)
assertTrue(federatedUser.getEmail() == null || federatedUser.getEmail().equals(""));
assertFalse(federatedUser.isEmailVerified());
} else {
assertEquals(expectedEmail, federatedUser.getEmail());
assertTrue(federatedUser.isEmailVerified());
}
assertNull(federatedUser.getFirstName());
assertNull(federatedUser.getLastName());

View file

@ -13,6 +13,7 @@
"providerId" : "google",
"enabled": true,
"updateProfileFirstLogin" : "true",
"trustEmail" : "true",
"storeToken": "true",
"config": {
"clientId": "clientId",
@ -78,7 +79,7 @@
"alias" : "model-stackoverflow",
"providerId" : "stackoverflow",
"enabled": true,
"updateProfileFirstLogin" : "true",
"updateProfileFirstLogin" : "false",
"storeToken": false,
"config": {
"key": "keyValue",
@ -129,6 +130,7 @@
"providerId" : "saml",
"enabled": true,
"updateProfileFirstLogin" : true,
"trustEmail" : true,
"addReadTokenRoleOnCreate": true,
"config": {
"singleSignOnServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-idp-basic/protocol/saml",