diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/user-social-links.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/user-federated-identity.html
old mode 100755
new mode 100644
similarity index 63%
rename from forms/common-themes/src/main/resources/theme/admin/base/resources/partials/user-social-links.html
rename to forms/common-themes/src/main/resources/theme/admin/base/resources/partials/user-federated-identity.html
index 3bb9ef28fc..845be1f428
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/user-social-links.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/user-federated-identity.html
@@ -5,26 +5,26 @@
- Users
- {{user.username}}
- - Social Links
+ - Federated Identities
-
User {{user.username}} Social Links
+
User {{user.username}} Federated Identities
- Provider Name |
- Social Username |
+ Identity Provider Name |
+ Username |
-
- {{socialLink.socialProvider}} |
- {{socialLink.socialUsername}} |
+
+ {{identity.identityProvider}} |
+ {{identity.userName}} |
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/user-sessions.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/user-sessions.html
index 26fbab2c9c..a2a8ee09d4 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/user-sessions.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/user-sessions.html
@@ -5,7 +5,7 @@
Credentials
Role Mappings
Sessions
-
Social Links
+
Federated Identities
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/templates/kc-navigation.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/templates/kc-navigation.html
index 19f23442a0..8d1ab9b953 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/templates/kc-navigation.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/templates/kc-navigation.html
@@ -1,7 +1,7 @@
- General
- Login
- - Social
+ - Identity Provider
- Credentials
- Keys
- Email
diff --git a/forms/common-themes/src/main/resources/theme/login/base/messages/messages.properties b/forms/common-themes/src/main/resources/theme/login/base/messages/messages.properties
index 6b12161085..bd8f0b2d6c 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/messages/messages.properties
+++ b/forms/common-themes/src/main/resources/theme/login/base/messages/messages.properties
@@ -53,7 +53,8 @@ successTotpRemoved=Mobile authenticator removed.
usernameExists=Username already exists
emailExists=Email already exists
-socialEmailExists=User with email already exists. Please login to account management to link the account.
+federatedIdentityEmailExists=User with email already exists. Please login to account management to link the account.
+federatedIdentityUsernameExists=User with username already exists. Please login to account management to link the account.
loginTitle=Log in to
loginOauthTitle=Temporary access.
diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
index 744d588190..704f8a757a 100755
--- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
+++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
@@ -20,7 +20,7 @@ import org.keycloak.login.freemarker.model.OAuthGrantBean;
import org.keycloak.login.freemarker.model.ProfileBean;
import org.keycloak.login.freemarker.model.RealmBean;
import org.keycloak.login.freemarker.model.RegisterBean;
-import org.keycloak.login.freemarker.model.SocialBean;
+import org.keycloak.login.freemarker.model.IdentityProviderBean;
import org.keycloak.login.freemarker.model.TotpBean;
import org.keycloak.login.freemarker.model.UrlBean;
import org.keycloak.models.ClientModel;
@@ -188,7 +188,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
if (realm != null) {
attributes.put("realm", new RealmBean(realm));
- attributes.put("social", new SocialBean(realm, baseUri));
+ attributes.put("social", new IdentityProviderBean(realm, baseUri));
attributes.put("url", new UrlBean(realm, theme, baseUri));
}
diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/SocialBean.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java
similarity index 55%
rename from forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/SocialBean.java
rename to forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java
index 3ee40b2fdb..399fb1548a 100755
--- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/SocialBean.java
+++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java
@@ -21,44 +21,50 @@
*/
package org.keycloak.login.freemarker.model;
+import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.RealmModel;
-import org.keycloak.services.resources.flows.Urls;
-import org.keycloak.social.SocialLoader;
+import org.keycloak.services.resources.AuthenticationBrokerResource;
import javax.ws.rs.core.UriBuilder;
import java.net.URI;
import java.util.LinkedList;
import java.util.List;
-import java.util.Map;
/**
* @author Stian Thorgersen
*/
-public class SocialBean {
+public class IdentityProviderBean {
private boolean displaySocial;
- private List providers;
+ private List providers;
private RealmModel realm;
- public SocialBean(RealmModel realm, URI baseURI) {
+ public IdentityProviderBean(RealmModel realm, URI baseURI) {
this.realm = realm;
- Map socialConfig = realm.getSocialConfig();
- if (realm.isSocial() && !socialConfig.isEmpty()) {
- displaySocial = true;
- providers = new LinkedList();
+ List identityProviders = realm.getIdentityProviders();
- UriBuilder socialLoginUrlBuilder = UriBuilder.fromUri(Urls.socialRedirectToProviderAuth(baseURI, realm.getName()));
- for (org.keycloak.social.SocialProvider p : SocialLoader.load()) {
- if (socialConfig.containsKey(p.getId() + ".key") && socialConfig.containsKey(p.getId() + ".secret")) {
- String loginUrl = socialLoginUrlBuilder.replaceQueryParam("provider_id", p.getId()).build().toString();
- providers.add(new SocialProvider(p.getId(), p.getName(), loginUrl));
+ if (!identityProviders.isEmpty()) {
+ providers = new LinkedList();
+
+ for (IdentityProviderModel identityProvider : identityProviders) {
+ if (identityProvider.isEnabled()) {
+ String loginUrl = UriBuilder.fromUri(baseURI)
+ .path(AuthenticationBrokerResource.class)
+ .path(AuthenticationBrokerResource.class, "performLogin")
+ .replaceQueryParam("provider_id", identityProvider.getId())
+ .build(realm.getName()).toString();
+ providers.add(new IdentityProvider(identityProvider.getId(), identityProvider.getName(), loginUrl));
}
}
+
+ if (!providers.isEmpty()) {
+ displaySocial = true;
+ }
}
}
- public List getProviders() {
+ public List getProviders() {
return providers;
}
@@ -66,18 +72,19 @@ public class SocialBean {
return realm.isRegistrationAllowed() || displaySocial;
}
- public boolean isDisplaySocialProviders() {
- return displaySocial;
- }
+ public static class IdentityProvider {
- public static class SocialProvider {
+ private final String id;
+ private final String name;
+ private final String loginUrl;
- private String id;
- private String name;
- private String loginUrl;
-
- public SocialProvider(String id, String name, String loginUrl) {
+ public IdentityProvider(String id, String name, String loginUrl) {
this.id = id;
+
+ if (name == null) {
+ name = id;
+ }
+
this.name = name;
this.loginUrl = loginUrl;
}
@@ -95,5 +102,4 @@ public class SocialBean {
}
}
-
}
diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/RealmBean.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/RealmBean.java
index 3dcebd8baf..f751cf9351 100755
--- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/RealmBean.java
+++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/RealmBean.java
@@ -40,8 +40,8 @@ public class RealmBean {
return realm.getName();
}
- public boolean isSocial() {
- return realm.isSocial();
+ public boolean isIdentityFederationEnabled() {
+ return realm.isIdentityFederationEnabled();
}
public boolean isRegistrationAllowed() {
@@ -64,5 +64,5 @@ public class RealmBean {
}
return false;
}
-
+
}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserResource.java
index ee27557a94..839ca23eba 100755
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserResource.java
@@ -1,7 +1,7 @@
package org.keycloak.admin.client.resource;
import org.keycloak.representations.idm.CredentialRepresentation;
-import org.keycloak.representations.idm.SocialLinkRepresentation;
+import org.keycloak.representations.idm.FederatedIdentityRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.UserSessionRepresentation;
@@ -55,11 +55,11 @@ public interface UserResource {
@GET
@Path("social-links")
- public List getSocialLinks();
+ public List getSocialLinks();
@POST
@Path("social-links/{provider}")
- public Response addSocialLink(@PathParam("provider") String provider, SocialLinkRepresentation rep);
+ public Response addSocialLink(@PathParam("provider") String provider, FederatedIdentityRepresentation rep);
@Path("social-links/{provider}")
@DELETE
diff --git a/model/api/src/main/java/org/keycloak/models/FederatedIdentityModel.java b/model/api/src/main/java/org/keycloak/models/FederatedIdentityModel.java
new file mode 100755
index 0000000000..77db720736
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/FederatedIdentityModel.java
@@ -0,0 +1,31 @@
+package org.keycloak.models;
+
+/**
+ * @author Marek Posolda
+ */
+public class FederatedIdentityModel {
+
+ private String userId;
+ private String identityProvider;
+ private String userName;
+
+ public FederatedIdentityModel() {};
+
+ public FederatedIdentityModel(String identityProvider, String userId, String userName) {
+ this.userId = userId;
+ this.identityProvider = identityProvider;
+ this.userName = userName;
+ }
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public String getIdentityProvider() {
+ return identityProvider;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/IdentityProviderModel.java b/model/api/src/main/java/org/keycloak/models/IdentityProviderModel.java
new file mode 100644
index 0000000000..457ba35700
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/IdentityProviderModel.java
@@ -0,0 +1,118 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.models;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 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.
+ *
+ * @author Pedro Igor
+ */
+public class IdentityProviderModel {
+
+ /**
+ * An user-defined identifier to unique identify an identity provider instance.
+ */
+ private String id;
+
+ /**
+ * An identifier used to reference a specific identity provider implementation. The value of this field is the same
+ * across instances of the same provider implementation.
+ */
+ private String providerId;
+
+ /**
+ * An user-defined friendly name for an identity provider instance.
+ */
+ private String name;
+
+ private boolean enabled;
+
+ private boolean updateProfileFirstLogin = true;
+
+ /**
+ * A map containing the configuration and properties for a specific identity provider instance and implementation. The items
+ * in the map are understood by the identity provider implementation.
+ */
+ private Map config = new HashMap();
+
+ public IdentityProviderModel() {
+ this(null, null, null, null);
+ }
+
+ public IdentityProviderModel(String providerId, String id, String name, Map config) {
+ this.providerId = providerId;
+ this.id = id;
+ this.name = name;
+
+ if (config != null) {
+ this.config.putAll(config);
+ }
+ }
+
+ public String getId() {
+ return this.id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getProviderId() {
+ return this.providerId;
+ }
+
+ public void setProviderId(String providerId) {
+ this.providerId = providerId;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean isEnabled() {
+ return this.enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public boolean isUpdateProfileFirstLogin() {
+ return this.updateProfileFirstLogin;
+ }
+
+ public void setUpdateProfileFirstLogin(boolean updateProfileFirstLogin) {
+ this.updateProfileFirstLogin = updateProfileFirstLogin;
+ }
+
+ public Map getConfig() {
+ return this.config;
+ }
+
+ public void setConfig(Map config) {
+ this.config = config;
+ }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java
index ffcd7a53a9..454179e0fb 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java
@@ -124,9 +124,9 @@ public interface RealmModel extends RoleContainerModel {
RoleModel getRoleById(String id);
List getDefaultRoles();
-
+
void addDefaultRole(String name);
-
+
void updateDefaultRoles(String[] defaultRoles);
ClientModel findClient(String clientId);
@@ -146,14 +146,6 @@ public interface RealmModel extends RoleContainerModel {
void updateRequiredCredentials(Set creds);
- boolean isSocial();
-
- void setSocial(boolean social);
-
- boolean isUpdateProfileOnInitialSocialLogin();
-
- void setUpdateProfileOnInitialSocialLogin(boolean updateProfileOnInitialSocialLogin);
-
OAuthClientModel addOAuthClient(String name);
OAuthClientModel addOAuthClient(String id, String name);
@@ -171,9 +163,10 @@ public interface RealmModel extends RoleContainerModel {
void setSmtpConfig(Map smtpConfig);
- Map getSocialConfig();
-
- void setSocialConfig(Map socialConfig);
+ List getIdentityProviders();
+ void addIdentityProvider(IdentityProviderModel identityProvider);
+ void removeIdentityProviderById(String providerId);
+ void updateIdentityProvider(IdentityProviderModel identityProvider);
List getUserFederationProviders();
@@ -228,4 +221,5 @@ public interface RealmModel extends RoleContainerModel {
ClientModel findClientById(String id);
+ boolean isIdentityFederationEnabled();
}
diff --git a/model/api/src/main/java/org/keycloak/models/SocialLinkModel.java b/model/api/src/main/java/org/keycloak/models/SocialLinkModel.java
deleted file mode 100755
index 802fa9e996..0000000000
--- a/model/api/src/main/java/org/keycloak/models/SocialLinkModel.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package org.keycloak.models;
-
-/**
- * @author Marek Posolda
- */
-public class SocialLinkModel {
-
- private String socialUserId;
- private String socialProvider;
- private String socialUsername;
-
- public SocialLinkModel() {};
-
- public SocialLinkModel(String socialProvider, String socialUserId, String socialUsername) {
- this.socialUserId = socialUserId;
- this.socialProvider = socialProvider;
- this.socialUsername = socialUsername;
- }
-
- public String getSocialUserId() {
- return socialUserId;
- }
-
- public void setSocialUserId(String socialUserId) {
- this.socialUserId = socialUserId;
- }
-
- public String getSocialProvider() {
- return socialProvider;
- }
-
- public void setSocialProvider(String socialProvider) {
- this.socialProvider = socialProvider;
- }
-
- public String getSocialUsername() {
- return socialUsername;
- }
-
- public void setSocialUsername(String socialUsername) {
- this.socialUsername = socialUsername;
- }
-}
diff --git a/model/api/src/main/java/org/keycloak/models/UserFederationManager.java b/model/api/src/main/java/org/keycloak/models/UserFederationManager.java
index 2a37f6c018..3bb00f3c24 100755
--- a/model/api/src/main/java/org/keycloak/models/UserFederationManager.java
+++ b/model/api/src/main/java/org/keycloak/models/UserFederationManager.java
@@ -116,16 +116,16 @@ public class UserFederationManager implements UserProvider {
}
@Override
- public void addSocialLink(RealmModel realm, UserModel user, SocialLinkModel socialLink) {
+ public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink) {
validateUser(realm, user);
- session.userStorage().addSocialLink(realm, user, socialLink);
+ session.userStorage().addFederatedIdentity(realm, user, socialLink);
}
@Override
- public boolean removeSocialLink(RealmModel realm, UserModel user, String socialProvider) {
+ public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) {
validateUser(realm, user);
if (user == null) throw new IllegalStateException("Federated user no longer valid");
- return session.userStorage().removeSocialLink(realm, user, socialProvider);
+ return session.userStorage().removeFederatedIdentity(realm, user, socialProvider);
}
@Override
@@ -168,8 +168,8 @@ public class UserFederationManager implements UserProvider {
}
@Override
- public UserModel getUserBySocialLink(SocialLinkModel socialLink, RealmModel realm) {
- UserModel user = session.userStorage().getUserBySocialLink(socialLink, realm);
+ public UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm) {
+ UserModel user = session.userStorage().getUserByFederatedIdentity(socialLink, realm);
if (user != null) {
user = validateAndProxyUser(realm, user);
}
@@ -278,17 +278,17 @@ public class UserFederationManager implements UserProvider {
}
@Override
- public Set getSocialLinks(UserModel user, RealmModel realm) {
+ public Set getFederatedIdentities(UserModel user, RealmModel realm) {
validateUser(realm, user);
if (user == null) throw new IllegalStateException("Federated user no longer valid");
- return session.userStorage().getSocialLinks(user, realm);
+ return session.userStorage().getFederatedIdentities(user, realm);
}
@Override
- public SocialLinkModel getSocialLink(UserModel user, String socialProvider, RealmModel realm) {
+ public FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm) {
validateUser(realm, user);
if (user == null) throw new IllegalStateException("Federated user no longer valid");
- return session.userStorage().getSocialLink(user, socialProvider, realm);
+ return session.userStorage().getFederatedIdentity(user, socialProvider, realm);
}
@Override
diff --git a/model/api/src/main/java/org/keycloak/models/UserProvider.java b/model/api/src/main/java/org/keycloak/models/UserProvider.java
index dd7b08be28..f0b72723e5 100755
--- a/model/api/src/main/java/org/keycloak/models/UserProvider.java
+++ b/model/api/src/main/java/org/keycloak/models/UserProvider.java
@@ -17,13 +17,13 @@ public interface UserProvider extends Provider {
UserModel addUser(RealmModel realm, String username);
boolean removeUser(RealmModel realm, UserModel user);
- public void addSocialLink(RealmModel realm, UserModel user, SocialLinkModel socialLink);
- public boolean removeSocialLink(RealmModel realm, UserModel user, String socialProvider);
+ public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink);
+ public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider);
UserModel getUserById(String id, RealmModel realm);
UserModel getUserByUsername(String username, RealmModel realm);
UserModel getUserByEmail(String email, RealmModel realm);
- UserModel getUserBySocialLink(SocialLinkModel socialLink, RealmModel realm);
+ UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm);
List getUsers(RealmModel realm);
int getUsersCount(RealmModel realm);
List getUsers(RealmModel realm, int firstResult, int maxResults);
@@ -31,8 +31,8 @@ public interface UserProvider extends Provider {
List searchForUser(String search, RealmModel realm, int firstResult, int maxResults);
List searchForUserByAttributes(Map attributes, RealmModel realm);
List searchForUserByAttributes(Map attributes, RealmModel realm, int firstResult, int maxResults);
- Set getSocialLinks(UserModel user, RealmModel realm);
- SocialLinkModel getSocialLink(UserModel user, String socialProvider, RealmModel realm);
+ Set getFederatedIdentities(UserModel user, RealmModel realm);
+ FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm);
void preRemove(RealmModel realm);
diff --git a/model/api/src/main/java/org/keycloak/models/entities/FederatedIdentityEntity.java b/model/api/src/main/java/org/keycloak/models/entities/FederatedIdentityEntity.java
new file mode 100644
index 0000000000..a8fa6473f3
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/entities/FederatedIdentityEntity.java
@@ -0,0 +1,62 @@
+package org.keycloak.models.entities;
+
+/**
+ * @author Marek Posolda
+ */
+public class FederatedIdentityEntity {
+
+ private String userId;
+ private String userName;
+ private String identityProvider;
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public void setUserId(String userId) {
+ this.userId = userId;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public String getIdentityProvider() {
+ return identityProvider;
+ }
+
+ public void setIdentityProvider(String identityProvider) {
+ this.identityProvider = identityProvider;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ FederatedIdentityEntity that = (FederatedIdentityEntity) o;
+
+ if (identityProvider != null && (that.identityProvider == null || !identityProvider.equals(that.identityProvider))) return false;
+ if (userId != null && (that.userId == null || !userId.equals(that.userId))) return false;
+ if (identityProvider == null && that.identityProvider != null)return false;
+ if (userId == null && that.userId != null) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int code = 1;
+ if (userId != null) {
+ code = code * userId.hashCode() * 13;
+ }
+ if (identityProvider != null) {
+ code = code * identityProvider.hashCode() * 17;
+ }
+ return code;
+ }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/entities/IdentityProviderEntity.java b/model/api/src/main/java/org/keycloak/models/entities/IdentityProviderEntity.java
new file mode 100644
index 0000000000..06d2ccae08
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/entities/IdentityProviderEntity.java
@@ -0,0 +1,64 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.models.entities;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Pedro Igor
+ */
+public class IdentityProviderEntity {
+
+ private String id;
+ private String name;
+ private String iconUrl;
+ private Map config = new HashMap();
+
+ public String getId() {
+ return this.id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getIconUrl() {
+ return this.iconUrl;
+ }
+
+ public void setIconUrl(String iconUrl) {
+ this.iconUrl = iconUrl;
+ }
+
+ public Map getConfig() {
+ return this.config;
+ }
+
+ public void setConfig(Map config) {
+ this.config = config;
+ }
+}
diff --git a/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java b/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java
index ef38009a58..07968085e3 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/RealmEntity.java
@@ -19,7 +19,6 @@ public class RealmEntity extends AbstractIdentifiableEntity {
private boolean passwordCredentialGrantAllowed;
private boolean resetPasswordAllowed;
private boolean social;
- private boolean updateProfileOnInitialSocialLogin;
private String passwordPolicy;
//--- brute force settings
private boolean bruteForceProtected;
@@ -128,22 +127,6 @@ public class RealmEntity extends AbstractIdentifiableEntity {
this.resetPasswordAllowed = resetPasswordAllowed;
}
- public boolean isSocial() {
- return social;
- }
-
- public void setSocial(boolean social) {
- this.social = social;
- }
-
- public boolean isUpdateProfileOnInitialSocialLogin() {
- return updateProfileOnInitialSocialLogin;
- }
-
- public void setUpdateProfileOnInitialSocialLogin(boolean updateProfileOnInitialSocialLogin) {
- this.updateProfileOnInitialSocialLogin = updateProfileOnInitialSocialLogin;
- }
-
public String getPasswordPolicy() {
return passwordPolicy;
}
diff --git a/model/api/src/main/java/org/keycloak/models/entities/SocialLinkEntity.java b/model/api/src/main/java/org/keycloak/models/entities/SocialLinkEntity.java
deleted file mode 100644
index 858968f98f..0000000000
--- a/model/api/src/main/java/org/keycloak/models/entities/SocialLinkEntity.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.keycloak.models.entities;
-
-/**
- * @author Marek Posolda
- */
-public class SocialLinkEntity {
-
- private String socialUserId;
- private String socialUsername;
- private String socialProvider;
-
- public String getSocialUserId() {
- return socialUserId;
- }
-
- public void setSocialUserId(String socialUserId) {
- this.socialUserId = socialUserId;
- }
-
- public String getSocialUsername() {
- return socialUsername;
- }
-
- public void setSocialUsername(String socialUsername) {
- this.socialUsername = socialUsername;
- }
-
- public String getSocialProvider() {
- return socialProvider;
- }
-
- public void setSocialProvider(String socialProvider) {
- this.socialProvider = socialProvider;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- SocialLinkEntity that = (SocialLinkEntity) o;
-
- if (socialProvider != null && (that.socialProvider == null || !socialProvider.equals(that.socialProvider))) return false;
- if (socialUserId != null && (that.socialUserId == null || !socialUserId.equals(that.socialUserId))) return false;
- if (socialProvider == null && that.socialProvider != null)return false;
- if (socialUserId == null && that.socialUserId != null) return false;
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int code = 1;
- if (socialUserId != null) {
- code = code * socialUserId.hashCode() * 13;
- }
- if (socialProvider != null) {
- code = code * socialProvider.hashCode() * 17;
- }
- return code;
- }
-}
diff --git a/model/api/src/main/java/org/keycloak/models/entities/UserEntity.java b/model/api/src/main/java/org/keycloak/models/entities/UserEntity.java
index 50be198d33..c84a805c75 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/UserEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/UserEntity.java
@@ -26,7 +26,7 @@ public class UserEntity extends AbstractIdentifiableEntity {
private Map attributes;
private List requiredActions;
private List credentials = new ArrayList();
- private List socialLinks;
+ private List socialLinks;
private String federationLink;
public String getUsername() {
@@ -125,11 +125,11 @@ public class UserEntity extends AbstractIdentifiableEntity {
this.credentials = credentials;
}
- public List getSocialLinks() {
+ public List getSocialLinks() {
return socialLinks;
}
- public void setSocialLinks(List socialLinks) {
+ public void setSocialLinks(List socialLinks) {
this.socialLinks = socialLinks;
}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index 0be1dc7460..a96e217a47 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -4,12 +4,12 @@ import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClaimMask;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
-import org.keycloak.models.Constants;
+import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel;
-import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
@@ -17,11 +17,12 @@ import org.keycloak.models.UserSessionModel;
import org.keycloak.representations.idm.ApplicationRepresentation;
import org.keycloak.representations.idm.ClaimRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.FederatedIdentityRepresentation;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.OAuthClientRepresentation;
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
-import org.keycloak.representations.idm.SocialLinkRepresentation;
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.UserSessionRepresentation;
@@ -80,9 +81,7 @@ public class ModelToRepresentation {
rep.setId(realm.getId());
rep.setRealm(realm.getName());
rep.setEnabled(realm.isEnabled());
- rep.setSocial(realm.isSocial());
rep.setNotBefore(realm.getNotBefore());
- rep.setUpdateProfileOnInitialSocialLogin(realm.isUpdateProfileOnInitialSocialLogin());
rep.setSslRequired(realm.getSslRequired().name().toLowerCase());
rep.setPublicKey(realm.getPublicKeyPem());
if (internal) {
@@ -112,7 +111,6 @@ public class ModelToRepresentation {
rep.setAccessCodeLifespan(realm.getAccessCodeLifespan());
rep.setAccessCodeLifespanUserAction(realm.getAccessCodeLifespanUserAction());
rep.setSmtpServer(realm.getSmtpConfig());
- rep.setSocialProviders(realm.getSocialConfig());
rep.setBrowserSecurityHeaders(realm.getBrowserSecurityHeaders());
rep.setAccountTheme(realm.getAccountTheme());
rep.setLoginTheme(realm.getLoginTheme());
@@ -146,6 +144,20 @@ public class ModelToRepresentation {
}
rep.setUserFederationProviders(fedProviderReps);
}
+
+ for (IdentityProviderModel provider : realm.getIdentityProviders()) {
+ IdentityProviderRepresentation providerRep = new IdentityProviderRepresentation();
+
+ providerRep.setProviderId(provider.getProviderId());
+ providerRep.setId(provider.getId());
+ providerRep.setName(provider.getName());
+ providerRep.setEnabled(provider.isEnabled());
+ providerRep.setUpdateProfileFirstLogin(provider.isUpdateProfileFirstLogin());
+ providerRep.setConfig(provider.getConfig());
+
+ rep.addIdentityProvider(providerRep);
+ }
+
return rep;
}
@@ -185,11 +197,11 @@ public class ModelToRepresentation {
return rep;
}
- public static SocialLinkRepresentation toRepresentation(SocialLinkModel socialLink) {
- SocialLinkRepresentation rep = new SocialLinkRepresentation();
- rep.setSocialUsername(socialLink.getSocialUsername());
- rep.setSocialProvider(socialLink.getSocialProvider());
- rep.setSocialUserId(socialLink.getSocialUserId());
+ public static FederatedIdentityRepresentation toRepresentation(FederatedIdentityModel socialLink) {
+ FederatedIdentityRepresentation rep = new FederatedIdentityRepresentation();
+ rep.setUserName(socialLink.getUserName());
+ rep.setIdentityProvider(socialLink.getIdentityProvider());
+ rep.setUserId(socialLink.getUserId());
return rep;
}
diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index 5ba8d06b84..2ab0afebfb 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -7,12 +7,12 @@ import org.keycloak.models.ApplicationModel;
import org.keycloak.models.BrowserSecurityHeaders;
import org.keycloak.models.ClaimMask;
import org.keycloak.models.ClientModel;
+import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
-import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserFederationProviderModel;
@@ -20,11 +20,11 @@ import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.ApplicationRepresentation;
import org.keycloak.representations.idm.ClaimRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.FederatedIdentityRepresentation;
import org.keycloak.representations.idm.OAuthClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.ScopeMappingRepresentation;
-import org.keycloak.representations.idm.SocialLinkRepresentation;
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
@@ -44,7 +44,6 @@ public class RepresentationToModel {
public static void importRealm(KeycloakSession session, RealmRepresentation rep, RealmModel newRealm) {
newRealm.setName(rep.getRealm());
if (rep.isEnabled() != null) newRealm.setEnabled(rep.isEnabled());
- if (rep.isSocial() != null) newRealm.setSocial(rep.isSocial());
if (rep.isBruteForceProtected() != null) newRealm.setBruteForceProtected(rep.isBruteForceProtected());
if (rep.getMaxFailureWaitSeconds() != null) newRealm.setMaxFailureWaitSeconds(rep.getMaxFailureWaitSeconds());
if (rep.getMinimumQuickLoginWaitSeconds() != null) newRealm.setMinimumQuickLoginWaitSeconds(rep.getMinimumQuickLoginWaitSeconds());
@@ -79,8 +78,6 @@ public class RepresentationToModel {
if (rep.isRememberMe() != null) newRealm.setRememberMe(rep.isRememberMe());
if (rep.isVerifyEmail() != null) newRealm.setVerifyEmail(rep.isVerifyEmail());
if (rep.isResetPasswordAllowed() != null) newRealm.setResetPasswordAllowed(rep.isResetPasswordAllowed());
- if (rep.isUpdateProfileOnInitialSocialLogin() != null)
- newRealm.setUpdateProfileOnInitialSocialLogin(rep.isUpdateProfileOnInitialSocialLogin());
if (rep.getPrivateKey() == null || rep.getPublicKey() == null) {
KeycloakModelUtils.generateRealmKeys(newRealm);
} else {
@@ -220,9 +217,6 @@ public class RepresentationToModel {
newRealm.setBrowserSecurityHeaders(BrowserSecurityHeaders.defaultHeaders);
}
- if (rep.getSocialProviders() != null) {
- newRealm.setSocialConfig(new HashMap(rep.getSocialProviders()));
- }
if (rep.getUserFederationProviders() != null) {
List providerModels = convertFederationProviders(rep.getUserFederationProviders());
newRealm.setUserFederationProviders(providerModels);
@@ -242,7 +236,6 @@ public class RepresentationToModel {
realm.setName(rep.getRealm());
}
if (rep.isEnabled() != null) realm.setEnabled(rep.isEnabled());
- if (rep.isSocial() != null) realm.setSocial(rep.isSocial());
if (rep.isBruteForceProtected() != null) realm.setBruteForceProtected(rep.isBruteForceProtected());
if (rep.getMaxFailureWaitSeconds() != null) realm.setMaxFailureWaitSeconds(rep.getMaxFailureWaitSeconds());
if (rep.getMinimumQuickLoginWaitSeconds() != null) realm.setMinimumQuickLoginWaitSeconds(rep.getMinimumQuickLoginWaitSeconds());
@@ -255,8 +248,6 @@ public class RepresentationToModel {
if (rep.isRememberMe() != null) realm.setRememberMe(rep.isRememberMe());
if (rep.isVerifyEmail() != null) realm.setVerifyEmail(rep.isVerifyEmail());
if (rep.isResetPasswordAllowed() != null) realm.setResetPasswordAllowed(rep.isResetPasswordAllowed());
- if (rep.isUpdateProfileOnInitialSocialLogin() != null)
- realm.setUpdateProfileOnInitialSocialLogin(rep.isUpdateProfileOnInitialSocialLogin());
if (rep.getSslRequired() != null) realm.setSslRequired(SslRequired.valueOf(rep.getSslRequired().toUpperCase()));
if (rep.getAccessCodeLifespan() != null) realm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
if (rep.getAccessCodeLifespanUserAction() != null)
@@ -286,10 +277,6 @@ public class RepresentationToModel {
realm.setSmtpConfig(new HashMap(rep.getSmtpServer()));
}
- if (rep.getSocialProviders() != null) {
- realm.setSocialConfig(new HashMap(rep.getSocialProviders()));
- }
-
if (rep.getBrowserSecurityHeaders() != null) {
realm.setBrowserSecurityHeaders(rep.getBrowserSecurityHeaders());
}
@@ -670,10 +657,10 @@ public class RepresentationToModel {
updateCredential(user, cred);
}
}
- if (userRep.getSocialLinks() != null) {
- for (SocialLinkRepresentation socialLink : userRep.getSocialLinks()) {
- SocialLinkModel mappingModel = new SocialLinkModel(socialLink.getSocialProvider(), socialLink.getSocialUserId(), socialLink.getSocialUsername());
- session.users().addSocialLink(newRealm, user, mappingModel);
+ if (userRep.getFederatedIdentities() != null) {
+ for (FederatedIdentityRepresentation identity : userRep.getFederatedIdentities()) {
+ FederatedIdentityModel mappingModel = new FederatedIdentityModel(identity.getIdentityProvider(), identity.getUserId(), identity.getUserName());
+ session.users().addFederatedIdentity(newRealm, user, mappingModel);
}
}
if (userRep.getRealmRoles() != null) {
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/DefaultCacheUserProvider.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/DefaultCacheUserProvider.java
index 678bf70ae7..2509081c98 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/DefaultCacheUserProvider.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/DefaultCacheUserProvider.java
@@ -4,7 +4,7 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
-import org.keycloak.models.SocialLinkModel;
+import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
@@ -191,8 +191,8 @@ public class DefaultCacheUserProvider implements CacheUserProvider {
}
@Override
- public UserModel getUserBySocialLink(SocialLinkModel socialLink, RealmModel realm) {
- return getDelegate().getUserBySocialLink(socialLink, realm);
+ public UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm) {
+ return getDelegate().getUserByFederatedIdentity(socialLink, realm);
}
@Override
@@ -231,13 +231,13 @@ public class DefaultCacheUserProvider implements CacheUserProvider {
}
@Override
- public Set getSocialLinks(UserModel user, RealmModel realm) {
- return getDelegate().getSocialLinks(user, realm);
+ public Set getFederatedIdentities(UserModel user, RealmModel realm) {
+ return getDelegate().getFederatedIdentities(user, realm);
}
@Override
- public SocialLinkModel getSocialLink(UserModel user, String socialProvider, RealmModel realm) {
- return getDelegate().getSocialLink(user, socialProvider, realm);
+ public FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm) {
+ return getDelegate().getFederatedIdentity(user, socialProvider, realm);
}
@Override
@@ -258,13 +258,13 @@ public class DefaultCacheUserProvider implements CacheUserProvider {
}
@Override
- public void addSocialLink(RealmModel realm, UserModel user, SocialLinkModel socialLink) {
- getDelegate().addSocialLink(realm, user, socialLink);
+ public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink) {
+ getDelegate().addFederatedIdentity(realm, user, socialLink);
}
@Override
- public boolean removeSocialLink(RealmModel realm, UserModel user, String socialProvider) {
- return getDelegate().removeSocialLink(realm, user, socialProvider);
+ public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) {
+ return getDelegate().removeFederatedIdentity(realm, user, socialProvider);
}
@Override
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/NoCacheUserProvider.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/NoCacheUserProvider.java
index 936604c156..706333250d 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/NoCacheUserProvider.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/NoCacheUserProvider.java
@@ -3,7 +3,7 @@ package org.keycloak.models.cache;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
-import org.keycloak.models.SocialLinkModel;
+import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
@@ -66,8 +66,8 @@ public class NoCacheUserProvider implements CacheUserProvider {
}
@Override
- public UserModel getUserBySocialLink(SocialLinkModel socialLink, RealmModel realm) {
- return getDelegate().getUserBySocialLink(socialLink, realm);
+ public UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm) {
+ return getDelegate().getUserByFederatedIdentity(socialLink, realm);
}
@Override
@@ -106,13 +106,13 @@ public class NoCacheUserProvider implements CacheUserProvider {
}
@Override
- public Set getSocialLinks(UserModel user, RealmModel realm) {
- return getDelegate().getSocialLinks(user, realm);
+ public Set getFederatedIdentities(UserModel user, RealmModel realm) {
+ return getDelegate().getFederatedIdentities(user, realm);
}
@Override
- public SocialLinkModel getSocialLink(UserModel user, String socialProvider, RealmModel realm) {
- return getDelegate().getSocialLink(user, socialProvider, realm);
+ public FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm) {
+ return getDelegate().getFederatedIdentity(user, socialProvider, realm);
}
@Override
@@ -131,13 +131,13 @@ public class NoCacheUserProvider implements CacheUserProvider {
}
@Override
- public void addSocialLink(RealmModel realm, UserModel user, SocialLinkModel socialLink) {
- getDelegate().addSocialLink(realm, user, socialLink);
+ public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink) {
+ getDelegate().addFederatedIdentity(realm, user, socialLink);
}
@Override
- public boolean removeSocialLink(RealmModel realm, UserModel user, String socialProvider) {
- return getDelegate().removeSocialLink(realm, user, socialProvider);
+ public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) {
+ return getDelegate().removeFederatedIdentity(realm, user, socialProvider);
}
@Override
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
index 8cc72973d7..98e120cac5 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
@@ -4,6 +4,7 @@ import org.keycloak.Config;
import org.keycloak.enums.SslRequired;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
+import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
@@ -532,30 +533,6 @@ public class RealmAdapter implements RealmModel {
updated.updateRequiredCredentials(creds);
}
- @Override
- public boolean isSocial() {
- if (updated != null) return updated.isSocial();
- return cached.isSocial();
- }
-
- @Override
- public void setSocial(boolean social) {
- getDelegateForUpdate();
- updated.setSocial(social);
- }
-
- @Override
- public boolean isUpdateProfileOnInitialSocialLogin() {
- if (updated != null) return updated.isUpdateProfileOnInitialSocialLogin();
- return cached.isUpdateProfileOnInitialSocialLogin();
- }
-
- @Override
- public void setUpdateProfileOnInitialSocialLogin(boolean updateProfileOnInitialSocialLogin) {
- getDelegateForUpdate();
- updated.setUpdateProfileOnInitialSocialLogin(updateProfileOnInitialSocialLogin);
- }
-
@Override
public OAuthClientModel addOAuthClient(String name) {
getDelegateForUpdate();
@@ -633,15 +610,27 @@ public class RealmAdapter implements RealmModel {
}
@Override
- public Map getSocialConfig() {
- if (updated != null) return updated.getSocialConfig();
- return cached.getSocialConfig();
+ public List getIdentityProviders() {
+ if (updated != null) return updated.getIdentityProviders();
+ return cached.getIdentityProviders();
}
@Override
- public void setSocialConfig(Map socialConfig) {
+ public void addIdentityProvider(IdentityProviderModel identityProvider) {
getDelegateForUpdate();
- updated.setSocialConfig(socialConfig);
+ updated.addIdentityProvider(identityProvider);
+ }
+
+ @Override
+ public void updateIdentityProvider(IdentityProviderModel identityProvider) {
+ getDelegateForUpdate();
+ updated.updateIdentityProvider(identityProvider);
+ }
+
+ @Override
+ public void removeIdentityProviderById(String providerId) {
+ getDelegateForUpdate();
+ updated.removeIdentityProviderById(providerId);
}
@Override
@@ -841,6 +830,13 @@ public class RealmAdapter implements RealmModel {
return getOAuthClientById(id);
}
+ @Override
+ public boolean isIdentityFederationEnabled() {
+ if (updated != null) return updated.isIdentityFederationEnabled();
+ return cached.isIdentityFederationEnabled();
+ }
+
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
index 76c9204789..0a13d926ed 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
@@ -2,6 +2,7 @@ package org.keycloak.models.cache.entities;
import org.keycloak.enums.SslRequired;
import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
@@ -34,8 +35,7 @@ public class CachedRealm {
private boolean verifyEmail;
private boolean passwordCredentialGrantAllowed;
private boolean resetPasswordAllowed;
- private boolean social;
- private boolean updateProfileOnInitialSocialLogin;
+ private boolean identityFederationEnabled;
//--- brute force settings
private boolean bruteForceProtected;
private int maxFailureWaitSeconds;
@@ -67,10 +67,10 @@ public class CachedRealm {
private List requiredCredentials = new ArrayList();
private List userFederationProviders = new ArrayList();
+ private List identityProviders = new ArrayList();
private Map browserSecurityHeaders = new HashMap();
private Map smtpConfig = new HashMap();
- private Map socialConfig = new HashMap();
private boolean eventsEnabled;
private long eventsExpiration;
@@ -93,8 +93,7 @@ public class CachedRealm {
verifyEmail = model.isVerifyEmail();
passwordCredentialGrantAllowed = model.isPasswordCredentialGrantAllowed();
resetPasswordAllowed = model.isResetPasswordAllowed();
- social = model.isSocial();
- updateProfileOnInitialSocialLogin = model.isUpdateProfileOnInitialSocialLogin();
+ identityFederationEnabled = model.isIdentityFederationEnabled();
//--- brute force settings
bruteForceProtected = model.isBruteForceProtected();
maxFailureWaitSeconds = model.getMaxFailureWaitSeconds();
@@ -125,9 +124,9 @@ public class CachedRealm {
requiredCredentials = model.getRequiredCredentials();
userFederationProviders = model.getUserFederationProviders();
+ identityProviders = model.getIdentityProviders();
smtpConfig.putAll(model.getSmtpConfig());
- socialConfig.putAll(model.getSocialConfig());
browserSecurityHeaders.putAll(model.getBrowserSecurityHeaders());
eventsEnabled = model.isEventsEnabled();
@@ -281,22 +280,14 @@ public class CachedRealm {
return passwordPolicy;
}
- public boolean isSocial() {
- return social;
- }
-
- public boolean isUpdateProfileOnInitialSocialLogin() {
- return updateProfileOnInitialSocialLogin;
+ public boolean isIdentityFederationEnabled() {
+ return identityFederationEnabled;
}
public Map getSmtpConfig() {
return smtpConfig;
}
- public Map getSocialConfig() {
- return socialConfig;
- }
-
public Map getBrowserSecurityHeaders() {
return browserSecurityHeaders;
}
@@ -340,4 +331,8 @@ public class CachedRealm {
public String getCertificatePem() {
return certificatePem;
}
+
+ public List getIdentityProviders() {
+ return identityProviders;
+ }
}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaUserProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaUserProvider.java
index 675d655226..60a79e62f7 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaUserProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaUserProvider.java
@@ -1,15 +1,15 @@
package org.keycloak.models.jpa;
import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
-import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider;
-import org.keycloak.models.jpa.entities.SocialLinkEntity;
+import org.keycloak.models.jpa.entities.FederatedIdentityEntity;
import org.keycloak.models.jpa.entities.UserEntity;
import org.keycloak.models.utils.CredentialValidation;
import org.keycloak.models.utils.KeycloakModelUtils;
@@ -85,17 +85,17 @@ public class JpaUserProvider implements UserProvider {
private void removeUser(UserEntity user) {
em.createNamedQuery("deleteUserRoleMappingsByUser").setParameter("user", user).executeUpdate();
- em.createNamedQuery("deleteSocialLinkByUser").setParameter("user", user).executeUpdate();
+ em.createNamedQuery("deleteFederatedIdentityByUser").setParameter("user", user).executeUpdate();
em.remove(user);
}
@Override
- public void addSocialLink(RealmModel realm, UserModel user, SocialLinkModel socialLink) {
- SocialLinkEntity entity = new SocialLinkEntity();
+ public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel identity) {
+ FederatedIdentityEntity entity = new FederatedIdentityEntity();
entity.setRealmId(realm.getId());
- entity.setSocialProvider(socialLink.getSocialProvider());
- entity.setSocialUserId(socialLink.getSocialUserId());
- entity.setSocialUsername(socialLink.getSocialUsername());
+ entity.setIdentityProvider(identity.getIdentityProvider());
+ entity.setUserId(identity.getUserId());
+ entity.setUserName(identity.getUserName());
UserEntity userEntity = em.getReference(UserEntity.class, user.getId());
entity.setUser(userEntity);
em.persist(entity);
@@ -103,8 +103,8 @@ public class JpaUserProvider implements UserProvider {
}
@Override
- public boolean removeSocialLink(RealmModel realm, UserModel user, String socialProvider) {
- SocialLinkEntity entity = findSocialLink(user, socialProvider);
+ public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String identityProvider) {
+ FederatedIdentityEntity entity = findFederatedIdentity(user, identityProvider);
if (entity != null) {
em.remove(entity);
em.flush();
@@ -122,7 +122,7 @@ public class JpaUserProvider implements UserProvider {
.setParameter("realmId", realm.getId()).executeUpdate();
num = em.createNamedQuery("deleteUserRequiredActionsByRealm")
.setParameter("realmId", realm.getId()).executeUpdate();
- num = em.createNamedQuery("deleteSocialLinkByRealm")
+ num = em.createNamedQuery("deleteFederatedIdentityByRealm")
.setParameter("realmId", realm.getId()).executeUpdate();
num = em.createNamedQuery("deleteCredentialsByRealm")
.setParameter("realmId", realm.getId()).executeUpdate();
@@ -142,7 +142,7 @@ public class JpaUserProvider implements UserProvider {
.setParameter("realmId", realm.getId())
.setParameter("link", link.getId())
.executeUpdate();
- num = em.createNamedQuery("deleteSocialLinkByRealmAndLink")
+ num = em.createNamedQuery("deleteFederatedIdentityByRealmAndLink")
.setParameter("realmId", realm.getId())
.setParameter("link", link.getId())
.executeUpdate();
@@ -199,17 +199,17 @@ public class JpaUserProvider implements UserProvider {
}
@Override
- public UserModel getUserBySocialLink(SocialLinkModel socialLink, RealmModel realm) {
- TypedQuery query = em.createNamedQuery("findUserByLinkAndRealm", UserEntity.class);
+ public UserModel getUserByFederatedIdentity(FederatedIdentityModel identity, RealmModel realm) {
+ TypedQuery query = em.createNamedQuery("findUserByFederatedIdentityAndRealm", UserEntity.class);
query.setParameter("realmId", realm.getId());
- query.setParameter("socialProvider", socialLink.getSocialProvider());
- query.setParameter("socialUserId", socialLink.getSocialUserId());
+ query.setParameter("identityProvider", identity.getIdentityProvider());
+ query.setParameter("userId", identity.getUserId());
List results = query.getResultList();
if (results.isEmpty()) {
return null;
} else if (results.size() > 1) {
- throw new IllegalStateException("More results found for socialProvider=" + socialLink.getSocialProvider() +
- ", socialUserId=" + socialLink.getSocialUserId() + ", results=" + results);
+ throw new IllegalStateException("More results found for identityProvider=" + identity.getIdentityProvider() +
+ ", userId=" + identity.getUserId() + ", results=" + results);
} else {
UserEntity user = results.get(0);
return new UserAdapter(realm, em, user);
@@ -326,33 +326,33 @@ public class JpaUserProvider implements UserProvider {
return users;
}
- private SocialLinkEntity findSocialLink(UserModel user, String socialProvider) {
- TypedQuery query = em.createNamedQuery("findSocialLinkByUserAndProvider", SocialLinkEntity.class);
+ private FederatedIdentityEntity findFederatedIdentity(UserModel user, String identityProvider) {
+ TypedQuery query = em.createNamedQuery("findFederatedIdentityByUserAndProvider", FederatedIdentityEntity.class);
UserEntity userEntity = em.getReference(UserEntity.class, user.getId());
query.setParameter("user", userEntity);
- query.setParameter("socialProvider", socialProvider);
- List results = query.getResultList();
+ query.setParameter("identityProvider", identityProvider);
+ List results = query.getResultList();
return results.size() > 0 ? results.get(0) : null;
}
@Override
- public Set getSocialLinks(UserModel user, RealmModel realm) {
- TypedQuery query = em.createNamedQuery("findSocialLinkByUser", SocialLinkEntity.class);
+ public Set getFederatedIdentities(UserModel user, RealmModel realm) {
+ TypedQuery query = em.createNamedQuery("findFederatedIdentityByUser", FederatedIdentityEntity.class);
UserEntity userEntity = em.getReference(UserEntity.class, user.getId());
query.setParameter("user", userEntity);
- List results = query.getResultList();
- Set set = new HashSet();
- for (SocialLinkEntity entity : results) {
- set.add(new SocialLinkModel(entity.getSocialProvider(), entity.getSocialUserId(), entity.getSocialUsername()));
+ List results = query.getResultList();
+ Set set = new HashSet();
+ for (FederatedIdentityEntity entity : results) {
+ set.add(new FederatedIdentityModel(entity.getIdentityProvider(), entity.getUserId(), entity.getUserName()));
}
return set;
}
@Override
- public SocialLinkModel getSocialLink(UserModel user, String socialProvider, RealmModel realm) {
- SocialLinkEntity entity = findSocialLink(user, socialProvider);
- return (entity != null) ? new SocialLinkModel(entity.getSocialProvider(), entity.getSocialUserId(), entity.getSocialUsername()) : null;
+ public FederatedIdentityModel getFederatedIdentity(UserModel user, String identityProvider, RealmModel realm) {
+ FederatedIdentityEntity entity = findFederatedIdentity(user, identityProvider);
+ return (entity != null) ? new FederatedIdentityModel(entity.getIdentityProvider(), entity.getUserId(), entity.getUserName()) : null;
}
@Override
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
index b58bd71084..b8d864cc18 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
@@ -3,6 +3,7 @@ package org.keycloak.models.jpa;
import org.keycloak.enums.SslRequired;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
+import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.PasswordPolicy;
@@ -11,6 +12,7 @@ import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.jpa.entities.ApplicationEntity;
+import org.keycloak.models.jpa.entities.IdentityProviderEntity;
import org.keycloak.models.jpa.entities.OAuthClientEntity;
import org.keycloak.models.jpa.entities.RealmAttributeEntity;
import org.keycloak.models.jpa.entities.RealmEntity;
@@ -682,28 +684,6 @@ public class RealmAdapter implements RealmModel {
return getApplicationNameMap().get(name);
}
- @Override
- public boolean isSocial() {
- return realm.isSocial();
- }
-
- @Override
- public void setSocial(boolean social) {
- realm.setSocial(social);
- em.flush();
- }
-
- @Override
- public boolean isUpdateProfileOnInitialSocialLogin() {
- return realm.isUpdateProfileOnInitialSocialLogin();
- }
-
- @Override
- public void setUpdateProfileOnInitialSocialLogin(boolean updateProfileOnInitialSocialLogin) {
- realm.setUpdateProfileOnInitialSocialLogin(updateProfileOnInitialSocialLogin);
- em.flush();
- }
-
@Override
public OAuthClientModel addOAuthClient(String name) {
return this.addOAuthClient(KeycloakModelUtils.generateId(), name);
@@ -790,17 +770,6 @@ public class RealmAdapter implements RealmModel {
em.flush();
}
- @Override
- public Map getSocialConfig() {
- return realm.getSocialConfig();
- }
-
- @Override
- public void setSocialConfig(Map socialConfig) {
- realm.setSocialConfig(socialConfig);
- em.flush();
- }
-
@Override
public List getUserFederationProviders() {
List entities = realm.getUserFederationProviders();
@@ -1137,4 +1106,67 @@ public class RealmAdapter implements RealmModel {
em.flush();
}
-}
+ @Override
+ public List getIdentityProviders() {
+ List identityProviders = new ArrayList();
+
+ for (IdentityProviderEntity entity: realm.getIdentityProviders()) {
+ IdentityProviderModel identityProviderModel = new IdentityProviderModel(entity.getProviderId(), entity.getId(), entity.getName(),
+ entity.getConfig());
+
+ identityProviderModel.setEnabled(entity.isEnabled());
+ identityProviderModel.setUpdateProfileFirstLogin(entity.isUpdateProfileFirstLogin());
+
+ identityProviders.add(identityProviderModel);
+ }
+
+ return identityProviders;
+ }
+
+ @Override
+ public void addIdentityProvider(IdentityProviderModel identityProvider) {
+ IdentityProviderEntity entity = new IdentityProviderEntity();
+
+ entity.setInternalId(KeycloakModelUtils.generateId());
+ entity.setId(identityProvider.getId());
+ entity.setProviderId(identityProvider.getProviderId());
+ entity.setName(identityProvider.getName());
+ entity.setEnabled(identityProvider.isEnabled());
+ entity.setUpdateProfileFirstLogin(identityProvider.isUpdateProfileFirstLogin());
+ entity.setConfig(identityProvider.getConfig());
+
+ realm.addIdentityProvider(entity);
+
+ em.persist(entity);
+ em.flush();
+ }
+
+ @Override
+ public void removeIdentityProviderById(String providerId) {
+ for (IdentityProviderEntity entity : realm.getIdentityProviders()) {
+ if (entity.getId().equals(providerId)) {
+ em.remove(entity);
+ em.flush();
+ }
+ }
+ }
+
+ @Override
+ public void updateIdentityProvider(IdentityProviderModel identityProvider) {
+ for (IdentityProviderEntity entity : this.realm.getIdentityProviders()) {
+ if (entity.getId().equals(identityProvider.getId())) {
+ entity.setName(identityProvider.getName());
+ entity.setEnabled(identityProvider.isEnabled());
+ entity.setUpdateProfileFirstLogin(identityProvider.isUpdateProfileFirstLogin());
+ entity.setConfig(identityProvider.getConfig());
+ }
+ }
+
+ em.flush();
+ }
+
+ @Override
+ public boolean isIdentityFederationEnabled() {
+ return !this.realm.getIdentityProviders().isEmpty();
+ }
+}
\ No newline at end of file
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/FederatedIdentityEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/FederatedIdentityEntity.java
new file mode 100755
index 0000000000..1a91888938
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/FederatedIdentityEntity.java
@@ -0,0 +1,132 @@
+package org.keycloak.models.jpa.entities;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import java.io.Serializable;
+
+/**
+ * @author Bill Burke
+ * @version $Revision: 1 $
+ */
+@NamedQueries({
+ @NamedQuery(name= "findFederatedIdentityByUser", query="select link from FederatedIdentityEntity link where link.user = :user"),
+ @NamedQuery(name= "findFederatedIdentityByUserAndProvider", query="select link from FederatedIdentityEntity link where link.user = :user and link.identityProvider = :identityProvider"),
+ @NamedQuery(name= "findUserByFederatedIdentityAndRealm", query="select link.user from FederatedIdentityEntity link where link.realmId = :realmId and link.identityProvider = :identityProvider and link.userId = :userId"),
+ @NamedQuery(name= "deleteFederatedIdentityByRealm", query="delete from FederatedIdentityEntity social where social.user IN (select u from UserEntity u where realmId=:realmId)"),
+ @NamedQuery(name= "deleteFederatedIdentityByRealmAndLink", query="delete from FederatedIdentityEntity social where social.user IN (select u from UserEntity u where realmId=:realmId and u.federationLink=:link)"),
+ @NamedQuery(name= "deleteFederatedIdentityByUser", query="delete from FederatedIdentityEntity social where social.user = :user")
+})
+@Table(name="FEDERATED_IDENTITY")
+@Entity
+@IdClass(FederatedIdentityEntity.Key.class)
+public class FederatedIdentityEntity {
+
+ @Id
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "USER_ID")
+ private UserEntity user;
+
+ @Column(name = "REALM_ID")
+ protected String realmId;
+
+ @Id
+ @Column(name = "IDENTITY_PROVIDER")
+ protected String identityProvider;
+ @Column(name = "FEDERATED_USER_ID")
+ protected String userId;
+ @Column(name = "FEDERATED_USERNAME")
+ protected String userName;
+
+ public UserEntity getUser() {
+ return user;
+ }
+
+ public void setUser(UserEntity user) {
+ this.user = user;
+ }
+
+ public String getIdentityProvider() {
+ return identityProvider;
+ }
+
+ public void setIdentityProvider(String identityProvider) {
+ this.identityProvider = identityProvider;
+ }
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public void setUserId(String userId) {
+ this.userId = userId;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public String getRealmId() {
+ return realmId;
+ }
+
+ public void setRealmId(String realmId) {
+ this.realmId = realmId;
+ }
+
+ public static class Key implements Serializable {
+
+ protected UserEntity user;
+
+ protected String identityProvider;
+
+ public Key() {
+ }
+
+ public Key(UserEntity user, String identityProvider) {
+ this.user = user;
+ this.identityProvider = identityProvider;
+ }
+
+ public UserEntity getUser() {
+ return user;
+ }
+
+ public String getIdentityProvider() {
+ return identityProvider;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Key key = (Key) o;
+
+ if (identityProvider != null ? !identityProvider.equals(key.identityProvider) : key.identityProvider != null)
+ return false;
+ if (user != null ? !user.getId().equals(key.user != null ? key.user.getId() : null) : key.user != null) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = user != null ? user.getId().hashCode() : 0;
+ result = 31 * result + (identityProvider != null ? identityProvider.hashCode() : 0);
+ return result;
+ }
+ }
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java
new file mode 100755
index 0000000000..96d9c506e9
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/IdentityProviderEntity.java
@@ -0,0 +1,114 @@
+package org.keycloak.models.jpa.entities;
+
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.MapKeyColumn;
+import javax.persistence.Table;
+import java.util.Map;
+
+/**
+ * @author Pedro Igor
+ */
+@Entity
+@Table(name="IDENTITY_PROVIDER")
+public class IdentityProviderEntity {
+
+ @Id
+ @Column(name="INTERNAL_ID", length = 36)
+ protected String internalId;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "REALM_ID")
+ protected RealmEntity realm;
+
+ @Column(name="PROVIDER_ID")
+ private String providerId;
+
+ @Column(name="PROVIDER_NONIMAL_ID")
+ private String id;
+
+ @Column(name="PROVIDER_NAME")
+ private String name;
+
+ @Column(name="ENABLED")
+ private boolean enabled;
+
+ @Column(name="UPDATE_PROFILE_FIRST_LOGIN")
+ private boolean updateProfileFirstLogin;
+
+ @ElementCollection
+ @MapKeyColumn(name="name")
+ @Column(name="value", columnDefinition = "TEXT")
+ @CollectionTable(name="IDENTITY_PROVIDER_CONFIG", joinColumns={ @JoinColumn(name="IDENTITY_PROVIDER_ID") })
+ private Map config;
+
+ public String getInternalId() {
+ return this.internalId;
+ }
+
+ public void setInternalId(String internalId) {
+ this.internalId = internalId;
+ }
+
+ public String getProviderId() {
+ return this.providerId;
+ }
+
+ public void setProviderId(String providerId) {
+ this.providerId = providerId;
+ }
+
+ public RealmEntity getRealm() {
+ return this.realm;
+ }
+
+ public void setRealm(RealmEntity realm) {
+ this.realm = realm;
+ }
+
+ public String getId() {
+ return this.id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean isEnabled() {
+ return this.enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public boolean isUpdateProfileFirstLogin() {
+ return this.updateProfileFirstLogin;
+ }
+
+ public void setUpdateProfileFirstLogin(boolean updateProfileFirstLogin) {
+ this.updateProfileFirstLogin = updateProfileFirstLogin;
+ }
+
+ public Map getConfig() {
+ return this.config;
+ }
+
+ public void setConfig(Map config) {
+ this.config = config;
+ }
+}
\ No newline at end of file
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
index c78e9163e9..0f2cea8f08 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
@@ -1,6 +1,5 @@
package org.keycloak.models.jpa.entities;
-
import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
@@ -54,12 +53,8 @@ public class RealmEntity {
protected boolean verifyEmail;
@Column(name="RESET_PASSWORD_ALLOWED")
protected boolean resetPasswordAllowed;
- @Column(name="SOCIAL")
- protected boolean social;
@Column(name="REMEMBER_ME")
protected boolean rememberMe;
- @Column(name="UPDATE_PROFILE_ON_SOC_LOGIN")
- protected boolean updateProfileOnInitialSocialLogin;
@Column(name="PASSWORD_POLICY")
protected String passwordPolicy;
@@ -100,7 +95,6 @@ public class RealmEntity {
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
Collection requiredCredentials = new ArrayList();
-
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true)
@JoinTable(name="FED_PROVIDERS")
List userFederationProviders = new ArrayList();
@@ -118,12 +112,6 @@ public class RealmEntity {
@CollectionTable(name="REALM_SMTP_CONFIG", joinColumns={ @JoinColumn(name="REALM_ID") })
protected Map smtpConfig = new HashMap();
- @ElementCollection
- @MapKeyColumn(name="NAME")
- @Column(name="VALUE")
- @CollectionTable(name="REALM_SOCIAL_CONFIG", joinColumns={ @JoinColumn(name="REALM_ID") })
- protected Map socialConfig = new HashMap();
-
@OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true)
@JoinTable(name="REALM_DEFAULT_ROLES", joinColumns = { @JoinColumn(name="REALM_ID")}, inverseJoinColumns = { @JoinColumn(name="ROLE_ID")})
protected Collection defaultRoles = new ArrayList();
@@ -142,6 +130,9 @@ public class RealmEntity {
@JoinColumn(name="MASTER_ADMIN_APP")
protected ApplicationEntity masterAdminApp;
+ @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
+ protected List identityProviders = new ArrayList();
+
public String getId() {
return id;
}
@@ -214,22 +205,6 @@ public class RealmEntity {
this.resetPasswordAllowed = resetPasswordAllowed;
}
- public boolean isSocial() {
- return social;
- }
-
- public void setSocial(boolean social) {
- this.social = social;
- }
-
- public boolean isUpdateProfileOnInitialSocialLogin() {
- return updateProfileOnInitialSocialLogin;
- }
-
- public void setUpdateProfileOnInitialSocialLogin(boolean updateProfileOnInitialSocialLogin) {
- this.updateProfileOnInitialSocialLogin = updateProfileOnInitialSocialLogin;
- }
-
public int getSsoSessionIdleTimeout() {
return ssoSessionIdleTimeout;
}
@@ -333,14 +308,6 @@ public class RealmEntity {
this.smtpConfig = smtpConfig;
}
- public Map getSocialConfig() {
- return socialConfig;
- }
-
- public void setSocialConfig(Map socialConfig) {
- this.socialConfig = socialConfig;
- }
-
public Collection getDefaultRoles() {
return defaultRoles;
}
@@ -452,5 +419,18 @@ public class RealmEntity {
public void setCertificatePem(String certificatePem) {
this.certificatePem = certificatePem;
}
+
+ public List getIdentityProviders() {
+ return this.identityProviders;
+ }
+
+ public void setIdentityProviders(List identityProviders) {
+ this.identityProviders = identityProviders;
+ }
+
+ public void addIdentityProvider(IdentityProviderEntity entity) {
+ entity.setRealm(this);
+ getIdentityProviders().add(entity);
+ }
}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/SocialLinkEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/SocialLinkEntity.java
deleted file mode 100755
index 68e586f3ef..0000000000
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/SocialLinkEntity.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package org.keycloak.models.jpa.entities;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.FetchType;
-import javax.persistence.Id;
-import javax.persistence.IdClass;
-import javax.persistence.JoinColumn;
-import javax.persistence.ManyToOne;
-import javax.persistence.NamedQueries;
-import javax.persistence.NamedQuery;
-import javax.persistence.Table;
-import java.io.Serializable;
-
-/**
- * @author Bill Burke
- * @version $Revision: 1 $
- */
-@NamedQueries({
- @NamedQuery(name="findSocialLinkByUser", query="select link from SocialLinkEntity link where link.user = :user"),
- @NamedQuery(name="findSocialLinkByUserAndProvider", query="select link from SocialLinkEntity link where link.user = :user and link.socialProvider = :socialProvider"),
- @NamedQuery(name="findUserByLinkAndRealm", query="select link.user from SocialLinkEntity link where link.realmId = :realmId and link.socialProvider = :socialProvider and link.socialUserId = :socialUserId"),
- @NamedQuery(name="deleteSocialLinkByRealm", query="delete from SocialLinkEntity social where social.user IN (select u from UserEntity u where realmId=:realmId)"),
- @NamedQuery(name="deleteSocialLinkByRealmAndLink", query="delete from SocialLinkEntity social where social.user IN (select u from UserEntity u where realmId=:realmId and u.federationLink=:link)"),
- @NamedQuery(name="deleteSocialLinkByUser", query="delete from SocialLinkEntity social where social.user = :user")
-})
-@Table(name="USER_SOCIAL_LINK")
-@Entity
-@IdClass(SocialLinkEntity.Key.class)
-public class SocialLinkEntity {
-
- @Id
- @ManyToOne(fetch = FetchType.LAZY)
- @JoinColumn(name = "USER_ID")
- private UserEntity user;
-
- @Column(name = "REALM_ID")
- protected String realmId;
-
- @Id
- @Column(name = "SOCIAL_PROVIDER")
- protected String socialProvider;
- @Column(name = "SOCIAL_USER_ID")
- protected String socialUserId;
- @Column(name = "SOCIAL_USERNAME")
- protected String socialUsername;
-
- public UserEntity getUser() {
- return user;
- }
-
- public void setUser(UserEntity user) {
- this.user = user;
- }
-
- public String getSocialProvider() {
- return socialProvider;
- }
-
- public void setSocialProvider(String socialProvider) {
- this.socialProvider = socialProvider;
- }
-
- public String getSocialUserId() {
- return socialUserId;
- }
-
- public void setSocialUserId(String socialUserId) {
- this.socialUserId = socialUserId;
- }
-
- public String getSocialUsername() {
- return socialUsername;
- }
-
- public void setSocialUsername(String socialUsername) {
- this.socialUsername = socialUsername;
- }
-
- public String getRealmId() {
- return realmId;
- }
-
- public void setRealmId(String realmId) {
- this.realmId = realmId;
- }
-
- public static class Key implements Serializable {
-
- protected UserEntity user;
-
- protected String socialProvider;
-
- public Key() {
- }
-
- public Key(UserEntity user, String socialProvider) {
- this.user = user;
- this.socialProvider = socialProvider;
- }
-
- public UserEntity getUser() {
- return user;
- }
-
- public String getSocialProvider() {
- return socialProvider;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- Key key = (Key) o;
-
- if (socialProvider != null ? !socialProvider.equals(key.socialProvider) : key.socialProvider != null)
- return false;
- if (user != null ? !user.getId().equals(key.user != null ? key.user.getId() : null) : key.user != null) return false;
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int result = user != null ? user.getId().hashCode() : 0;
- result = 31 * result + (socialProvider != null ? socialProvider.hashCode() : 0);
- return result;
- }
- }
-
-}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoUserProvider.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoUserProvider.java
index df11ffd706..c67952a7be 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoUserProvider.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoUserProvider.java
@@ -9,12 +9,12 @@ import org.keycloak.models.ApplicationModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
-import org.keycloak.models.SocialLinkModel;
+import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider;
-import org.keycloak.models.entities.SocialLinkEntity;
+import org.keycloak.models.entities.FederatedIdentityEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity;
import org.keycloak.models.utils.CredentialValidation;
@@ -93,10 +93,10 @@ public class MongoUserProvider implements UserProvider {
}
@Override
- public UserModel getUserBySocialLink(SocialLinkModel socialLink, RealmModel realm) {
+ public UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm) {
DBObject query = new QueryBuilder()
- .and("socialLinks.socialProvider").is(socialLink.getSocialProvider())
- .and("socialLinks.socialUserId").is(socialLink.getSocialUserId())
+ .and("federatedIdentities.identityProvider").is(socialLink.getIdentityProvider())
+ .and("federatedIdentities.userId").is(socialLink.getUserId())
.and("realmId").is(realm.getId())
.get();
MongoUserEntity userEntity = getMongoStore().loadSingleEntity(MongoUserEntity.class, query, invocationContext);
@@ -213,35 +213,35 @@ public class MongoUserProvider implements UserProvider {
}
@Override
- public Set getSocialLinks(UserModel userModel, RealmModel realm) {
+ public Set getFederatedIdentities(UserModel userModel, RealmModel realm) {
UserModel user = getUserById(userModel.getId(), realm);
MongoUserEntity userEntity = ((UserAdapter) user).getUser();
- List linkEntities = userEntity.getSocialLinks();
+ List linkEntities = userEntity.getSocialLinks();
if (linkEntities == null) {
return Collections.EMPTY_SET;
}
- Set result = new HashSet();
- for (SocialLinkEntity socialLinkEntity : linkEntities) {
- SocialLinkModel model = new SocialLinkModel(socialLinkEntity.getSocialProvider(),
- socialLinkEntity.getSocialUserId(), socialLinkEntity.getSocialUsername());
+ Set result = new HashSet();
+ for (FederatedIdentityEntity federatedIdentityEntity : linkEntities) {
+ FederatedIdentityModel model = new FederatedIdentityModel(federatedIdentityEntity.getIdentityProvider(),
+ federatedIdentityEntity.getUserId(), federatedIdentityEntity.getUserName());
result.add(model);
}
return result;
}
- private SocialLinkEntity findSocialLink(UserModel userModel, String socialProvider, RealmModel realm) {
+ private FederatedIdentityEntity findSocialLink(UserModel userModel, String socialProvider, RealmModel realm) {
UserModel user = getUserById(userModel.getId(), realm);
MongoUserEntity userEntity = ((UserAdapter) user).getUser();
- List linkEntities = userEntity.getSocialLinks();
+ List linkEntities = userEntity.getSocialLinks();
if (linkEntities == null) {
return null;
}
- for (SocialLinkEntity socialLinkEntity : linkEntities) {
- if (socialLinkEntity.getSocialProvider().equals(socialProvider)) {
- return socialLinkEntity;
+ for (FederatedIdentityEntity federatedIdentityEntity : linkEntities) {
+ if (federatedIdentityEntity.getIdentityProvider().equals(socialProvider)) {
+ return federatedIdentityEntity;
}
}
return null;
@@ -249,9 +249,9 @@ public class MongoUserProvider implements UserProvider {
@Override
- public SocialLinkModel getSocialLink(UserModel user, String socialProvider, RealmModel realm) {
- SocialLinkEntity socialLinkEntity = findSocialLink(user, socialProvider, realm);
- return socialLinkEntity != null ? new SocialLinkModel(socialLinkEntity.getSocialProvider(), socialLinkEntity.getSocialUserId(), socialLinkEntity.getSocialUsername()) : null;
+ public FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm) {
+ FederatedIdentityEntity federatedIdentityEntity = findSocialLink(user, socialProvider, realm);
+ return federatedIdentityEntity != null ? new FederatedIdentityModel(federatedIdentityEntity.getIdentityProvider(), federatedIdentityEntity.getUserId(), federatedIdentityEntity.getUserName()) : null;
}
@Override
@@ -296,37 +296,37 @@ public class MongoUserProvider implements UserProvider {
@Override
- public void addSocialLink(RealmModel realm, UserModel user, SocialLinkModel socialLink) {
+ public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink) {
user = getUserById(user.getId(), realm);
MongoUserEntity userEntity = ((UserAdapter) user).getUser();
- SocialLinkEntity socialLinkEntity = new SocialLinkEntity();
- socialLinkEntity.setSocialProvider(socialLink.getSocialProvider());
- socialLinkEntity.setSocialUserId(socialLink.getSocialUserId());
- socialLinkEntity.setSocialUsername(socialLink.getSocialUsername());
+ FederatedIdentityEntity federatedIdentityEntity = new FederatedIdentityEntity();
+ federatedIdentityEntity.setIdentityProvider(socialLink.getIdentityProvider());
+ federatedIdentityEntity.setUserId(socialLink.getUserId());
+ federatedIdentityEntity.setUserName(socialLink.getUserName());
- getMongoStore().pushItemToList(userEntity, "socialLinks", socialLinkEntity, true, invocationContext);
+ getMongoStore().pushItemToList(userEntity, "federatedIdentities", federatedIdentityEntity, true, invocationContext);
}
@Override
- public boolean removeSocialLink(RealmModel realm, UserModel userModel, String socialProvider) {
+ public boolean removeFederatedIdentity(RealmModel realm, UserModel userModel, String socialProvider) {
UserModel user = getUserById(userModel.getId(), realm);
MongoUserEntity userEntity = ((UserAdapter) user).getUser();
- SocialLinkEntity socialLinkEntity = findSocialLink(userEntity, socialProvider);
- if (socialLinkEntity == null) {
+ FederatedIdentityEntity federatedIdentityEntity = findSocialLink(userEntity, socialProvider);
+ if (federatedIdentityEntity == null) {
return false;
}
- return getMongoStore().pullItemFromList(userEntity, "socialLinks", socialLinkEntity, invocationContext);
+ return getMongoStore().pullItemFromList(userEntity, "federatedIdentities", federatedIdentityEntity, invocationContext);
}
- private SocialLinkEntity findSocialLink(MongoUserEntity userEntity, String socialProvider) {
- List linkEntities = userEntity.getSocialLinks();
+ private FederatedIdentityEntity findSocialLink(MongoUserEntity userEntity, String socialProvider) {
+ List linkEntities = userEntity.getSocialLinks();
if (linkEntities == null) {
return null;
}
- for (SocialLinkEntity socialLinkEntity : linkEntities) {
- if (socialLinkEntity.getSocialProvider().equals(socialProvider)) {
- return socialLinkEntity;
+ for (FederatedIdentityEntity federatedIdentityEntity : linkEntities) {
+ if (federatedIdentityEntity.getIdentityProvider().equals(socialProvider)) {
+ return federatedIdentityEntity;
}
}
return null;
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
index 49fe46b820..b23d3a0c02 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
@@ -2,11 +2,11 @@ package org.keycloak.models.mongo.keycloak.adapters;
import com.mongodb.DBObject;
import com.mongodb.QueryBuilder;
-import org.jboss.logging.Logger;
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
import org.keycloak.enums.SslRequired;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
+import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.PasswordPolicy;
@@ -234,28 +234,6 @@ public class RealmAdapter extends AbstractMongoAdapter impleme
updateRealm();
}
- @Override
- public boolean isSocial() {
- return realm.isSocial();
- }
-
- @Override
- public void setSocial(boolean social) {
- realm.setSocial(social);
- updateRealm();
- }
-
- @Override
- public boolean isUpdateProfileOnInitialSocialLogin() {
- return realm.isUpdateProfileOnInitialSocialLogin();
- }
-
- @Override
- public void setUpdateProfileOnInitialSocialLogin(boolean updateProfileOnInitialSocialLogin) {
- realm.setUpdateProfileOnInitialSocialLogin(updateProfileOnInitialSocialLogin);
- updateRealm();
- }
-
@Override
public PasswordPolicy getPasswordPolicy() {
if (passwordPolicy == null) {
@@ -804,14 +782,23 @@ public class RealmAdapter extends AbstractMongoAdapter impleme
}
@Override
- public Map getSocialConfig() {
- return realm.getSocialConfig();
+ public List getIdentityProviders() {
+ return null;
}
@Override
- public void setSocialConfig(Map socialConfig) {
- realm.setSocialConfig(socialConfig);
- updateRealm();
+ public void addIdentityProvider(IdentityProviderModel identityProvider) {
+
+ }
+
+ @Override
+ public void removeIdentityProviderById(String providerId) {
+
+ }
+
+ @Override
+ public void updateIdentityProvider(IdentityProviderModel identityProvider) {
+
}
@Override
@@ -974,6 +961,12 @@ public class RealmAdapter extends AbstractMongoAdapter impleme
return realm;
}
+ @Override
+ public boolean isIdentityFederationEnabled() {
+ //TODO: support identity federation storage for mongo
+ return false;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/pom.xml b/pom.xml
index 93cfce2862..afc7119540 100755
--- a/pom.xml
+++ b/pom.xml
@@ -113,6 +113,7 @@
federation
services
saml
+ broker
social
forms
examples
@@ -702,7 +703,7 @@
org.wildfly.plugins
wildfly-maven-plugin
- 1.0.1.Final
+ 1.0.1.Final
true
diff --git a/project-integrations/aerogear-ups/auth-server/src/main/webapp/WEB-INF/testrealm.json b/project-integrations/aerogear-ups/auth-server/src/main/webapp/WEB-INF/testrealm.json
index ab37d0ac92..e087a1beb9 100755
--- a/project-integrations/aerogear-ups/auth-server/src/main/webapp/WEB-INF/testrealm.json
+++ b/project-integrations/aerogear-ups/auth-server/src/main/webapp/WEB-INF/testrealm.json
@@ -6,11 +6,9 @@
"accessCodeLifespanUserAction": 6000,
"sslRequired": "external",
"registrationAllowed": false,
- "social": false,
"adminTheme": "aerogear",
"accountTheme": "aerogear",
"loginTheme": "aerogear",
- "updateProfileOnInitialSocialLogin": false,
"requiredCredentials": [ "password" ],
"users" : [
{
diff --git a/services/pom.xml b/services/pom.xml
index 82e4b6a45d..d061ea8ef7 100755
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -79,6 +79,11 @@
${project.version}
provided
+
+ org.keycloak
+ keycloak-broker-core
+ ${project.version}
+
org.keycloak
keycloak-timer-api
diff --git a/services/src/main/java/org/keycloak/services/messages/Messages.java b/services/src/main/java/org/keycloak/services/messages/Messages.java
index bcea5ed736..c2eaaaad55 100755
--- a/services/src/main/java/org/keycloak/services/messages/Messages.java
+++ b/services/src/main/java/org/keycloak/services/messages/Messages.java
@@ -71,19 +71,19 @@ public class Messages {
public static final String ACTION_WARN_EMAIL = "actionEmailWarning";
- public static final String MISSING_SOCIAL_PROVIDER = "missingSocialProvider";
+ public static final String MISSING_IDENTITY_PROVIDER = "missingIdentityProvider";
- public static final String INVALID_SOCIAL_ACTION = "invalidSocialAction";
+ public static final String INVALID_FEDERATED_IDENTITY_ACTION = "invalidFederatedIdentityAction";
- public static final String SOCIAL_PROVIDER_NOT_FOUND = "socialProviderNotFound";
+ public static final String IDENTITY_PROVIDER_NOT_FOUND = "identityProviderNotFound";
- public static final String SOCIAL_LINK_NOT_ACTIVE = "socialLinkNotActive";
+ public static final String FEDERATED_IDENTITY_NOT_ACTIVE = "federatedIdentityLinkNotActive";
- public static final String SOCIAL_REMOVING_LAST_PROVIDER = "socialRemovingLastProvider";
+ public static final String FEDERATED_IDENTITY_REMOVING_LAST_PROVIDER = "federatedIdentityRemovingLastProvider";
- public static final String SOCIAL_REDIRECT_ERROR = "socialRedirectError";
+ public static final String IDENTITY_PROVIDER_REDIRECT_ERROR = "identityProviderRedirectError";
- public static final String SOCIAL_PROVIDER_REMOVED = "socialProviderRemoved";
+ public static final String IDENTITY_PROVIDER_REMOVED = "identityProviderRemoved";
public static final String ERROR = "error";
diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java
index f08df6f669..f3f6e9ab5d 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -37,14 +37,16 @@ import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.Constants;
+import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelReadOnlyException;
import org.keycloak.models.RealmModel;
-import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.TimeBasedOTP;
import org.keycloak.protocol.oidc.OpenIDConnect;
@@ -64,14 +66,10 @@ import org.keycloak.services.resources.flows.Urls;
import org.keycloak.services.util.CookieHelper;
import org.keycloak.services.util.ResolveRelative;
import org.keycloak.services.validation.Validation;
-import org.keycloak.social.SocialLoader;
-import org.keycloak.social.SocialProvider;
-import org.keycloak.social.SocialProviderException;
import org.keycloak.util.UriUtils;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
-import javax.ws.rs.HttpMethod;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
@@ -111,7 +109,7 @@ public class AccountService {
}
}
- private static final EventType[] LOG_EVENTS = {EventType.LOGIN, EventType.LOGOUT, EventType.REGISTER, EventType.REMOVE_SOCIAL_LINK, EventType.REMOVE_TOTP, EventType.SEND_RESET_PASSWORD,
+ private static final EventType[] LOG_EVENTS = {EventType.LOGIN, EventType.LOGOUT, EventType.REGISTER, EventType.REMOVE_FEDERATED_IDENTITY, EventType.REMOVE_TOTP, EventType.SEND_RESET_PASSWORD,
EventType.SEND_VERIFY_EMAIL, EventType.SOCIAL_LINK, EventType.UPDATE_EMAIL, EventType.UPDATE_PASSWORD, EventType.UPDATE_PROFILE, EventType.UPDATE_TOTP, EventType.VERIFY_EMAIL};
private static final Set LOG_DETAILS = new HashSet();
@@ -227,7 +225,7 @@ public class AccountService {
boolean eventsEnabled = eventStore != null && realm.isEventsEnabled();
// todo find out from federation if password is updatable
- account.setFeatures(realm.isSocial(), eventsEnabled, true);
+ account.setFeatures(realm.isIdentityFederationEnabled(), eventsEnabled, true);
}
public static UriBuilder accountServiceBaseUrl(UriInfo uriInfo) {
@@ -325,15 +323,10 @@ public class AccountService {
return forwardToPage("password", AccountPages.PASSWORD);
}
-
- public static UriBuilder socialUrl(UriBuilder base) {
- return RealmsResource.accountUrl(base).path(AccountService.class, "socialPage");
- }
-
- @Path("social")
+ @Path("identity")
@GET
- public Response socialPage() {
- return forwardToPage("social", AccountPages.SOCIAL);
+ public Response federatedIdentityPage() {
+ return forwardToPage("identity", AccountPages.FEDERATED_IDENTITY);
}
@Path("log")
@@ -639,13 +632,13 @@ public class AccountService {
return account.setPasswordSet(true).setSuccess("accountPasswordUpdated").createResponse(AccountPages.PASSWORD);
}
- @Path("social-update")
+ @Path("federated-identity-update")
@GET
- public Response processSocialUpdate(@QueryParam("action") String action,
- @QueryParam("provider_id") String providerId,
- @QueryParam("stateChecker") String stateChecker) {
+ public Response processFederatedIdentityUpdate(@QueryParam("action") String action,
+ @QueryParam("provider_id") String providerId,
+ @QueryParam("stateChecker") String stateChecker) {
if (auth == null) {
- return login("social");
+ return login("broker");
}
require(AccountRoles.MANAGE_ACCOUNT);
@@ -654,23 +647,30 @@ public class AccountService {
if (Validation.isEmpty(providerId)) {
setReferrerOnPage();
- return account.setError(Messages.MISSING_SOCIAL_PROVIDER).createResponse(AccountPages.SOCIAL);
+ return account.setError(Messages.MISSING_IDENTITY_PROVIDER).createResponse(AccountPages.FEDERATED_IDENTITY);
}
AccountSocialAction accountSocialAction = AccountSocialAction.getAction(action);
if (accountSocialAction == null) {
setReferrerOnPage();
- return account.setError(Messages.INVALID_SOCIAL_ACTION).createResponse(AccountPages.SOCIAL);
+ return account.setError(Messages.INVALID_FEDERATED_IDENTITY_ACTION).createResponse(AccountPages.FEDERATED_IDENTITY);
}
- SocialProvider provider = SocialLoader.load(providerId);
- if (provider == null) {
+ boolean hasProvider = false;
+
+ for (IdentityProviderModel model : realm.getIdentityProviders()) {
+ if (model.getId().equals(providerId)) {
+ hasProvider = true;
+ }
+ }
+
+ if (!hasProvider) {
setReferrerOnPage();
- return account.setError(Messages.SOCIAL_PROVIDER_NOT_FOUND).createResponse(AccountPages.SOCIAL);
+ return account.setError(Messages.IDENTITY_PROVIDER_NOT_FOUND).createResponse(AccountPages.FEDERATED_IDENTITY);
}
if (!user.isEnabled()) {
setReferrerOnPage();
- return account.setError(Messages.ACCOUNT_DISABLED).createResponse(AccountPages.SOCIAL);
+ return account.setError(Messages.ACCOUNT_DISABLED).createResponse(AccountPages.FEDERATED_IDENTITY);
}
switch (accountSocialAction) {
@@ -682,36 +682,44 @@ public class AccountService {
clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE);
clientSession.setRedirectUri(redirectUri);
clientSession.setNote(OpenIDConnect.STATE_PARAM, UUID.randomUUID().toString());
+ clientSession.setNote(ClientSessionCode.ACTION_KEY, KeycloakModelUtils.generateCodeSecret());
ClientSessionCode clientSessionCode = new ClientSessionCode(realm, clientSession);
- return Flows.social(realm, uriInfo, clientConnection, provider)
- .redirectToSocialProvider(clientSessionCode);
- } catch (SocialProviderException spe) {
+
+ URI url = UriBuilder.fromUri(this.uriInfo.getBaseUri())
+ .path(AuthenticationBrokerResource.class)
+ .path(AuthenticationBrokerResource.class, "performLogin")
+ .queryParam("provider_id", providerId)
+ .queryParam("code", clientSessionCode.getCode())
+ .build(this.realm.getName());
+
+ return Response.temporaryRedirect(url).build();
+ } catch (Exception spe) {
setReferrerOnPage();
- return account.setError(Messages.SOCIAL_REDIRECT_ERROR).createResponse(AccountPages.SOCIAL);
+ return account.setError(Messages.IDENTITY_PROVIDER_REDIRECT_ERROR).createResponse(AccountPages.FEDERATED_IDENTITY);
}
case REMOVE:
- SocialLinkModel link = session.users().getSocialLink(user, providerId, realm);
+ FederatedIdentityModel link = session.users().getFederatedIdentity(user, providerId, realm);
if (link != null) {
// Removing last social provider is not possible if you don't have other possibility to authenticate
- if (session.users().getSocialLinks(user, realm).size() > 1 || user.getFederationLink() != null || isPasswordSet(user)) {
- session.users().removeSocialLink(realm, user, providerId);
+ if (session.users().getFederatedIdentities(user, realm).size() > 1 || user.getFederationLink() != null || isPasswordSet(user)) {
+ session.users().removeFederatedIdentity(realm, user, providerId);
logger.debugv("Social provider {0} removed successfully from user {1}", providerId, user.getUsername());
- event.event(EventType.REMOVE_SOCIAL_LINK).client(auth.getClient()).user(auth.getUser())
- .detail(Details.USERNAME, link.getSocialUserId() + "@" + link.getSocialProvider())
+ event.event(EventType.REMOVE_FEDERATED_IDENTITY).client(auth.getClient()).user(auth.getUser())
+ .detail(Details.USERNAME, link.getUserId() + "@" + link.getIdentityProvider())
.success();
setReferrerOnPage();
- return account.setSuccess(Messages.SOCIAL_PROVIDER_REMOVED).createResponse(AccountPages.SOCIAL);
+ return account.setSuccess(Messages.IDENTITY_PROVIDER_REMOVED).createResponse(AccountPages.FEDERATED_IDENTITY);
} else {
setReferrerOnPage();
- return account.setError(Messages.SOCIAL_REMOVING_LAST_PROVIDER).createResponse(AccountPages.SOCIAL);
+ return account.setError(Messages.FEDERATED_IDENTITY_REMOVING_LAST_PROVIDER).createResponse(AccountPages.FEDERATED_IDENTITY);
}
} else {
setReferrerOnPage();
- return account.setError(Messages.SOCIAL_LINK_NOT_ACTIVE).createResponse(AccountPages.SOCIAL);
+ return account.setError(Messages.FEDERATED_IDENTITY_NOT_ACTIVE).createResponse(AccountPages.FEDERATED_IDENTITY);
}
default:
throw new IllegalArgumentException();
diff --git a/services/src/main/java/org/keycloak/services/resources/AuthenticationBrokerResource.java b/services/src/main/java/org/keycloak/services/resources/AuthenticationBrokerResource.java
new file mode 100644
index 0000000000..550deda2c9
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/AuthenticationBrokerResource.java
@@ -0,0 +1,356 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.services.resources;
+
+import org.jboss.resteasy.spi.HttpRequest;
+import org.keycloak.ClientConnection;
+import org.keycloak.broker.provider.AuthenticationRequest;
+import org.keycloak.broker.provider.AuthenticationResponse;
+import org.keycloak.broker.provider.FederatedIdentity;
+import org.keycloak.broker.provider.IdentityProvider;
+import org.keycloak.broker.provider.IdentityProviderFactory;
+import org.keycloak.events.Details;
+import org.keycloak.events.Errors;
+import org.keycloak.events.EventBuilder;
+import org.keycloak.events.EventType;
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.IdentityProviderModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.protocol.oidc.TokenManager;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.services.managers.AuthenticationManager;
+import org.keycloak.services.managers.ClientSessionCode;
+import org.keycloak.services.managers.EventsManager;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.services.resources.flows.Flows;
+import org.keycloak.social.SocialIdentityProvider;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.keycloak.models.AccountRoles.MANAGE_ACCOUNT;
+import static org.keycloak.models.ClientSessionModel.Action.AUTHENTICATE;
+import static org.keycloak.models.Constants.ACCOUNT_MANAGEMENT_APP;
+import static org.keycloak.models.UserModel.RequiredAction.UPDATE_PROFILE;
+
+/**
+ * @author Pedro Igor
+ */
+@Path("/broker")
+public class AuthenticationBrokerResource {
+
+ @Context
+ private UriInfo uriInfo;
+
+ @Context
+ private KeycloakSession session;
+
+ @Context
+ private ClientConnection clientConnection;
+
+ @Context
+ private HttpRequest request;
+
+ @GET
+ @Path("{realm}/login")
+ public Response performLogin(@PathParam("realm") String realmName,
+ @QueryParam("provider_id") String providerId,
+ @QueryParam("code") String code) {
+ RealmManager realmManager = new RealmManager(session);
+ RealmModel realm = realmManager.getRealmByName(realmName);
+ ClientSessionCode clientCode = isValidAuthorizationCode(code, realm);
+
+ if (clientCode == null) {
+ return redirectToErrorPage(realm, "Invalid code, please login again through your application.");
+ }
+
+ EventBuilder event = new EventsManager(realm, session, clientConnection).createEventBuilder()
+ .event(EventType.LOGIN)
+ .detail(Details.AUTH_METHOD, "unknown_id@" + providerId);
+
+ try {
+ ClientSessionModel clientSession = clientCode.getClientSession();
+ IdentityProvider identityProvider = getIdentityProvider(realm, providerId);
+
+ if (identityProvider == null) {
+ event.error(Errors.IDENTITY_PROVIDER_NOT_FOUND);
+ return Flows.forms(session, realm, null, uriInfo).setError("Identity Provider not found").createErrorPage();
+ }
+
+ AuthenticationResponse authenticationResponse = identityProvider.handleRequest(createAuthenticationRequest(providerId, code, realm,
+ clientSession));
+ Response response = authenticationResponse.getResponse();
+
+ if (response != null) {
+ event.success();
+ return response;
+ }
+ } catch (Exception e) {
+ String message = "Could not send authentication request to identity provider";
+ event.error(message);
+ return redirectToErrorPage(realm, message);
+ }
+
+ String message = "Could not proceed with authentication request to identity provider.";
+
+ event.error(message);
+
+ return redirectToErrorPage(realm, message);
+ }
+
+ @GET
+ @Path("{realm}/{provider_id}")
+ public Response handleResponseGet(@PathParam("realm") final String realmName,
+ @PathParam("provider_id") String providerId) {
+ return handleResponse(realmName, providerId);
+ }
+
+ @POST
+ @Path("{realm}/{provider_id}")
+ public Response handleResponsePost(@PathParam("realm") final String realmName,
+ @PathParam("provider_id") String providerId) {
+ return handleResponse(realmName, providerId);
+ }
+
+ private Response handleResponse(String realmName, String providerId) {
+ RealmManager realmManager = new RealmManager(session);
+ RealmModel realm = realmManager.getRealmByName(realmName);
+
+ try {
+ IdentityProvider provider = getIdentityProvider(realm, providerId);
+
+ if (provider == null) {
+ return Flows.forms(session, realm, null, uriInfo).setError("Social provider not found").createErrorPage();
+ }
+
+ String relayState = provider.getRelayState(createAuthenticationRequest(providerId, null, realm, null));
+
+ if (relayState == null) {
+ return redirectToErrorPage(realm, "No authorization code provided.");
+ }
+
+ ClientSessionCode clientCode = isValidAuthorizationCode(relayState, realm);
+
+ if (clientCode == null) {
+ return redirectToErrorPage(realm, "Invalid authorization code, please login again through your application.");
+ }
+
+ ClientSessionModel clientSession = clientCode.getClientSession();
+
+ AuthenticationResponse authenticationResponse = provider.handleResponse(createAuthenticationRequest(providerId, null, realm, clientSession));
+ Response response = authenticationResponse.getResponse();
+
+ if (response != null) {
+ return response;
+ }
+
+ FederatedIdentity socialUser = authenticationResponse.getUser();
+
+ return performLocalAuthentication(realm, providerId, socialUser, clientCode);
+ } catch (Exception e) {
+ if (session.getTransaction().isActive()) {
+ session.getTransaction().rollback();
+ }
+
+ IdentityProviderModel identityProviderConfig = getIdentityProviderConfig(realm, providerId);
+
+ return Flows.forms(session, realm, null, uriInfo).setError("Authentication failed. Could not authenticate against Identity Provider [" + identityProviderConfig.getName() + "].").createErrorPage();
+ } finally {
+ if (session.getTransaction().isActive()) {
+ session.getTransaction().commit();
+ }
+ }
+ }
+
+ private Response performLocalAuthentication(RealmModel realm, String providerId, FederatedIdentity socialUser, ClientSessionCode clientCode) {
+ ClientSessionModel clientSession = clientCode.getClientSession();
+ FederatedIdentityModel socialLink = new FederatedIdentityModel(providerId, socialUser.getId(),
+ socialUser.getUsername());
+ UserModel federatedUser = session.users().getUserByFederatedIdentity(socialLink, realm);
+ IdentityProviderModel identityProviderConfig = getIdentityProviderConfig(realm, providerId);
+
+ String authMethod = socialLink.getUserId() + "@" + identityProviderConfig.getId();
+ EventBuilder event = new EventsManager(realm, session, clientConnection).createEventBuilder()
+ .event(EventType.LOGIN)
+ .client(clientSession.getClient())
+ .detail(Details.REDIRECT_URI, clientSession.getRedirectUri())
+ .detail(Details.AUTH_METHOD, authMethod);
+
+ event.detail(Details.USERNAME, authMethod);
+
+ // Check if federatedUser is already authenticated (this means linking social into existing federatedUser account)
+ if (clientSession.getUserSession() != null) {
+ UserModel authenticatedUser = clientSession.getUserSession().getUser();
+
+ if (federatedUser != null) {
+ String message = "The identity returned by the Identity Provider [" + identityProviderConfig.getName() + "] is already linked to other user";
+ event.error(message);
+ return redirectToErrorPage(realm, message);
+ }
+
+ if (!authenticatedUser.isEnabled()) {
+ event.error(Errors.USER_DISABLED);
+ return redirectToErrorPage(realm, "User is disabled");
+ }
+
+ if (!authenticatedUser.hasRole(realm.getApplicationByName(ACCOUNT_MANAGEMENT_APP).getRole(MANAGE_ACCOUNT))) {
+ event.error(Errors.NOT_ALLOWED);
+ return redirectToErrorPage(realm, "Insufficient permissions to link identity");
+ }
+
+ session.users().addFederatedIdentity(realm, authenticatedUser, socialLink);
+
+ event.success();
+
+ return Response.status(302).location(UriBuilder.fromUri(clientSession.getRedirectUri()).build()).build();
+ }
+
+ UserModel user = session.users().getUserByEmail(socialUser.getEmail(), realm);
+ String errorMessage = "federatedIdentityEmailExists";
+
+ if (user == null) {
+ user = session.users().getUserByUsername(socialUser.getUsername(), realm);
+ errorMessage = "federatedIdentityUsernameExists";
+ }
+
+ if (user == null) {
+ federatedUser = session.users().addUser(realm, socialUser.getUsername());
+ federatedUser.setEnabled(true);
+ federatedUser.setFirstName(socialUser.getFirstName());
+ federatedUser.setLastName(socialUser.getLastName());
+ federatedUser.setEmail(socialUser.getEmail());
+
+ session.users().addFederatedIdentity(realm, federatedUser, socialLink);
+
+ event.clone().user(federatedUser).event(EventType.REGISTER)
+ .detail(Details.REGISTER_METHOD, authMethod)
+ .detail(Details.EMAIL, federatedUser.getEmail())
+ .removeDetail("auth_method")
+ .success();
+
+ if (identityProviderConfig.isUpdateProfileFirstLogin()) {
+ federatedUser.addRequiredAction(UPDATE_PROFILE);
+ }
+ } else {
+ if (federatedUser == null) {
+ return Flows.forms(session, realm, clientSession.getClient(), uriInfo)
+ .setClientSessionCode(clientCode.getCode())
+ .setError(errorMessage)
+ .createLogin();
+ }
+ }
+
+ event.user(federatedUser);
+
+ String username = socialLink.getUserId() + "@" + identityProviderConfig.getName();
+
+ UserSessionModel userSession = session.sessions()
+ .createUserSession(realm, federatedUser, username, clientConnection.getRemoteAddr(), "broker", false);
+
+ event.session(userSession);
+
+ TokenManager.attachClientSession(userSession, clientSession);
+
+ AuthenticationManager authManager = new AuthenticationManager();
+
+ return authManager.nextActionAfterAuthentication(session, userSession, clientSession, clientConnection, request,
+ uriInfo, event);
+ }
+
+ private ClientSessionCode isValidAuthorizationCode(String code, RealmModel realm) {
+ ClientSessionCode clientCode = ClientSessionCode.parse(code, this.session, realm);
+
+ if (clientCode != null && clientCode.isValid(AUTHENTICATE)) {
+ return clientCode;
+ }
+
+ return null;
+ }
+
+ private AuthenticationRequest createAuthenticationRequest(String providerId, String code, RealmModel realm, ClientSessionModel clientSession) {
+ return new AuthenticationRequest(realm, clientSession, this.request, this.uriInfo, code, getRedirectUri(providerId, realm));
+ }
+
+ private String getRedirectUri(String providerId, RealmModel realm) {
+ return UriBuilder.fromUri(this.uriInfo.getBaseUri())
+ .path(AuthenticationBrokerResource.class)
+ .path(AuthenticationBrokerResource.class, "handleResponseGet")
+ .build(realm.getName(), providerId)
+ .toString();
+ }
+
+ private Response redirectToErrorPage(RealmModel realm, String message) {
+ return Flows.forwardToSecurityFailurePage(this.session, realm, uriInfo, message);
+ }
+
+ private IdentityProvider getIdentityProvider(RealmModel realm, String providerId) {
+ for (IdentityProviderModel model : realm.getIdentityProviders()) {
+ if (model.getId().equals(providerId)) {
+ IdentityProviderFactory providerFactory = getIdentityProviderFactory(model);
+
+ if (providerFactory == null) {
+ throw new RuntimeException("Could not find provider factory for identity provider [" + providerId + "].");
+ }
+
+ return providerFactory.create(model);
+ }
+ }
+
+ return null;
+ }
+
+ private IdentityProviderFactory getIdentityProviderFactory(IdentityProviderModel model) {
+ Map availableProviders = new HashMap();
+ List allProviders = new ArrayList();
+
+ allProviders.addAll(this.session.getKeycloakSessionFactory().getProviderFactories(IdentityProvider.class));
+ allProviders.addAll(this.session.getKeycloakSessionFactory().getProviderFactories(SocialIdentityProvider.class));
+
+ for (ProviderFactory providerFactory : allProviders) {
+ availableProviders.put(providerFactory.getId(), (IdentityProviderFactory) providerFactory);
+ }
+
+ return availableProviders.get(model.getProviderId());
+ }
+
+ private IdentityProviderModel getIdentityProviderConfig(RealmModel realm, String providerId) {
+ for (IdentityProviderModel model : realm.getIdentityProviders()) {
+ if (model.getId().equals(providerId)) {
+ return model;
+ }
+ }
+
+ return null;
+ }
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
index 89874e6558..f3044ea26d 100755
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -72,7 +72,7 @@ public class KeycloakApplication extends Application {
singletons.add(new ServerVersionResource());
singletons.add(new RealmsResource());
- singletons.add(new SocialResource());
+ singletons.add(new AuthenticationBrokerResource());
singletons.add(new AdminRoot());
classes.add(SkeletonKeyContextResolver.class);
classes.add(QRCodeResource.class);
diff --git a/services/src/main/java/org/keycloak/services/resources/SocialResource.java b/services/src/main/java/org/keycloak/services/resources/SocialResource.java
deleted file mode 100755
index 195a9bfdf7..0000000000
--- a/services/src/main/java/org/keycloak/services/resources/SocialResource.java
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2012, Red Hat, Inc., and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.keycloak.services.resources;
-
-import org.jboss.logging.Logger;
-import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
-import org.jboss.resteasy.spi.HttpRequest;
-import org.keycloak.ClientConnection;
-import org.keycloak.events.Details;
-import org.keycloak.events.Errors;
-import org.keycloak.events.EventBuilder;
-import org.keycloak.events.EventType;
-import org.keycloak.models.AccountRoles;
-import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientSessionModel;
-import org.keycloak.models.Constants;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.ModelDuplicateException;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.SocialLinkModel;
-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.services.managers.AuthenticationManager;
-import org.keycloak.services.managers.ClientSessionCode;
-import org.keycloak.services.managers.EventsManager;
-import org.keycloak.services.managers.RealmManager;
-import org.keycloak.services.resources.flows.Flows;
-import org.keycloak.services.resources.flows.Urls;
-import org.keycloak.social.AuthCallback;
-import org.keycloak.social.SocialAccessDeniedException;
-import org.keycloak.social.SocialLoader;
-import org.keycloak.social.SocialProvider;
-import org.keycloak.social.SocialProviderConfig;
-import org.keycloak.social.SocialProviderException;
-import org.keycloak.social.SocialUser;
-
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-/**
- * @author Stian Thorgersen
- */
-@Path("/social")
-public class SocialResource {
-
- protected static Logger logger = Logger.getLogger(SocialResource.class);
-
- @Context
- protected UriInfo uriInfo;
-
- @Context
- protected HttpHeaders headers;
-
- @Context
- private HttpRequest request;
-
- @Context
- protected KeycloakSession session;
-
- @Context
- protected ClientConnection clientConnection;
-
- @GET
- @Path("callback")
- public Response callback(@QueryParam("state") String encodedState) throws URISyntaxException, IOException {
- ClientSessionCode clientCode = null;
- ClientSessionModel clientSession = null;
- try {
- clientCode = ClientSessionCode.parse(encodedState, session);
- if (clientCode == null) {
- return Flows.forms(session, null, null, uriInfo).setError("Unexpected callback").createErrorPage();
- }
- clientSession = clientCode.getClientSession();
- if (!clientCode.isValid(ClientSessionModel.Action.SOCIAL_CALLBACK)) {
- return Flows.forwardToSecurityFailurePage(session, clientSession.getRealm(), uriInfo, "Invalid code, please login again through your application.");
- }
- } catch (Throwable t) {
- logger.error("Invalid social callback", t);
- return Flows.forms(session, null, null, uriInfo).setError("Unexpected callback").createErrorPage();
- }
- String providerId = clientSession.getNote("social_provider");
- SocialProvider provider = SocialLoader.load(providerId);
-
- String authMethod = "social@" + provider.getId();
-
- RealmModel realm = clientSession.getRealm();
-
- EventBuilder event = new EventsManager(realm, session, clientConnection).createEventBuilder()
- .event(EventType.LOGIN)
- .client(clientSession.getClient())
- .detail(Details.REDIRECT_URI, clientSession.getRedirectUri())
- .detail(Details.AUTH_METHOD, authMethod);
-
- if (!realm.isEnabled()) {
- event.error(Errors.REALM_DISABLED);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Realm not enabled.");
- }
-
- String key = realm.getSocialConfig().get(provider.getId() + ".key");
- String secret = realm.getSocialConfig().get(provider.getId() + ".secret");
- String callbackUri = Urls.socialCallback(uriInfo.getBaseUri()).toString();
- SocialProviderConfig config = new SocialProviderConfig(key, secret, callbackUri);
-
- Map queryParams = getQueryParams();
-
- AuthCallback callback = new AuthCallback(queryParams);
-
- SocialUser socialUser;
- try {
- socialUser = provider.processCallback(clientSession, config, callback);
- } catch (SocialAccessDeniedException e) {
- event.error(Errors.REJECTED_BY_USER);
- clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE);
- return Flows.forms(session, realm, clientSession.getClient(), uriInfo).setClientSessionCode(clientCode.getCode()).setWarning("Access denied").createLogin();
- } catch (SocialProviderException e) {
- logger.error("Failed to process social callback", e);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Failed to process social callback");
- }
-
- event.detail(Details.USERNAME, socialUser.getId() + "@" + provider.getId());
-
- try {
- SocialLinkModel socialLink = new SocialLinkModel(provider.getId(), socialUser.getId(), socialUser.getUsername());
- UserModel user = session.users().getUserBySocialLink(socialLink, realm);
-
- // Check if user is already authenticated (this means linking social into existing user account)
- if (clientSession.getUserSession() != null) {
-
- UserModel authenticatedUser = clientSession.getUserSession().getUser();
-
- event.event(EventType.SOCIAL_LINK).user(authenticatedUser.getId());
-
- if (user != null) {
- event.error(Errors.SOCIAL_ID_IN_USE);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "This social account is already linked to other user");
- }
-
- if (!authenticatedUser.isEnabled()) {
- event.error(Errors.USER_DISABLED);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "User is disabled");
- }
-
- if (!authenticatedUser.hasRole(realm.getApplicationByName(Constants.ACCOUNT_MANAGEMENT_APP).getRole(AccountRoles.MANAGE_ACCOUNT))) {
- event.error(Errors.NOT_ALLOWED);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Insufficient permissions to link social account");
- }
-
- session.users().addSocialLink(realm, authenticatedUser, socialLink);
- logger.debugv("Social provider {0} linked with user {1}", provider.getId(), authenticatedUser.getUsername());
-
- event.success();
- return Response.status(302).location(UriBuilder.fromUri(clientSession.getRedirectUri()).build()).build();
- }
-
- if (user == null) {
- user = session.users().addUser(realm, KeycloakModelUtils.generateId());
- user.setEnabled(true);
- user.setFirstName(socialUser.getFirstName());
- user.setLastName(socialUser.getLastName());
- user.setEmail(socialUser.getEmail());
-
- if (realm.isUpdateProfileOnInitialSocialLogin()) {
- user.addRequiredAction(UserModel.RequiredAction.UPDATE_PROFILE);
- }
-
- session.users().addSocialLink(realm, user, socialLink);
-
- event.clone().user(user).event(EventType.REGISTER)
- .detail(Details.REGISTER_METHOD, "social@" + provider.getId())
- .detail(Details.EMAIL, socialUser.getEmail())
- .removeDetail("auth_method")
- .success();
- }
-
- event.user(user);
-
- if (!user.isEnabled()) {
- event.error(Errors.USER_DISABLED);
- return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Your account is not enabled.");
- }
-
- String username = socialLink.getSocialUserId() + "@" + socialLink.getSocialProvider();
-
- UserSessionModel userSession = session.sessions().createUserSession(realm, user, username, clientConnection.getRemoteAddr(), authMethod, false);
- event.session(userSession);
- TokenManager.attachClientSession(userSession, clientSession);
-
- AuthenticationManager authManager = new AuthenticationManager();
- Response response = authManager.nextActionAfterAuthentication(session, userSession, clientSession, clientConnection, request, uriInfo, event);
- if (session.getTransaction().isActive()) {
- session.getTransaction().commit();
- }
- return response;
- } catch (ModelDuplicateException e) {
- // Assume email is the duplicate as there's nothing else atm
- return Flows.forms(session, realm, clientSession.getClient(), uriInfo)
- .setClientSessionCode(clientCode.getCode())
- .setError("socialEmailExists")
- .createLogin();
- }
- }
-
- private class Checks {
- ClientSessionCode clientCode;
- Response response;
-
- private boolean checkSsl(RealmModel realm) {
- if (uriInfo.getBaseUri().getScheme().equals("https")) {
- return true;
- } else {
- return !realm.getSslRequired().isRequired(clientConnection);
- }
- }
-
-
- boolean check(EventBuilder event, RealmModel realm, String code, ClientSessionModel.Action requiredAction) {
- if (!checkSsl(realm)) {
- event.error(Errors.SSL_REQUIRED);
- response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "HTTPS required");
- return false;
- }
- if (!realm.isEnabled()) {
- event.error(Errors.REALM_DISABLED);
- response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Realm not enabled.");
- return false;
- }
- clientCode = ClientSessionCode.parse(code, session, realm);
- if (clientCode == null) {
- event.error(Errors.INVALID_CODE);
- response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Unknown code, please login again through your application.");
- return false;
- }
- if (!clientCode.isValid(requiredAction)) {
- event.error(Errors.INVALID_CODE);
- response = Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Invalid code, please login again through your application.");
- }
- return true;
- }
- }
-
-
- @GET
- @Path("{realm}/login")
- public Response redirectToProviderAuth(@PathParam("realm") final String realmName,
- @QueryParam("provider_id") final String providerId,
- @QueryParam("code") String code) {
- RealmManager realmManager = new RealmManager(session);
- RealmModel realm = realmManager.getRealmByName(realmName);
-
- EventBuilder event = new EventsManager(realm, session, clientConnection).createEventBuilder()
- .event(EventType.LOGIN)
- .detail(Details.AUTH_METHOD, "social@" + providerId);
-
- SocialProvider provider = SocialLoader.load(providerId);
- if (provider == null) {
- event.error(Errors.SOCIAL_PROVIDER_NOT_FOUND);
- return Flows.forms(session, realm, null, uriInfo).setError("Social provider not found").createErrorPage();
- }
-
- Checks checks = new Checks();
- if (!checks.check(event, realm, code, ClientSessionModel.Action.AUTHENTICATE)) {
- return checks.response;
- }
-
- ClientSessionCode clientSessionCode = checks.clientCode;
-
- try {
- return Flows.social(realm, uriInfo, clientConnection, provider)
- .redirectToSocialProvider(clientSessionCode);
- } catch (Throwable t) {
- logger.error("Failed to redirect to social auth", t);
- return Flows.forms(session, realm, null, uriInfo).setError("Failed to redirect to social auth").createErrorPage();
- }
- }
-
- private Response returnToLogin(RealmModel realm, ClientModel client, Map attributes, String error) {
- MultivaluedMap q = new MultivaluedMapImpl();
- for (Entry e : attributes.entrySet()) {
- q.add(e.getKey(), e.getValue());
- }
- return Flows.forms(session, realm, client, uriInfo)
- .setQueryParams(q)
- .setError(error)
- .createLogin();
- }
-
- private Map getQueryParams() {
- Map queryParams = new HashMap();
- for (Entry> e : uriInfo.getQueryParameters().entrySet()) {
- queryParams.put(e.getKey(), e.getValue().toArray(new String[e.getValue().size()]));
- }
- return queryParams;
- }
-
-}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
new file mode 100755
index 0000000000..fc0e6cac0b
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
@@ -0,0 +1,145 @@
+package org.keycloak.services.resources.admin;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.jboss.resteasy.plugins.providers.multipart.InputPart;
+import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
+import org.keycloak.broker.provider.IdentityProvider;
+import org.keycloak.broker.provider.IdentityProviderFactory;
+import org.keycloak.models.IdentityProviderModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.social.SocialIdentityProvider;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
+
+/**
+ * @author Pedro Igor
+ */
+public class IdentityProviderResource {
+
+ private final RealmModel realm;
+ private final KeycloakSession session;
+
+ public IdentityProviderResource(RealmModel realm, KeycloakSession session) {
+ this.realm = realm;
+ this.session = session;
+ }
+
+ @GET
+ @NoCache
+ @Produces("application/json")
+ public List getIdentityProviders() {
+ return realm.getIdentityProviders();
+ }
+
+ @Path("/providers/{provider_id}")
+ @GET
+ @NoCache
+ @Produces("application/json")
+ public Response getIdentityProviders(@PathParam("provider_id") String providerId) {
+ IdentityProviderFactory providerFactory = getProviderFactorytById(providerId);
+
+ if (providerFactory != null) {
+ return Response.ok(providerFactory).build();
+ }
+
+ return Response.status(BAD_REQUEST).build();
+ }
+
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response create(@Context UriInfo uriInfo, IdentityProviderModel providerModel) {
+ realm.addIdentityProvider(providerModel);
+
+ return Response.created(uriInfo.getAbsolutePathBuilder().path(providerModel.getProviderId()).build()).build();
+ }
+
+ @POST
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ public Response createWithFile(@Context UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
+ Map> formDataMap = input.getFormDataMap();
+
+ String id = formDataMap.get("id").get(0).getBodyAsString();
+ String name = formDataMap.get("name").get(0).getBodyAsString();
+ String providerId = formDataMap.get("providerId").get(0).getBodyAsString();
+ String enabled = formDataMap.get("enabled").get(0).getBodyAsString();
+ String updateProfileFirstLogin = formDataMap.get("updateProfileFirstLogin").get(0).getBodyAsString();
+ InputPart file = formDataMap.get("file").get(0);
+ InputStream inputStream = file.getBody(InputStream.class, null);
+ IdentityProviderFactory providerFactory = getProviderFactorytById(providerId);
+ Map config = providerFactory.parseConfig(inputStream);
+ IdentityProviderModel providerModel = new IdentityProviderModel();
+
+ providerModel.setId(id);
+ providerModel.setName(name);
+ providerModel.setProviderId(providerId);
+ providerModel.setEnabled(Boolean.valueOf(enabled));
+ providerModel.setUpdateProfileFirstLogin(Boolean.valueOf(updateProfileFirstLogin));
+ providerModel.setConfig(config);
+
+ return create(uriInfo, providerModel);
+ }
+
+ @Path("{id}")
+ @GET
+ @NoCache
+ @Produces("application/json")
+ public Response getIdentityProvider(@PathParam("id") String providerId) {
+ for (IdentityProviderModel identityProviderModel : this.realm.getIdentityProviders()) {
+ if (identityProviderModel.getId().equals(providerId)) {
+ return Response.ok(identityProviderModel).build();
+ }
+ }
+
+ return Response.noContent().build();
+ }
+
+ @Path("{id}")
+ @DELETE
+ @NoCache
+ public Response delete(@PathParam("id") String providerId) {
+ this.realm.removeIdentityProviderById(providerId);
+ return Response.noContent().build();
+ }
+
+ @PUT
+ @Consumes("application/json")
+ public Response update(IdentityProviderModel model) {
+ this.realm.updateIdentityProvider(model);
+ return Response.noContent().build();
+ }
+
+ private IdentityProviderFactory getProviderFactorytById(String providerId) {
+ List allProviders = new ArrayList();
+
+ allProviders.addAll(this.session.getKeycloakSessionFactory().getProviderFactories(IdentityProvider.class));
+ allProviders.addAll(this.session.getKeycloakSessionFactory().getProviderFactories(SocialIdentityProvider.class));
+
+ for (ProviderFactory providerFactory : allProviders) {
+ if (providerFactory.getId().equals(providerId)) {
+ return (IdentityProviderFactory) providerFactory;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index b2766bb058..51a39f79f8 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -445,4 +445,9 @@ public class RealmAdminResource {
boolean result = new LDAPConnectionTestManager().testLDAP(action, connectionUrl, bindDn, bindCredential);
return result ? Response.noContent().build() : Flows.errors().error("LDAP test error", Response.Status.BAD_REQUEST);
}
+
+ @Path("identity-provider")
+ public IdentityProviderResource getIdentityProviderResource() {
+ return new IdentityProviderResource(realm, session);
+ }
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java
index 837b56b8a8..2ac929ded4 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java
@@ -1,6 +1,8 @@
package org.keycloak.services.resources.admin;
import org.keycloak.Version;
+import org.keycloak.broker.provider.IdentityProvider;
+import org.keycloak.broker.provider.IdentityProviderFactory;
import org.keycloak.events.EventListenerProvider;
import org.keycloak.exportimport.ApplicationImporter;
import org.keycloak.exportimport.ApplicationImporterFactory;
@@ -8,16 +10,15 @@ import org.keycloak.freemarker.Theme;
import org.keycloak.freemarker.ThemeProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.protocol.LoginProtocol;
-import org.keycloak.protocol.LoginProtocolFactory;
-import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.Spi;
-import org.keycloak.social.SocialProvider;
-import org.keycloak.util.ProviderLoader;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.social.SocialIdentityProvider;
import javax.ws.rs.GET;
import javax.ws.rs.core.Context;
import java.util.Collections;
+import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
@@ -45,6 +46,7 @@ public class ServerInfoAdminResource {
info.version = Version.VERSION;
info.serverTime = new Date().toString();
setSocialProviders(info);
+ setIdentityProviders(info);
setThemes(info);
setEventListeners(info);
setProtocols(info);
@@ -74,11 +76,38 @@ public class ServerInfoAdminResource {
}
private void setSocialProviders(ServerInfoRepresentation info) {
- info.socialProviders = new LinkedList();
- for (SocialProvider p : ProviderLoader.load(SocialProvider.class)) {
- info.socialProviders.add(p.getId());
+ info.socialProviders = new LinkedList();
+ List