From 98d2fe15e821df8d39a05fffce9a6b81f8ef8553 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 18 Aug 2016 08:02:05 -0300 Subject: [PATCH] [KEYCLOAK-2438] - Add display name to social login buttons [KEYCLOAK-3291] - Names of social identity providers are wrongly capitalized (eg GitHub vs Github) --- .../idm/IdentityProviderRepresentation.java | 9 ++++++ .../org/keycloak/models/jpa/RealmAdapter.java | 30 +++++++++++++++---- .../jpa/entities/IdentityProviderEntity.java | 11 +++++++ .../META-INF/jpa-changelog-2.2.0.xml | 6 +++- .../mongo/keycloak/adapters/RealmAdapter.java | 4 ++- .../models/IdentityProviderModel.java | 11 +++++++ .../entities/IdentityProviderEntity.java | 9 ++++++ .../models/utils/KeycloakModelUtils.java | 29 +++++++++++++++--- .../models/utils/ModelToRepresentation.java | 1 + .../models/utils/RepresentationToModel.java | 1 + .../model/AccountFederatedIdentityBean.java | 16 ++++++++-- .../FreeMarkerLoginFormsProvider.java | 5 ++-- .../model/IdentityProviderBean.java | 26 +++++++++++----- .../model/IdentityProviderBeanTest.java | 16 +++++----- .../testsuite/account/AccountTest.java | 24 +++++++++++++++ .../testsuite/admin/AbstractAdminTest.java | 9 +----- .../testsuite/admin/ConsentsTest.java | 1 + .../testsuite/admin/IdentityProviderTest.java | 1 + .../testsuite/admin/PermissionsTest.java | 3 +- .../testsuite/broker/AbstractBrokerTest.java | 1 + .../testsuite/i18n/LoginPageTest.java | 29 ++++++++++++++++++ .../util/IdentityProviderBuilder.java | 5 ++++ .../broker-test/test-realm-with-broker.json | 3 ++ .../theme/base/account/federatedIdentity.ftl | 2 +- .../messages/admin-messages_en.properties | 2 ++ .../admin/resources/js/controllers/realm.js | 16 +++++++++- .../identity-provider-mapper-detail.html | 2 +- .../partials/identity-provider-mappers.html | 2 +- .../realm-identity-provider-export.html | 2 +- .../realm-identity-provider-oidc.html | 9 +++++- .../realm-identity-provider-saml.html | 9 +++++- .../realm-identity-provider-social.html | 2 +- .../partials/realm-identity-provider.html | 2 +- .../templates/kc-tabs-identity-provider.html | 2 +- .../main/resources/theme/base/login/login.ftl | 2 +- .../keycloak/login/resources/css/login.css | 3 -- 36 files changed, 249 insertions(+), 56 deletions(-) mode change 100755 => 100644 themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js diff --git a/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java index 2466f12e4f..40b530181e 100755 --- a/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/IdentityProviderRepresentation.java @@ -25,6 +25,7 @@ import java.util.Map; public class IdentityProviderRepresentation { protected String alias; + protected String displayName; protected String internalId; protected String providerId; protected boolean enabled = true; @@ -176,4 +177,12 @@ public class IdentityProviderRepresentation { this.trustEmail = trustEmail; } + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + } 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 a5747c6285..21aa8d0648 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 @@ -18,10 +18,9 @@ package org.keycloak.models.jpa; import org.jboss.logging.Logger; -import org.keycloak.common.util.MultivaluedHashMap; -import org.keycloak.common.util.StringPropertyReplacer; -import org.keycloak.component.ComponentModel; import org.keycloak.common.enums.SslRequired; +import org.keycloak.common.util.MultivaluedHashMap; +import org.keycloak.component.ComponentModel; import org.keycloak.jose.jwk.JWKBuilder; import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.AuthenticationFlowModel; @@ -43,12 +42,28 @@ import org.keycloak.models.RoleModel; import org.keycloak.models.UserFederationMapperModel; import org.keycloak.models.UserFederationProviderCreationEventImpl; import org.keycloak.models.UserFederationProviderModel; -import org.keycloak.models.jpa.entities.*; +import org.keycloak.models.jpa.entities.AuthenticationExecutionEntity; +import org.keycloak.models.jpa.entities.AuthenticationFlowEntity; +import org.keycloak.models.jpa.entities.AuthenticatorConfigEntity; +import org.keycloak.models.jpa.entities.ClientEntity; +import org.keycloak.models.jpa.entities.ClientTemplateEntity; +import org.keycloak.models.jpa.entities.ComponentConfigEntity; +import org.keycloak.models.jpa.entities.ComponentEntity; +import org.keycloak.models.jpa.entities.GroupEntity; +import org.keycloak.models.jpa.entities.IdentityProviderEntity; +import org.keycloak.models.jpa.entities.IdentityProviderMapperEntity; +import org.keycloak.models.jpa.entities.RealmAttributeEntity; +import org.keycloak.models.jpa.entities.RealmAttributes; +import org.keycloak.models.jpa.entities.RealmEntity; +import org.keycloak.models.jpa.entities.RequiredActionProviderEntity; +import org.keycloak.models.jpa.entities.RequiredCredentialEntity; +import org.keycloak.models.jpa.entities.RoleEntity; +import org.keycloak.models.jpa.entities.UserFederationMapperEntity; +import org.keycloak.models.jpa.entities.UserFederationProviderEntity; import org.keycloak.models.utils.KeycloakModelUtils; import javax.persistence.EntityManager; import javax.persistence.TypedQuery; - import java.security.Key; import java.security.PrivateKey; import java.security.PublicKey; @@ -1255,9 +1270,10 @@ public class RealmAdapter implements RealmModel, JpaModel { for (IdentityProviderEntity entity: entities) { IdentityProviderModel identityProviderModel = new IdentityProviderModel(); - identityProviderModel.setProviderId(entity.getProviderId()); identityProviderModel.setAlias(entity.getAlias()); + identityProviderModel.setDisplayName(entity.getDisplayName()); + identityProviderModel.setInternalId(entity.getInternalId()); Map config = entity.getConfig(); Map copy = new HashMap<>(); @@ -1294,6 +1310,7 @@ public class RealmAdapter implements RealmModel, JpaModel { entity.setInternalId(KeycloakModelUtils.generateId()); entity.setAlias(identityProvider.getAlias()); + entity.setDisplayName(identityProvider.getDisplayName()); entity.setProviderId(identityProvider.getProviderId()); entity.setEnabled(identityProvider.isEnabled()); entity.setStoreToken(identityProvider.isStoreToken()); @@ -1327,6 +1344,7 @@ public class RealmAdapter implements RealmModel, JpaModel { for (IdentityProviderEntity entity : this.realm.getIdentityProviders()) { if (entity.getInternalId().equals(identityProvider.getInternalId())) { entity.setAlias(identityProvider.getAlias()); + entity.setDisplayName(identityProvider.getDisplayName()); entity.setEnabled(identityProvider.isEnabled()); entity.setTrustEmail(identityProvider.isTrustEmail()); entity.setAuthenticateByDefault(identityProvider.isAuthenticateByDefault()); 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 index 77ca6147ed..9a94431208 100755 --- 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 @@ -59,6 +59,9 @@ public class IdentityProviderEntity { @Column(name="PROVIDER_ALIAS") private String alias; + @Column(name="PROVIDER_DISPLAY_NAME") + private String displayName; + @Column(name="ENABLED") private boolean enabled; @@ -182,6 +185,14 @@ public class IdentityProviderEntity { this.trustEmail = trustEmail; } + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/model/jpa/src/main/resources/META-INF/jpa-changelog-2.2.0.xml b/model/jpa/src/main/resources/META-INF/jpa-changelog-2.2.0.xml index adc49fbf3d..39e7fe4a12 100755 --- a/model/jpa/src/main/resources/META-INF/jpa-changelog-2.2.0.xml +++ b/model/jpa/src/main/resources/META-INF/jpa-changelog-2.2.0.xml @@ -24,6 +24,10 @@ + + + + @@ -58,4 +62,4 @@ - \ No newline at end of file + 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 86a90013cc..85592b0483 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 @@ -21,7 +21,6 @@ import com.mongodb.DBObject; import com.mongodb.QueryBuilder; import org.keycloak.common.util.MultivaluedHashMap; -import org.keycloak.common.util.StringPropertyReplacer; import org.keycloak.component.ComponentModel; import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext; import org.keycloak.common.enums.SslRequired; @@ -914,6 +913,7 @@ public class RealmAdapter extends AbstractMongoAdapter impleme identityProviderModel.setProviderId(entity.getProviderId()); identityProviderModel.setAlias(entity.getAlias()); + identityProviderModel.setDisplayName(entity.getDisplayName()); identityProviderModel.setInternalId(entity.getInternalId()); Map config = entity.getConfig(); Map copy = new HashMap<>(); @@ -950,6 +950,7 @@ public class RealmAdapter extends AbstractMongoAdapter impleme entity.setInternalId(KeycloakModelUtils.generateId()); entity.setAlias(identityProvider.getAlias()); + entity.setDisplayName(identityProvider.getDisplayName()); entity.setProviderId(identityProvider.getProviderId()); entity.setEnabled(identityProvider.isEnabled()); entity.setTrustEmail(identityProvider.isTrustEmail()); @@ -980,6 +981,7 @@ public class RealmAdapter extends AbstractMongoAdapter impleme for (IdentityProviderEntity entity : this.realm.getIdentityProviders()) { if (entity.getInternalId().equals(identityProvider.getInternalId())) { entity.setAlias(identityProvider.getAlias()); + entity.setDisplayName(identityProvider.getDisplayName()); entity.setEnabled(identityProvider.isEnabled()); entity.setTrustEmail(identityProvider.isTrustEmail()); entity.setAuthenticateByDefault(identityProvider.isAuthenticateByDefault()); diff --git a/server-spi/src/main/java/org/keycloak/models/IdentityProviderModel.java b/server-spi/src/main/java/org/keycloak/models/IdentityProviderModel.java index 2425c7d877..41a1e41fee 100755 --- a/server-spi/src/main/java/org/keycloak/models/IdentityProviderModel.java +++ b/server-spi/src/main/java/org/keycloak/models/IdentityProviderModel.java @@ -57,6 +57,8 @@ public class IdentityProviderModel implements Serializable { private String postBrokerLoginFlowId; + private String displayName; + /** *

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.

@@ -70,6 +72,7 @@ public class IdentityProviderModel implements Serializable { this.internalId = model.getInternalId(); this.providerId = model.getProviderId(); this.alias = model.getAlias(); + this.displayName = model.getDisplayName(); this.config = new HashMap(model.getConfig()); this.enabled = model.isEnabled(); this.trustEmail = model.isTrustEmail(); @@ -169,5 +172,13 @@ public class IdentityProviderModel implements Serializable { public void setTrustEmail(boolean trustEmail) { this.trustEmail = trustEmail; } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } } diff --git a/server-spi/src/main/java/org/keycloak/models/entities/IdentityProviderEntity.java b/server-spi/src/main/java/org/keycloak/models/entities/IdentityProviderEntity.java index e23198e696..b0c39ffa75 100755 --- a/server-spi/src/main/java/org/keycloak/models/entities/IdentityProviderEntity.java +++ b/server-spi/src/main/java/org/keycloak/models/entities/IdentityProviderEntity.java @@ -26,6 +26,7 @@ public class IdentityProviderEntity { private String internalId; private String alias; + private String displayName; private String providerId; private String name; private boolean enabled; @@ -134,6 +135,14 @@ public class IdentityProviderEntity { this.trustEmail = trustEmail; } + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/server-spi/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java b/server-spi/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java index b8adc6271d..928963cf17 100755 --- a/server-spi/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java +++ b/server-spi/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java @@ -18,6 +18,8 @@ package org.keycloak.models.utils; import org.bouncycastle.openssl.PEMWriter; +import org.keycloak.broker.social.SocialIdentityProvider; +import org.keycloak.broker.social.SocialIdentityProviderFactory; import org.keycloak.common.util.Base64Url; import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.AuthenticationFlowModel; @@ -47,8 +49,6 @@ import org.keycloak.common.util.PemUtils; import org.keycloak.transaction.JtaTransactionManagerLookup; import javax.crypto.spec.SecretKeySpec; -import javax.naming.InitialContext; -import javax.sql.DataSource; import javax.transaction.InvalidTransactionException; import javax.transaction.SystemException; import javax.transaction.Transaction; @@ -62,7 +62,6 @@ import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.cert.X509Certificate; -import java.sql.DriverManager; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -70,7 +69,6 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; -import java.util.function.Function; /** * Set of helper methods, which are useful in various model implementations. @@ -689,4 +687,27 @@ public final class KeycloakModelUtils { } } + + /** + * Retrieve display name based on identity provider type + * @param session + * @param displayName + * @param providerId + * @return + */ + public static String getIdentityProviderDisplayName(KeycloakSession session, String displayName, String providerId) { + + SocialIdentityProviderFactory providerFactory = (SocialIdentityProviderFactory) session.getKeycloakSessionFactory() + .getProviderFactory(SocialIdentityProvider.class, providerId); + + if ((displayName == null || displayName.isEmpty()) && (providerId.contains("saml") || providerId.contains("oidc"))) { + return providerId; + } else if (providerFactory != null && (displayName == null || displayName.isEmpty())) { + return providerFactory.getName(); + } else { + return displayName; + } + } + + } diff --git a/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java index 659c116419..e5e888d27f 100755 --- a/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java +++ b/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java @@ -627,6 +627,7 @@ public class ModelToRepresentation { providerRep.setInternalId(identityProviderModel.getInternalId()); providerRep.setProviderId(identityProviderModel.getProviderId()); providerRep.setAlias(identityProviderModel.getAlias()); + providerRep.setDisplayName(identityProviderModel.getDisplayName()); providerRep.setEnabled(identityProviderModel.isEnabled()); providerRep.setStoreToken(identityProviderModel.isStoreToken()); providerRep.setTrustEmail(identityProviderModel.isTrustEmail()); diff --git a/server-spi/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/server-spi/src/main/java/org/keycloak/models/utils/RepresentationToModel.java index f228bc7631..4cfdfd06bc 100755 --- a/server-spi/src/main/java/org/keycloak/models/utils/RepresentationToModel.java +++ b/server-spi/src/main/java/org/keycloak/models/utils/RepresentationToModel.java @@ -1524,6 +1524,7 @@ public class RepresentationToModel { identityProviderModel.setInternalId(representation.getInternalId()); identityProviderModel.setAlias(representation.getAlias()); + identityProviderModel.setDisplayName(representation.getDisplayName()); identityProviderModel.setProviderId(representation.getProviderId()); identityProviderModel.setEnabled(representation.isEnabled()); identityProviderModel.setTrustEmail(representation.isTrustEmail()); diff --git a/services/src/main/java/org/keycloak/forms/account/freemarker/model/AccountFederatedIdentityBean.java b/services/src/main/java/org/keycloak/forms/account/freemarker/model/AccountFederatedIdentityBean.java index a20810e8a0..5ef319c206 100755 --- a/services/src/main/java/org/keycloak/forms/account/freemarker/model/AccountFederatedIdentityBean.java +++ b/services/src/main/java/org/keycloak/forms/account/freemarker/model/AccountFederatedIdentityBean.java @@ -22,6 +22,7 @@ import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; +import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.services.resources.AccountService; import org.keycloak.services.Urls; @@ -70,7 +71,9 @@ public class AccountFederatedIdentityBean { .queryParam("stateChecker", stateChecker) .build().toString(); - FederatedIdentityEntry entry = new FederatedIdentityEntry(identity, provider.getAlias(), provider.getAlias(), actionUrl, + String displayName = KeycloakModelUtils.getIdentityProviderDisplayName(session, + provider.getDisplayName(), provider.getProviderId()); + FederatedIdentityEntry entry = new FederatedIdentityEntry(identity, displayName, provider.getAlias(), provider.getAlias(), actionUrl, provider.getConfig() != null ? provider.getConfig().get("guiOrder") : null); orderedSet.add(entry); } @@ -106,10 +109,12 @@ public class AccountFederatedIdentityBean { private final String providerName; private final String actionUrl; private final String guiOrder; + private final String displayName; - public FederatedIdentityEntry(FederatedIdentityModel federatedIdentityModel, String providerId, String providerName, String actionUrl, String guiOrder - ) { + public FederatedIdentityEntry(FederatedIdentityModel federatedIdentityModel, String displayName, String providerId, + String providerName, String actionUrl, String guiOrder) { this.federatedIdentityModel = federatedIdentityModel; + this.displayName = displayName; this.providerId = providerId; this.providerName = providerName; this.actionUrl = actionUrl; @@ -143,6 +148,11 @@ public class AccountFederatedIdentityBean { public String getGuiOrder() { return guiOrder; } + + public String getDisplayName() { + return displayName; + } + } public static class IdentityProviderComparator implements Comparator { diff --git a/services/src/main/java/org/keycloak/forms/login/freemarker/FreeMarkerLoginFormsProvider.java b/services/src/main/java/org/keycloak/forms/login/freemarker/FreeMarkerLoginFormsProvider.java index 631ff5792e..515ab76d48 100755 --- a/services/src/main/java/org/keycloak/forms/login/freemarker/FreeMarkerLoginFormsProvider.java +++ b/services/src/main/java/org/keycloak/forms/login/freemarker/FreeMarkerLoginFormsProvider.java @@ -250,7 +250,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider { List identityProviders = realm.getIdentityProviders(); identityProviders = LoginFormsUtil.filterIdentityProviders(identityProviders, session, realm, attributes, formData); - attributes.put("social", new IdentityProviderBean(realm, identityProviders, baseUri, uriInfo)); + attributes.put("social", new IdentityProviderBean(realm, session, identityProviders, baseUri, uriInfo)); attributes.put("url", new UrlBean(realm, theme, baseUri, this.actionUri)); @@ -398,7 +398,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider { List identityProviders = realm.getIdentityProviders(); identityProviders = LoginFormsUtil.filterIdentityProviders(identityProviders, session, realm, attributes, formData); - attributes.put("social", new IdentityProviderBean(realm, identityProviders, baseUri, uriInfo)); + attributes.put("social", new IdentityProviderBean(realm, session, identityProviders, baseUri, uriInfo)); attributes.put("url", new UrlBean(realm, theme, baseUri, this.actionUri)); attributes.put("requiredActionUrl", new RequiredActionUrlFormatterMethod(realm, baseUri)); @@ -425,7 +425,6 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider { } } - @Override public Response createLogin() { return createResponse(LoginFormsPages.LOGIN); diff --git a/services/src/main/java/org/keycloak/forms/login/freemarker/model/IdentityProviderBean.java b/services/src/main/java/org/keycloak/forms/login/freemarker/model/IdentityProviderBean.java index 830166039c..c31bea748f 100755 --- a/services/src/main/java/org/keycloak/forms/login/freemarker/model/IdentityProviderBean.java +++ b/services/src/main/java/org/keycloak/forms/login/freemarker/model/IdentityProviderBean.java @@ -17,7 +17,9 @@ package org.keycloak.forms.login.freemarker.model; import org.keycloak.models.IdentityProviderModel; +import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; +import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.services.Urls; import javax.ws.rs.core.UriInfo; @@ -35,12 +37,13 @@ import java.util.TreeSet; public class IdentityProviderBean { private boolean displaySocial; - private List providers; private RealmModel realm; + private final KeycloakSession session; - public IdentityProviderBean(RealmModel realm, List identityProviders, URI baseURI, UriInfo uriInfo) { + public IdentityProviderBean(RealmModel realm, KeycloakSession session, List identityProviders, URI baseURI, UriInfo uriInfo) { this.realm = realm; + this.session = session; if (!identityProviders.isEmpty()) { Set orderedSet = new TreeSet<>(IdentityProviderComparator.INSTANCE); @@ -59,7 +62,11 @@ public class IdentityProviderBean { private void addIdentityProvider(Set orderedSet, RealmModel realm, URI baseURI, IdentityProviderModel identityProvider) { String loginUrl = Urls.identityProviderAuthnRequest(baseURI, identityProvider.getAlias(), realm.getName()).toString(); - orderedSet.add(new IdentityProvider(identityProvider.getAlias(), identityProvider.getProviderId(), loginUrl, + String displayName = KeycloakModelUtils.getIdentityProviderDisplayName(session, + identityProvider.getDisplayName(), identityProvider.getProviderId()); + + orderedSet.add(new IdentityProvider(identityProvider.getAlias(), + displayName, identityProvider.getProviderId(), loginUrl, identityProvider.getConfig() != null ? identityProvider.getConfig().get("guiOrder") : null)); } @@ -77,9 +84,11 @@ public class IdentityProviderBean { private final String providerId; // This refer to providerType (facebook, google, etc.) private final String loginUrl; private final String guiOrder; + private final String displayName; - public IdentityProvider(String alias, String providerId, String loginUrl, String guiOrder) { + public IdentityProvider(String alias, String displayName, String providerId, String loginUrl, String guiOrder) { this.alias = alias; + this.displayName = displayName; this.providerId = providerId; this.loginUrl = loginUrl; this.guiOrder = guiOrder; @@ -100,6 +109,10 @@ public class IdentityProviderBean { public String getGuiOrder() { return guiOrder; } + + public String getDisplayName() { + return displayName; + } } public static class IdentityProviderComparator implements Comparator { @@ -112,7 +125,7 @@ public class IdentityProviderBean { @Override public int compare(IdentityProvider o1, IdentityProvider o2) { - + int o1order = parseOrder(o1); int o2order = parseOrder(o2); @@ -120,7 +133,7 @@ public class IdentityProviderBean { return 1; else if (o1order < o2order) return -1; - + return 1; } @@ -134,6 +147,5 @@ public class IdentityProviderBean { } return 10000; } - } } diff --git a/services/src/test/java/org/keycloak/test/login/freemarker/model/IdentityProviderBeanTest.java b/services/src/test/java/org/keycloak/test/login/freemarker/model/IdentityProviderBeanTest.java index ff4c3686a8..0598ef635c 100755 --- a/services/src/test/java/org/keycloak/test/login/freemarker/model/IdentityProviderBeanTest.java +++ b/services/src/test/java/org/keycloak/test/login/freemarker/model/IdentityProviderBeanTest.java @@ -32,32 +32,32 @@ public class IdentityProviderBeanTest { @Test public void testIdentityProviderComparator() { - IdentityProvider o1 = new IdentityProvider("alias1", "id1", "ur1", null); - IdentityProvider o2 = new IdentityProvider("alias2", "id2", "ur2", null); + IdentityProvider o1 = new IdentityProvider("alias1", "displayName1", "id1", "ur1", null); + IdentityProvider o2 = new IdentityProvider("alias2", "displayName2", "id2", "ur2", null); // guiOrder not defined at any object - first is always lower Assert.assertEquals(1, IdentityProviderComparator.INSTANCE.compare(o1, o2)); Assert.assertEquals(1, IdentityProviderComparator.INSTANCE.compare(o2, o1)); // guiOrder is not a number so it is same as not defined - first is always lower - o1 = new IdentityProvider("alias1", "id1", "ur1", "not a number"); + o1 = new IdentityProvider("alias1", "displayName1", "id1", "ur1", "not a number"); Assert.assertEquals(1, IdentityProviderComparator.INSTANCE.compare(o1, o2)); Assert.assertEquals(1, IdentityProviderComparator.INSTANCE.compare(o2, o1)); // guiOrder is defined for one only to it is always first - o1 = new IdentityProvider("alias1", "id1", "ur1", "0"); + o1 = new IdentityProvider("alias1", "displayName1", "id1", "ur1", "0"); Assert.assertEquals(-1, IdentityProviderComparator.INSTANCE.compare(o1, o2)); Assert.assertEquals(1, IdentityProviderComparator.INSTANCE.compare(o2, o1)); // guiOrder is defined for both but is same - first is always lower - o1 = new IdentityProvider("alias1", "id1", "ur1", "0"); - o2 = new IdentityProvider("alias2", "id2", "ur2", "0"); + o1 = new IdentityProvider("alias1", "displayName1", "id1", "ur1", "0"); + o2 = new IdentityProvider("alias2", "displayName2", "id2", "ur2", "0"); Assert.assertEquals(1, IdentityProviderComparator.INSTANCE.compare(o1, o2)); Assert.assertEquals(1, IdentityProviderComparator.INSTANCE.compare(o2, o1)); // guiOrder is reflected - o1 = new IdentityProvider("alias1", "id1", "ur1", "0"); - o2 = new IdentityProvider("alias2", "id2", "ur2", "1"); + o1 = new IdentityProvider("alias1", "displayName1", "id1", "ur1", "0"); + o2 = new IdentityProvider("alias2", "displayName2", "id2", "ur2", "1"); Assert.assertEquals(-1, IdentityProviderComparator.INSTANCE.compare(o1, o2)); Assert.assertEquals(1, IdentityProviderComparator.INSTANCE.compare(o2, o1)); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java index 35d11d15f4..4d45b2182f 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java @@ -38,6 +38,7 @@ import org.keycloak.testsuite.pages.AppPage.RequestType; import org.keycloak.testsuite.pages.ErrorPage; import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.pages.RegisterPage; +import org.keycloak.testsuite.util.IdentityProviderBuilder; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; @@ -75,6 +76,20 @@ public class AccountTest extends TestRealmKeycloakTest { .password("password") .build(); + testRealm.addIdentityProvider(IdentityProviderBuilder.create() + .providerId("github") + .alias("github") + .build()); + testRealm.addIdentityProvider(IdentityProviderBuilder.create() + .providerId("saml") + .alias("saml") + .build()); + testRealm.addIdentityProvider(IdentityProviderBuilder.create() + .providerId("oidc") + .alias("oidc") + .displayName("MyOIDC") + .build()); + RealmBuilder.edit(testRealm) .user(user2); } @@ -790,4 +805,13 @@ public class AccountTest extends TestRealmKeycloakTest { events.clear(); } + @Test + public void testIdentityProviderCapitalization(){ + loginPage.open(); + Assert.assertEquals("GitHub", loginPage.findSocialButton("github").getText()); + Assert.assertEquals("saml", loginPage.findSocialButton("saml").getText()); + Assert.assertEquals("MyOIDC", loginPage.findSocialButton("oidc").getText()); + + } + } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/AbstractAdminTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/AbstractAdminTest.java index e538dcc5e5..5d51db4fc3 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/AbstractAdminTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/AbstractAdminTest.java @@ -20,9 +20,6 @@ package org.keycloak.testsuite.admin; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -31,16 +28,12 @@ import org.junit.Before; import org.junit.Rule; import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.events.log.JBossLoggingEventListenerProviderFactory; -import org.keycloak.representations.idm.ClientRepresentation; -import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.testsuite.TestRealmKeycloakTest; import org.keycloak.testsuite.events.EventsListenerProviderFactory; import org.keycloak.testsuite.util.AssertAdminEvents; import org.keycloak.util.JsonSerialization; -import static org.junit.Assert.assertArrayEquals; - /** * This class adapts the functionality from the old testsuite to make tests * easier to port. @@ -109,4 +102,4 @@ public abstract class AbstractAdminTest extends TestRealmKeycloakTest { } } -} +} \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ConsentsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ConsentsTest.java index fb0a8635db..8407610d2d 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ConsentsTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ConsentsTest.java @@ -205,6 +205,7 @@ public class ConsentsTest extends AbstractKeycloakTest { IdentityProviderRepresentation identityProviderRepresentation = new IdentityProviderRepresentation(); identityProviderRepresentation.setAlias(alias); + identityProviderRepresentation.setDisplayName(providerId); identityProviderRepresentation.setProviderId(providerId); identityProviderRepresentation.setEnabled(true); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java index b9102e118a..834fc365cb 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java @@ -177,6 +177,7 @@ public class IdentityProviderTest extends AbstractAdminTest { IdentityProviderRepresentation idp = new IdentityProviderRepresentation(); idp.setAlias(id); + idp.setDisplayName(id); idp.setProviderId(providerId); idp.setEnabled(true); if (config != null) { diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/PermissionsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/PermissionsTest.java index b6fca90ed3..a0ed2c1fd5 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/PermissionsTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/PermissionsTest.java @@ -1440,7 +1440,8 @@ public class PermissionsTest extends AbstractKeycloakTest { }, Resource.IDENTITY_PROVIDER, false); invoke(new InvocationWithResponse() { public void invoke(RealmResource realm, AtomicReference response) { - response.set(realm.identityProviders().create(IdentityProviderBuilder.create().providerId("nosuch").alias("foo").build())); + response.set(realm.identityProviders().create(IdentityProviderBuilder.create().providerId("nosuch") + .displayName("nosuch-foo").alias("foo").build())); } }, Resource.IDENTITY_PROVIDER, true); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBrokerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBrokerTest.java index 29f796f6f5..cff20055ea 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBrokerTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBrokerTest.java @@ -126,6 +126,7 @@ public abstract class AbstractBrokerTest extends AbstractKeycloakTest { IdentityProviderRepresentation identityProviderRepresentation = new IdentityProviderRepresentation(); identityProviderRepresentation.setAlias(alias); + identityProviderRepresentation.setDisplayName(providerId); identityProviderRepresentation.setProviderId(providerId); identityProviderRepresentation.setEnabled(true); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/LoginPageTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/LoginPageTest.java index 2cd04fa5f3..6f6e98946d 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/LoginPageTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/LoginPageTest.java @@ -23,10 +23,12 @@ import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine; import org.junit.Assert; import org.junit.Test; import org.keycloak.adapters.HttpClientBuilder; +import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.testsuite.pages.LoginPage; import javax.ws.rs.core.Response; import org.jboss.arquillian.graphene.page.Page; +import org.keycloak.testsuite.util.IdentityProviderBuilder; /** * @author Michael Gerber @@ -37,6 +39,24 @@ public class LoginPageTest extends AbstractI18NTest { @Page protected LoginPage loginPage; + @Override + public void configureTestRealm(RealmRepresentation testRealm) { + testRealm.addIdentityProvider(IdentityProviderBuilder.create() + .providerId("github") + .alias("github") + .build()); + testRealm.addIdentityProvider(IdentityProviderBuilder.create() + .providerId("saml") + .alias("saml") + .build()); + testRealm.addIdentityProvider(IdentityProviderBuilder.create() + .providerId("oidc") + .alias("oidc") + .displayName("MyOIDC") + .build()); + + } + @Test public void languageDropdown() { loginPage.open(); @@ -87,4 +107,13 @@ public class LoginPageTest extends AbstractI18NTest { response = client.target(driver.getCurrentUrl()).request().acceptLanguage("en").get(); Assert.assertTrue(response.readEntity(String.class).contains("Log in to test")); } + + @Test + public void testIdentityProviderCapitalization(){ + loginPage.open(); + Assert.assertEquals("GitHub", loginPage.findSocialButton("github").getText()); + Assert.assertEquals("saml", loginPage.findSocialButton("saml").getText()); + Assert.assertEquals("MyOIDC", loginPage.findSocialButton("oidc").getText()); + + } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/IdentityProviderBuilder.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/IdentityProviderBuilder.java index bc3dae6d04..7cb1446df6 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/IdentityProviderBuilder.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/IdentityProviderBuilder.java @@ -44,6 +44,11 @@ public class IdentityProviderBuilder { return this; } + public IdentityProviderBuilder displayName(String displayName) { + rep.setDisplayName(displayName); + return this; + } + public IdentityProviderRepresentation build() { return rep; } diff --git a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json index dba9c1505d..ab707149f2 100755 --- a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json +++ b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json @@ -94,6 +94,7 @@ { "alias" : "model-saml-signed-idp", "providerId" : "saml", + "displayName": "My SAML", "enabled": true, "config": { "singleSignOnServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-identity-provider/protocol/saml", @@ -157,6 +158,7 @@ { "alias" : "model-oidc-idp", "providerId" : "oidc", + "displayName": "My OIDC", "enabled": false, "authenticateByDefault" : "false", "config": { @@ -172,6 +174,7 @@ { "alias" : "kc-oidc-idp", "providerId" : "keycloak-oidc", + "displayName": "My Keycloak OIDC", "enabled": true, "storeToken" : true, "addReadTokenRoleOnCreate": true, diff --git a/themes/src/main/resources/theme/base/account/federatedIdentity.ftl b/themes/src/main/resources/theme/base/account/federatedIdentity.ftl index 3a18805d78..9a901733ce 100755 --- a/themes/src/main/resources/theme/base/account/federatedIdentity.ftl +++ b/themes/src/main/resources/theme/base/account/federatedIdentity.ftl @@ -11,7 +11,7 @@ <#list federatedIdentity.identities as identity>
- +
diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties index d3cdd9ee82..4857924a96 100644 --- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties +++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties @@ -418,7 +418,9 @@ post-broker-login-flow=Post Login Flow redirect-uri=Redirect URI redirect-uri.tooltip=The redirect uri to use when configuring the identity provider. alias=Alias +display-name=Display Name identity-provider.alias.tooltip=The alias uniquely identifies an identity provider and it is also used to build the redirect uri. +identity-provider.display-name.tooltip=Friendly name for Identity Providers. identity-provider.enabled.tooltip=Enable/disable this identity provider. authenticate-by-default=Authenticate by Default identity-provider.authenticate-by-default.tooltip=Indicates if this provider should be tried by default for authentication even before displaying login screen. diff --git a/themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js b/themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js old mode 100755 new mode 100644 index 5db9cf0495..111af84e75 --- a/themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js +++ b/themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js @@ -689,6 +689,14 @@ module.controller('RealmDefaultRolesCtrl', function ($scope, Realm, realm, clien module.controller('IdentityProviderTabCtrl', function(Dialog, $scope, Current, Notifications, $location) { + for (var i in $scope.allProviders) { + var provider = $scope.allProviders[i]; + if (provider.groupName == 'Social' && (provider.id == $scope.identityProvider.alias)) { + $scope.identityProvider.displayName = provider.name; + } else if (!$scope.identityProvider.displayName) { + $scope.identityProvider.displayName = provider.id; + } + } $scope.removeIdentityProvider = function() { Dialog.confirmDelete($scope.identityProvider.alias, 'provider', function() { $scope.identityProvider.$remove({ @@ -773,6 +781,8 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload $scope.identityProvider.config = {}; $scope.identityProvider.alias = providerFactory.id; $scope.identityProvider.providerId = providerFactory.id; + $scope.identityProvider.displayName = providerFactory.displayName; + $scope.identityProvider.enabled = true; $scope.identityProvider.authenticateByDefault = false; $scope.identityProvider.firstBrokerLoginFlowAlias = 'first broker login'; @@ -836,7 +846,6 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload } } - $scope.uploadFile = function() { if (!$scope.identityProvider.alias) { Notifications.error("You must specify an alias"); @@ -909,10 +918,15 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload if (provider.groupName == 'Social' && (provider.id == configProvidedId)) { $scope.allProviders.splice(i, 1); + configuredProviders[j].displayName = provider.name; + break; + } else if (!configuredProviders[j].displayName) { + configuredProviders[j].displayName = configProvidedId; break; } } } + $scope.configuredProviders = angular.copy(configuredProviders); } }, true); diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/identity-provider-mapper-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/identity-provider-mapper-detail.html index cd2964d632..a7c54f804e 100755 --- a/themes/src/main/resources/theme/base/admin/resources/partials/identity-provider-mapper-detail.html +++ b/themes/src/main/resources/theme/base/admin/resources/partials/identity-provider-mapper-detail.html @@ -1,7 +1,7 @@