Merge pull request #1125 from velias/KEYCLOAK-1195
KEYCLOAK-1195 - added identity brokes ordering for login page
This commit is contained in:
commit
4955f36115
8 changed files with 147 additions and 9 deletions
|
@ -284,6 +284,15 @@
|
||||||
during the authentication process.
|
during the authentication process.
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>
|
||||||
|
<literal>GUI order</literal>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
Allows you to define order of the provider when shown on login page.
|
||||||
|
You can put number into this field, providers with lower numbers are shown first.
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
<!--<row>-->
|
<!--<row>-->
|
||||||
<!--<entry>-->
|
<!--<entry>-->
|
||||||
<!--<literal>Store Tokens</literal>-->
|
<!--<literal>Store Tokens</literal>-->
|
||||||
|
|
|
@ -55,6 +55,13 @@
|
||||||
</div>
|
</div>
|
||||||
<span tooltip-placement="right" tooltip="Indicates if user must update his profile right after the first login." class="fa fa-info-circle"></span>
|
<span tooltip-placement="right" tooltip="Indicates if user must update his profile right after the first login." class="fa fa-info-circle"></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="guiOrder">GUI order</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" id="guiOrder" type="text" ng-model="identityProvider.config.guiOrder">
|
||||||
|
</div>
|
||||||
|
<span tooltip-placement="right" tooltip="Number defining order of the provider in GUI (eg. on Login page)." class="fa fa-info-circle"></span>
|
||||||
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend uncollapsed><span class="text">OpenID Connect Config</span> <span tooltip-placement="right" tooltip="OIDC SP and external IDP configuration." class="fa fa-info-circle"></span></legend>
|
<legend uncollapsed><span class="text">OpenID Connect Config</span> <span tooltip-placement="right" tooltip="OIDC SP and external IDP configuration." class="fa fa-info-circle"></span></legend>
|
||||||
|
|
|
@ -55,6 +55,13 @@
|
||||||
</div>
|
</div>
|
||||||
<span tooltip-placement="right" tooltip="Indicates if user must update his profile right after the first login." class="fa fa-info-circle"></span>
|
<span tooltip-placement="right" tooltip="Indicates if user must update his profile right after the first login." class="fa fa-info-circle"></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="guiOrder">GUI order</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" id="guiOrder" type="text" ng-model="identityProvider.config.guiOrder">
|
||||||
|
</div>
|
||||||
|
<span tooltip-placement="right" tooltip="Number defining order of the provider in GUI (eg. on Login page)." class="fa fa-info-circle"></span>
|
||||||
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend uncollapsed><span class="text">SAML Config</span> <span tooltip-placement="right" tooltip="SAML SP and external IDP configuration." class="fa fa-info-circle"></span></legend>
|
<legend uncollapsed><span class="text">SAML Config</span> <span tooltip-placement="right" tooltip="SAML SP and external IDP configuration." class="fa fa-info-circle"></span></legend>
|
||||||
|
|
|
@ -73,6 +73,13 @@
|
||||||
</div>
|
</div>
|
||||||
<span tooltip-placement="right" tooltip="Indicates if this provider should be tried by default for authentication even before displaying login screen" class="fa fa-info-circle"></span>
|
<span tooltip-placement="right" tooltip="Indicates if this provider should be tried by default for authentication even before displaying login screen" class="fa fa-info-circle"></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="guiOrder">GUI order</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" id="guiOrder" type="text" ng-model="identityProvider.config.guiOrder">
|
||||||
|
</div>
|
||||||
|
<span tooltip-placement="right" tooltip="Number defining order of the provider in GUI (eg. on Login page)." class="fa fa-info-circle"></span>
|
||||||
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<div class="pull-right form-actions">
|
<div class="pull-right form-actions">
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
<caption class="hidden">Table of identity providers</caption>
|
<caption class="hidden">Table of identity providers</caption>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="5" class="kc-table-actions">
|
<th colspan="3" class="kc-table-actions">
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<div class="select-kc">
|
<div class="select-kc">
|
||||||
<select ng-model="provider"
|
<select ng-model="provider"
|
||||||
|
@ -27,6 +27,7 @@
|
||||||
<tr ng-show="configuredProviders.length > 0">
|
<tr ng-show="configuredProviders.length > 0">
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>Provider</th>
|
<th>Provider</th>
|
||||||
|
<th width="15%">GUI order</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody ng-show="configuredProviders.length > 0">
|
<tbody ng-show="configuredProviders.length > 0">
|
||||||
|
@ -35,6 +36,7 @@
|
||||||
<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}}">{{identityProvider.alias}}</a>
|
||||||
</td>
|
</td>
|
||||||
<td>{{identityProvider.providerId}}</td>
|
<td>{{identityProvider.providerId}}</td>
|
||||||
|
<td>{{identityProvider.config.guiOrder}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -71,6 +71,12 @@
|
||||||
<artifactId>jboss-logging</artifactId>
|
<artifactId>jboss-logging</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -27,11 +27,15 @@ import org.keycloak.services.resources.flows.Urls;
|
||||||
|
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
* @author Vlastimil Elias (velias at redhat dot com)
|
||||||
*/
|
*/
|
||||||
public class IdentityProviderBean {
|
public class IdentityProviderBean {
|
||||||
|
|
||||||
|
@ -45,23 +49,24 @@ public class IdentityProviderBean {
|
||||||
List<IdentityProviderModel> identityProviders = realm.getIdentityProviders();
|
List<IdentityProviderModel> identityProviders = realm.getIdentityProviders();
|
||||||
|
|
||||||
if (!identityProviders.isEmpty()) {
|
if (!identityProviders.isEmpty()) {
|
||||||
providers = new LinkedList<IdentityProvider>();
|
Set<IdentityProvider> orderedSet = new TreeSet<>(IdentityProviderComparator.INSTANCE);
|
||||||
|
|
||||||
for (IdentityProviderModel identityProvider : identityProviders) {
|
for (IdentityProviderModel identityProvider : identityProviders) {
|
||||||
if (identityProvider.isEnabled()) {
|
if (identityProvider.isEnabled()) {
|
||||||
addIdentityProvider(realm, baseURI, identityProvider);
|
addIdentityProvider(orderedSet, realm, baseURI, identityProvider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!providers.isEmpty()) {
|
if (!orderedSet.isEmpty()) {
|
||||||
|
providers = new LinkedList<IdentityProvider>(orderedSet);
|
||||||
displaySocial = true;
|
displaySocial = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addIdentityProvider(RealmModel realm, URI baseURI, IdentityProviderModel identityProvider) {
|
private void addIdentityProvider(Set<IdentityProvider> orderedSet, RealmModel realm, URI baseURI, IdentityProviderModel identityProvider) {
|
||||||
String loginUrl = Urls.identityProviderAuthnRequest(baseURI, identityProvider.getAlias(), realm.getName()).toString();
|
String loginUrl = Urls.identityProviderAuthnRequest(baseURI, identityProvider.getAlias(), realm.getName()).toString();
|
||||||
providers.add(new IdentityProvider(identityProvider.getAlias(), identityProvider.getProviderId(), loginUrl));
|
orderedSet.add(new IdentityProvider(identityProvider.getAlias(), identityProvider.getProviderId(), loginUrl,
|
||||||
|
identityProvider.getConfig() != null ? identityProvider.getConfig().get("guiOrder") : null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<IdentityProvider> getProviders() {
|
public List<IdentityProvider> getProviders() {
|
||||||
|
@ -77,12 +82,13 @@ public class IdentityProviderBean {
|
||||||
private final String alias;
|
private final String alias;
|
||||||
private final String providerId; // This refer to providerType (facebook, google, etc.)
|
private final String providerId; // This refer to providerType (facebook, google, etc.)
|
||||||
private final String loginUrl;
|
private final String loginUrl;
|
||||||
|
private final String guiOrder;
|
||||||
|
|
||||||
public IdentityProvider(String alias, String providerId,String loginUrl) {
|
public IdentityProvider(String alias, String providerId, String loginUrl, String guiOrder) {
|
||||||
this.alias = alias;
|
this.alias = alias;
|
||||||
this.providerId = providerId;
|
this.providerId = providerId;
|
||||||
|
|
||||||
this.loginUrl = loginUrl;
|
this.loginUrl = loginUrl;
|
||||||
|
this.guiOrder = guiOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAlias() {
|
public String getAlias() {
|
||||||
|
@ -96,5 +102,44 @@ public class IdentityProviderBean {
|
||||||
public String getProviderId() {
|
public String getProviderId() {
|
||||||
return providerId;
|
return providerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getGuiOrder() {
|
||||||
|
return guiOrder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class IdentityProviderComparator implements Comparator<IdentityProvider> {
|
||||||
|
|
||||||
|
public static IdentityProviderComparator INSTANCE = new IdentityProviderComparator();
|
||||||
|
|
||||||
|
private IdentityProviderComparator() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(IdentityProvider o1, IdentityProvider o2) {
|
||||||
|
|
||||||
|
int o1order = parseOrder(o1);
|
||||||
|
int o2order = parseOrder(o2);
|
||||||
|
|
||||||
|
if (o1order > o2order)
|
||||||
|
return 1;
|
||||||
|
else if (o1order < o2order)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int parseOrder(IdentityProvider ip) {
|
||||||
|
if (ip != null && ip.getGuiOrder() != null) {
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(ip.getGuiOrder());
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// ignore it and use defaulr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 10000;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
* Copyright 2015 Red Hat Inc. and/or its affiliates and other contributors
|
||||||
|
* as indicated by the @authors tag. All rights reserved.
|
||||||
|
*/
|
||||||
|
package org.keycloak.login.freemarker.model;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.login.freemarker.model.IdentityProviderBean.IdentityProvider;
|
||||||
|
import org.keycloak.login.freemarker.model.IdentityProviderBean.IdentityProviderComparator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit test for {@link IdentityProviderBean}
|
||||||
|
*
|
||||||
|
* @author Vlastimil Elias (velias at redhat dot com)
|
||||||
|
*/
|
||||||
|
public class IdentityProviderBeanTest {
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIdentityProviderComparator() {
|
||||||
|
|
||||||
|
IdentityProvider o1 = new IdentityProvider("alias1", "id1", "ur1", null);
|
||||||
|
IdentityProvider o2 = new IdentityProvider("alias2", "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");
|
||||||
|
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");
|
||||||
|
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");
|
||||||
|
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");
|
||||||
|
Assert.assertEquals(-1, IdentityProviderComparator.INSTANCE.compare(o1, o2));
|
||||||
|
Assert.assertEquals(1, IdentityProviderComparator.INSTANCE.compare(o2, o1));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue