Merge pull request #3268 from stianst/REVIEW

KEYCLOAK-2438
This commit is contained in:
Stian Thorgersen 2016-09-28 13:27:26 +02:00 committed by GitHub
commit a58c985934
36 changed files with 247 additions and 61 deletions

View file

@ -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;
}
}

View file

@ -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<RealmEntity> {
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<String, String> config = entity.getConfig();
Map<String, String> copy = new HashMap<>();
@ -1294,6 +1310,7 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
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<RealmEntity> {
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());

View file

@ -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;

View file

@ -33,8 +33,9 @@
<dropColumn tableName="USER_ENTITY" columnName="TOTP" />
<addColumn tableName="IDENTITY_PROVIDER">
<column name="PROVIDER_DISPLAY_NAME" type="VARCHAR(255)"></column>
</addColumn>
</changeSet>

View file

@ -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<MongoRealmEntity> impleme
identityProviderModel.setProviderId(entity.getProviderId());
identityProviderModel.setAlias(entity.getAlias());
identityProviderModel.setDisplayName(entity.getDisplayName());
identityProviderModel.setInternalId(entity.getInternalId());
Map<String, String> config = entity.getConfig();
Map<String, String> copy = new HashMap<>();
@ -950,6 +950,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> 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<MongoRealmEntity> 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());

View file

