KEYCLOAK-1372 - do not perform email verification if email is provided
by trusted Identity provider
This commit is contained in:
parent
483ac69c47
commit
b86d091ad1
18 changed files with 106 additions and 2 deletions
|
@ -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"/>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -44,6 +44,8 @@ public class IdentityProviderModel {
|
|||
private boolean enabled;
|
||||
|
||||
private boolean updateProfileFirstLogin = true;
|
||||
|
||||
private boolean trustEmail;
|
||||
|
||||
private boolean storeToken;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ public class IdentityProviderTest extends AbstractClientTest {
|
|||
assertTrue(representation.isEnabled());
|
||||
assertFalse(representation.isStoreToken());
|
||||
assertTrue(representation.isUpdateProfileFirstLogin());
|
||||
assertFalse(representation.isTrustEmail());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in a new issue