keycloak-aplcache

Merge pull request #1125 from velias/KEYCLOAK-1195 KEYCLOAK-1195

4/9/2015 10:44:43 AM

Details

diff --git a/docbook/reference/en/en-US/modules/identity-broker.xml b/docbook/reference/en/en-US/modules/identity-broker.xml
index 397fd02..4c1a3c2 100755
--- a/docbook/reference/en/en-US/modules/identity-broker.xml
+++ b/docbook/reference/en/en-US/modules/identity-broker.xml
@@ -284,6 +284,15 @@
                             during the authentication process.
                         </entry>
                     </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>-->
                         <!--<entry>-->
                             <!--<literal>Store Tokens</literal>-->
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html
index 1c0ed54..778bb2c 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html
@@ -12,7 +12,7 @@
                         <caption class="hidden">Table of identity providers</caption>
                         <thead>
                         <tr>
-                            <th colspan="5" class="kc-table-actions">
+                            <th colspan="3" class="kc-table-actions">
                                 <div class="pull-right">
                                     <div class="select-kc">
                                         <select ng-model="provider"
@@ -27,6 +27,7 @@
                         <tr ng-show="configuredProviders.length > 0">
                             <th>Name</th>
                             <th>Provider</th>
+                            <th width="15%">GUI order</th>
                         </tr>
                         </thead>
                         <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>
                             </td>
                             <td>{{identityProvider.providerId}}</td>
+                            <td>{{identityProvider.config.guiOrder}}</td>
                         </tr>
                         </tbody>
                     </table>
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html
index 7bf4035..d093744 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html
@@ -55,6 +55,13 @@
                         </div>
                         <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 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>
                     <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>
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
index 10327e6..3e151fd 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
@@ -55,6 +55,13 @@
                         </div>
                         <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 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>
                     <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>
diff --git a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html
index 0a8b56a..809984b 100755
--- a/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html
+++ b/forms/common-themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html
@@ -73,6 +73,13 @@
                         </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>
                     </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>
 
                 <div class="pull-right form-actions">
diff --git a/forms/login-freemarker/pom.xml b/forms/login-freemarker/pom.xml
index e83bc52..c5b7134 100755
--- a/forms/login-freemarker/pom.xml
+++ b/forms/login-freemarker/pom.xml
@@ -71,6 +71,12 @@
             <artifactId>jboss-logging</artifactId>
             <scope>provided</scope>
         </dependency>
+        
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
 	</dependencies>
 
 	<build>
diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java
index cd11bfd..65e0272 100755
--- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java
+++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java
@@ -27,11 +27,15 @@ import org.keycloak.services.resources.flows.Urls;
 
 import javax.ws.rs.core.UriInfo;
 import java.net.URI;
+import java.util.Comparator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ * @author Vlastimil Elias (velias at redhat dot com)
  */
 public class IdentityProviderBean {
 
@@ -45,23 +49,24 @@ public class IdentityProviderBean {
         List<IdentityProviderModel> identityProviders = realm.getIdentityProviders();
 
         if (!identityProviders.isEmpty()) {
-            providers = new LinkedList<IdentityProvider>();
-
+            Set<IdentityProvider> orderedSet = new TreeSet<>(IdentityProviderComparator.INSTANCE);
             for (IdentityProviderModel identityProvider : identityProviders) {
                 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;
             }
         }
     }
 
-    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();
-        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() {
@@ -77,12 +82,13 @@ public class IdentityProviderBean {
         private final String alias;
         private final String providerId; // This refer to providerType (facebook, google, etc.)
         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.providerId = providerId;
-
             this.loginUrl = loginUrl;
+            this.guiOrder = guiOrder;
         }
 
         public String getAlias() {
@@ -96,5 +102,44 @@ public class IdentityProviderBean {
         public String getProviderId() {
             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;
+        }
+
     }
 }
diff --git a/forms/login-freemarker/src/test/java/org/keycloak/login/freemarker/model/IdentityProviderBeanTest.java b/forms/login-freemarker/src/test/java/org/keycloak/login/freemarker/model/IdentityProviderBeanTest.java
new file mode 100644
index 0000000..dda3316
--- /dev/null
+++ b/forms/login-freemarker/src/test/java/org/keycloak/login/freemarker/model/IdentityProviderBeanTest.java
@@ -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));
+
+    }
+
+}