@ -57,6 +57,8 @@ public class IdentityProviderModel implements Serializable {
private String postBrokerLoginFlowId;
private String displayName;
/**
* <p>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.</p>
@ -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<String, String>(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;
}
}

View file

@ -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;

View file

@ -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,21 @@ public final class KeycloakModelUtils {
}
}
public static String getIdentityProviderDisplayName(KeycloakSession session, IdentityProviderModel provider) {
String displayName = provider.getDisplayName();
if (displayName != null && !displayName.isEmpty()) {
return displayName;
}
SocialIdentityProviderFactory providerFactory = (SocialIdentityProviderFactory) session.getKeycloakSessionFactory()
.getProviderFactory(SocialIdentityProvider.class, provider.getProviderId());
if (providerFactory != null) {
return providerFactory.getName();
} else {
return provider.getAlias();
}
}
}

View file

@ -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());

View file

@ -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());

View file

@ -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,8 @@ public class AccountFederatedIdentityBean {
.queryParam("stateChecker", stateChecker)
.build().toString();
FederatedIdentityEntry entry = new FederatedIdentityEntry(identity, provider.getAlias(), provider.getAlias(), actionUrl,
String displayName = KeycloakModelUtils.getIdentityProviderDisplayName(session, provider);
FederatedIdentityEntry entry = new FederatedIdentityEntry(identity, displayName, provider.getAlias(), provider.getAlias(), actionUrl,
provider.getConfig() != null ? provider.getConfig().get("guiOrder") : null);
orderedSet.add(entry);
}
@ -106,10 +108,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 +147,11 @@ public class AccountFederatedIdentityBean {
public String getGuiOrder() {
return guiOrder;
}
public String getDisplayName() {
return displayName;
}
}
public static class IdentityProviderComparator implements Comparator<FederatedIdentityEntry> {

View file

@ -250,7 +250,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
List<IdentityProviderModel> 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<IdentityProviderModel> 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);

View file

@ -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<IdentityProvider> providers;
private RealmModel realm;
private final KeycloakSession session;
public IdentityProviderBean(RealmModel realm, List<IdentityProviderModel> identityProviders, URI baseURI, UriInfo uriInfo) {
public IdentityProviderBean(RealmModel realm, KeycloakSession session, List<IdentityProviderModel> identityProviders, URI baseURI, UriInfo uriInfo) {
this.realm = realm;
this.session = session;
if (!identityProviders.isEmpty()) {
Set<IdentityProvider> orderedSet = new TreeSet<>(IdentityProviderComparator.INSTANCE);
@ -59,7 +62,10 @@ public class IdentityProviderBean {
private void addIdentityProvider(Set<IdentityProvider> 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);
orderedSet.add(new IdentityProvider(identityProvider.getAlias(),
displayName, identityProvider.getProviderId(), loginUrl,
identityProvider.getConfig() != null ? identityProvider.getConfig().get("guiOrder") : null));
}
@ -77,9 +83,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 +108,10 @@ public class IdentityProviderBean {
public String getGuiOrder() {
return guiOrder;
}
public String getDisplayName() {
return displayName;
}
}
public static class IdentityProviderComparator implements Comparator<IdentityProvider> {
@ -112,7 +124,7 @@ public class IdentityProviderBean {
@Override
public int compare(IdentityProvider o1, IdentityProvider o2) {
int o1order = parseOrder(o1);
int o2order = parseOrder(o2);
@ -120,7 +132,7 @@ public class IdentityProviderBean {
return 1;
else if (o1order < o2order)
return -1;
return 1;
}
@ -134,6 +146,5 @@ public class IdentityProviderBean {
}
return 10000;
}
}
}

View file

@ -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));

View file

@ -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("mysaml")
.build());
testRealm.addIdentityProvider(IdentityProviderBuilder.create()
.providerId("oidc")
.alias("myoidc")
.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("mysaml", loginPage.findSocialButton("mysaml").getText());
Assert.assertEquals("MyOIDC", loginPage.findSocialButton("myoidc").getText());
}
}

View file

@ -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 {
}
}
}
}

View file

@ -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);

View file

@ -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) {

View file

@ -1440,7 +1440,8 @@ public class PermissionsTest extends AbstractKeycloakTest {
}, Resource.IDENTITY_PROVIDER, false);
invoke(new InvocationWithResponse() {
public void invoke(RealmResource realm, AtomicReference<Response> 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);

View file

@ -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);

View file

@ -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 <a href="mailto:gerbermichi@me.com">Michael Gerber</a>
@ -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("mysaml")
.build());
testRealm.addIdentityProvider(IdentityProviderBuilder.create()
.providerId("oidc")
.alias("myoidc")
.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("mysaml", loginPage.findSocialButton("mysaml").getText());
Assert.assertEquals("MyOIDC", loginPage.findSocialButton("myoidc").getText());
}
}

View file

@ -44,6 +44,11 @@ public class IdentityProviderBuilder {
return this;
}
public IdentityProviderBuilder displayName(String displayName) {
rep.setDisplayName(displayName);
return this;
}
public IdentityProviderRepresentation build() {
return rep;
}

View file

@ -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,

View file

@ -11,7 +11,7 @@
<#list federatedIdentity.identities as identity>
<div class="form-group">
<div class="col-sm-2 col-md-2">
<label for="${identity.providerId!}" class="control-label">${identity.providerName!}</label>
<label for="${identity.providerId!}" class="control-label">${identity.displayName!}</label>
</div>
<div class="col-sm-5 col-md-5">
<input disabled="true" class="form-control" value="${identity.userName!}">

View file

@ -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.

View file

@ -768,11 +768,19 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
if (instance && instance.alias) {
$scope.identityProvider = angular.copy(instance);
$scope.newIdentityProvider = false;
for (var i in serverInfo.identityProviders) {
var provider = serverInfo.identityProviders[i];
if (provider.id == instance.providerId) {
$scope.provider = provider;
}
}
} else {
$scope.identityProvider = {};
$scope.identityProvider.config = {};
$scope.identityProvider.alias = providerFactory.id;
$scope.identityProvider.providerId = providerFactory.id;
$scope.identityProvider.enabled = true;
$scope.identityProvider.authenticateByDefault = false;
$scope.identityProvider.firstBrokerLoginFlowAlias = 'first broker login';
@ -836,7 +844,6 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
}
}
$scope.uploadFile = function() {
if (!$scope.identityProvider.alias) {
Notifications.error("You must specify an alias");
@ -906,13 +913,12 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
for (var i in $scope.allProviders) {
var provider = $scope.allProviders[i];
if (provider.groupName == 'Social' && (provider.id == configProvidedId)) {
$scope.allProviders.splice(i, 1);
break;
if (provider.id == configProvidedId) {
configuredProviders[j].provider = provider;
}
}
}
$scope.configuredProviders = angular.copy(configuredProviders);
}
}, true);

View file

@ -1,7 +1,7 @@
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.realm}}/identity-provider-settings">{{:: 'identity-providers' | translate}}</a></li>
<li><a href="#/realms/{{realm.realm}}/identity-provider-settings/provider/{{identityProvider.providerId}}/{{identityProvider.alias}}">{{identityProvider.alias}}</a></li>
<li><a href="#/realms/{{realm.realm}}/identity-provider-settings/provider/{{identityProvider.providerId}}/{{identityProvider.alias}}">{{identityProvider.displayName}}</a></li>
<li><a href="#/realms/{{realm.realm}}/identity-provider-mappers/{{identityProvider.alias}}/mappers">{{:: 'identity-provider-mappers' | translate}}</a></li>
<li class="active" data-ng-show="create">{{:: 'create-identity-provider-mapper' | translate}}</li>
<li class="active" data-ng-hide="create">{{mapper.name|capitalize}}</li>

View file

@ -1,7 +1,7 @@
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.realm}}/identity-provider-settings">{{:: 'identity-providers' | translate}}</a></li>
<li>{{identityProvider.alias}}</li>
<li>{{identityProvider.displayName}}</li>
</ol>
<kc-tabs-identity-provider></kc-tabs-identity-provider>

View file

@ -1,7 +1,7 @@
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2" data-ng-init="initProvider()">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.realm}}/identity-provider-settings">{{:: 'identity-providers' | translate}}</a></li>
<li>{{identityProvider.alias}}</li>
<li>{{identityProvider.displayName}}</li>
</ol>
<kc-tabs-identity-provider></kc-tabs-identity-provider>

View file

@ -1,7 +1,9 @@
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.realm}}/identity-provider-settings">{{:: 'identity-providers' | translate}}</a></li>
<li>{{identityProvider.alias}}</li>
<li data-ng-show="!newIdentityProvider && identityProvider.displayName">{{identityProvider.displayName}}</li>
<li data-ng-show="!newIdentityProvider && !identityProvider.displayName">{{identityProvider.alias}}</li>
<li data-ng-show="newIdentityProvider">{{:: 'add-identity-provider' | translate}}</li>
</ol>
<kc-tabs-identity-provider></kc-tabs-identity-provider>
@ -27,6 +29,13 @@
</div>
<kc-tooltip>{{:: 'identity-provider.alias.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="displayName"> {{:: 'display-name' | translate}}</label>
<div class="col-md-6">
<input class="form-control" id="displayName" type="text" ng-model="identityProvider.displayName">
</div>
<kc-tooltip>{{:: 'identity-provider.display-name.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="enabled">{{:: 'enabled' | translate}}</label>
<div class="col-md-6">

View file

@ -1,7 +1,9 @@
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2" data-ng-init="initSamlProvider()">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.realm}}/identity-provider-settings">{{:: 'identity-providers' | translate}}</a></li>
<li>{{identityProvider.alias}}</li>
<li data-ng-show="!newIdentityProvider && identityProvider.displayName">{{identityProvider.displayName}}</li>
<li data-ng-show="!newIdentityProvider && !identityProvider.displayName">{{identityProvider.alias}}</li>
<li data-ng-show="newIdentityProvider">{{:: 'add-identity-provider' | translate}}</li>
</ol>
<kc-tabs-identity-provider></kc-tabs-identity-provider>
@ -24,6 +26,13 @@
</div>
<kc-tooltip>{{:: 'identity-provider.alias.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="displayName"> {{:: 'display-name' | translate}}</label>
<div class="col-md-6">
<input class="form-control" id="displayName" type="text" ng-model="identityProvider.displayName">
</div>
<kc-tooltip>{{:: 'identity-provider.display-name.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="enabled">{{:: 'enabled' | translate}}</label>
<div class="col-md-6">

View file

@ -1,7 +1,8 @@
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.realm}}/identity-provider-settings">{{:: 'identity-providers' | translate}}</a></li>
<li>{{identityProvider.alias}}</li>
<li data-ng-hide="newIdentityProvider">{{provider.name}}</li>
<li data-ng-show="newIdentityProvider">{{:: 'add-identity-provider' | translate}}</li>
</ol>
<kc-tabs-identity-provider></kc-tabs-identity-provider>

View file

@ -54,7 +54,11 @@
<tbody>
<tr ng-repeat="identityProvider in configuredProviders">
<td>
<a href="#/realms/{{realm.realm}}/identity-provider-settings/provider/{{identityProvider.providerId}}/{{identityProvider.alias}}">{{identityProvider.alias}}</a>
<a href="#/realms/{{realm.realm}}/identity-provider-settings/provider/{{identityProvider.providerId}}/{{identityProvider.alias}}">
<span data-ng-show="identityProvider.displayName">{{identityProvider.displayName}}</span>
<span data-ng-show="!identityProvider.displayName && identityProvider.provider.groupName == 'Social'">{{identityProvider.provider.name}}</span>
<span data-ng-show="!identityProvider.displayName && identityProvider.provider.groupName != 'Social'">{{identityProvider.alias}}</span>
</a>
</td>
<td>{{identityProvider.providerId}}</td>
<td translate="{{identityProvider.enabled}}"></td>

View file

@ -1,6 +1,9 @@
<div data-ng-controller="IdentityProviderTabCtrl">
<h1 data-ng-hide="path[0] == 'create'">
{{identityProvider.alias|capitalize}}
<span data-ng-show="identityProvider.displayName">{{identityProvider.displayName}}</span>
<span data-ng-show="!identityProvider.displayName && provider.groupName == 'Social'">{{provider.name}}</span>
<span data-ng-show="!identityProvider.displayName && provider.groupName != 'Social'">{{identityProvider.alias}}</span>
<i class="pficon pficon-delete clickable" data-ng-hide="newIdentityProvider || changed" data-ng-click="removeIdentityProvider()"></i>
</h1>
<h1 data-ng-show="path[0] == 'create'">{{:: 'add-identity-provider' | translate}}</h1>

View file

@ -70,7 +70,7 @@
<div id="kc-social-providers">
<ul>
<#list social.providers as p>
<li><a href="${p.loginUrl}" id="zocial-${p.alias}" class="zocial ${p.providerId}"> <span class="text">${p.alias}</span></a></li>
<li><a href="${p.loginUrl}" id="zocial-${p.alias}" class="zocial ${p.providerId}"> <span class="text">${p.displayName}</span></a></li>
</#list>
</ul>
</div>

View file

@ -229,9 +229,6 @@ ol#kc-totp-settings li:first-of-type {
.zocial.google {
background-color: #dd4b39 !important;
}
.zocial.google .text:after {
content: "+";
}
.zocial.facebook:hover,
.zocial.github:hover,