keycloak-memoizeit

Merge pull request #3220 from abstractj/KEYCLOAK-3535 KEYCLOAK-3535

9/9/2016 3:15:11 AM

Details

diff --git a/federation/sssd/src/main/java/cx/ath/matthew/LibraryLoader.java b/federation/sssd/src/main/java/cx/ath/matthew/LibraryLoader.java
index ffdf02d..095d214 100644
--- a/federation/sssd/src/main/java/cx/ath/matthew/LibraryLoader.java
+++ b/federation/sssd/src/main/java/cx/ath/matthew/LibraryLoader.java
@@ -31,7 +31,7 @@ public class LibraryLoader {
     private static final String VERSION = "0.0.8";
     private static boolean loadSucceeded;
 
-    public static void load() {
+    public static LibraryLoader load() {
         for (String path : PATHS) {
             try {
                 System.load(String.format("%s/%s.so.%s", path, LIBRARY_NAME, VERSION));
@@ -45,5 +45,11 @@ public class LibraryLoader {
 
         if (!loadSucceeded) LOGGER.log(Level.WARNING, "libunix_dbus_java not found\n" +
                 "Please, make sure you have the package libunix-dbus-java installed.");
+
+        return new LibraryLoader();
+    }
+
+    public boolean succeed() {
+        return loadSucceeded;
     }
 }
diff --git a/federation/sssd/src/main/java/org/freedesktop/DBus.java b/federation/sssd/src/main/java/org/freedesktop/DBus.java
index 1aa180a..b7a1687 100644
--- a/federation/sssd/src/main/java/org/freedesktop/DBus.java
+++ b/federation/sssd/src/main/java/org/freedesktop/DBus.java
@@ -30,18 +30,22 @@ import java.util.List;
 import java.util.Map;
 
 public interface DBus extends DBusInterface {
-    public static final int DBUS_NAME_FLAG_ALLOW_REPLACEMENT = 0x01;
-    public static final int DBUS_NAME_FLAG_REPLACE_EXISTING = 0x02;
-    public static final int DBUS_NAME_FLAG_DO_NOT_QUEUE = 0x04;
-    public static final int DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER = 1;
-    public static final int DBUS_REQUEST_NAME_REPLY_IN_QUEUE = 2;
-    public static final int DBUS_REQUEST_NAME_REPLY_EXISTS = 3;
-    public static final int DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER = 4;
-    public static final int DBUS_RELEASE_NAME_REPLY_RELEASED = 1;
-    public static final int DBUS_RELEASE_NAME_REPLY_NON_EXISTANT = 2;
-    public static final int DBUS_RELEASE_NAME_REPLY_NOT_OWNER = 3;
-    public static final int DBUS_START_REPLY_SUCCESS = 1;
-    public static final int DBUS_START_REPLY_ALREADY_RUNNING = 2;
+
+    String BUSNAME = "org.freedesktop.DBus";
+    String OBJECTPATH = "/org/freedesktop/DBus";
+
+    int DBUS_NAME_FLAG_ALLOW_REPLACEMENT = 0x01;
+    int DBUS_NAME_FLAG_REPLACE_EXISTING = 0x02;
+    int DBUS_NAME_FLAG_DO_NOT_QUEUE = 0x04;
+    int DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER = 1;
+    int DBUS_REQUEST_NAME_REPLY_IN_QUEUE = 2;
+    int DBUS_REQUEST_NAME_REPLY_EXISTS = 3;
+    int DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER = 4;
+    int DBUS_RELEASEME_REPLY_RELEASED = 1;
+    int DBUS_RELEASE_NAME_REPLY_NON_EXISTANT = 2;
+    int DBUS_RELEASE_NAME_REPLY_NOT_OWNER = 3;
+    int DBUS_START_REPLY_SUCCESS = 1;
+    int DBUS_START_REPLY_ALREADY_RUNNING = 2;
 
     /**
      * All DBus Applications should respond to the Ping method on this interface
@@ -527,4 +531,4 @@ public interface DBus extends DBusInterface {
             }
         }
     }
-}
+}
\ No newline at end of file
diff --git a/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/InfoPipe.java b/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/InfoPipe.java
index 8791170..6152d26 100644
--- a/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/InfoPipe.java
+++ b/federation/sssd/src/main/java/org/freedesktop/sssd/infopipe/InfoPipe.java
@@ -32,6 +32,8 @@ import java.util.Map;
 public interface InfoPipe extends DBusInterface {
 
     String OBJECTPATH = "/org/freedesktop/sssd/infopipe";
+    String BUSNAME = "org.freedesktop.sssd.infopipe";
+
 
     @DBusMemberName("GetUserAttr")
     Map<String, Variant> getUserAttributes(String user, List<String> attr);
@@ -39,4 +41,4 @@ public interface InfoPipe extends DBusInterface {
     @DBusMemberName("GetUserGroups")
     List<String> getUserGroups(String user);
 
-}
+}
\ No newline at end of file
diff --git a/federation/sssd/src/main/java/org/keycloak/federation/sssd/api/Sssd.java b/federation/sssd/src/main/java/org/keycloak/federation/sssd/api/Sssd.java
index a5bb57a..fd9dc67 100644
--- a/federation/sssd/src/main/java/org/keycloak/federation/sssd/api/Sssd.java
+++ b/federation/sssd/src/main/java/org/keycloak/federation/sssd/api/Sssd.java
@@ -17,6 +17,8 @@
 
 package org.keycloak.federation.sssd.api;
 
+import cx.ath.matthew.LibraryLoader;
+import org.freedesktop.DBus;
 import org.freedesktop.dbus.DBusConnection;
 import org.freedesktop.dbus.Variant;
 import org.freedesktop.dbus.exceptions.DBusException;
@@ -35,8 +37,6 @@ import java.util.Vector;
  */
 public class Sssd {
 
-    public static final String BUSNAME = "org.freedesktop.sssd.infopipe";
-
     public static User user() {
         return SingletonHolder.USER_OBJECT;
     }
@@ -45,6 +45,7 @@ public class Sssd {
         return SingletonHolder.INFOPIPE_OBJECT;
     }
 
+
     public static void disconnect() {
         SingletonHolder.DBUS_CONNECTION.disconnect();
     }
@@ -67,10 +68,10 @@ public class Sssd {
         static {
             try {
                 DBUS_CONNECTION = DBusConnection.getConnection(DBusConnection.SYSTEM);
-                INFOPIPE_OBJECT = DBUS_CONNECTION.getRemoteObject(BUSNAME, InfoPipe.OBJECTPATH, InfoPipe.class);
-                USER_OBJECT = DBUS_CONNECTION.getRemoteObject(BUSNAME, User.OBJECTPATH, User.class);
+                INFOPIPE_OBJECT = DBUS_CONNECTION.getRemoteObject(InfoPipe.BUSNAME, InfoPipe.OBJECTPATH, InfoPipe.class);
+                USER_OBJECT = DBUS_CONNECTION.getRemoteObject(InfoPipe.BUSNAME, User.OBJECTPATH, User.class);
             } catch (DBusException e) {
-                e.printStackTrace();
+                logger.error("Failed to obtain D-Bus connection", e);
             }
         }
     }
@@ -108,4 +109,24 @@ public class Sssd {
         }
         return userGroups;
     }
+
+    public static boolean isAvailable(){
+        boolean sssdAvailable = false;
+        try {
+            if (LibraryLoader.load().succeed()) {
+                DBusConnection connection = DBusConnection.getConnection(DBusConnection.SYSTEM);
+                DBus dbus = connection.getRemoteObject(DBus.BUSNAME, DBus.OBJECTPATH, DBus.class);
+                sssdAvailable = Arrays.asList(dbus.ListNames()).contains(InfoPipe.BUSNAME);
+                if (!sssdAvailable) {
+                    logger.debugv("SSSD is not available in your system. Federation provider will be disabled.");
+                } else {
+                    sssdAvailable = true;
+                }
+                connection.disconnect();
+            }
+        } catch (DBusException e) {
+            logger.error("Failed to check the status of SSSD", e);
+        }
+        return sssdAvailable;
+    }
 }
diff --git a/federation/sssd/src/main/java/org/keycloak/federation/sssd/SSSDFederationProviderFactory.java b/federation/sssd/src/main/java/org/keycloak/federation/sssd/SSSDFederationProviderFactory.java
index 6a287a7..3140e9e 100755
--- a/federation/sssd/src/main/java/org/keycloak/federation/sssd/SSSDFederationProviderFactory.java
+++ b/federation/sssd/src/main/java/org/keycloak/federation/sssd/SSSDFederationProviderFactory.java
@@ -19,6 +19,7 @@ package org.keycloak.federation.sssd;
 
 import org.jboss.logging.Logger;
 import org.keycloak.Config;
+import org.keycloak.federation.sssd.api.Sssd;
 import org.keycloak.federation.sssd.impl.PAMAuthenticator;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
@@ -26,6 +27,7 @@ import org.keycloak.models.UserFederationProvider;
 import org.keycloak.models.UserFederationProviderFactory;
 import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserFederationSyncResult;
+import org.keycloak.provider.EnvironmentDependentProviderFactory;
 
 import java.util.Date;
 import java.util.HashSet;
@@ -35,7 +37,7 @@ import java.util.Set;
  * @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>
  * @version $Revision: 1 $
  */
-public class SSSDFederationProviderFactory implements UserFederationProviderFactory {
+public class SSSDFederationProviderFactory implements UserFederationProviderFactory, EnvironmentDependentProviderFactory {
 
     private static final String PROVIDER_NAME = "sssd";
     private static final Logger logger = Logger.getLogger(SSSDFederationProvider.class);
@@ -99,4 +101,8 @@ public class SSSDFederationProviderFactory implements UserFederationProviderFact
         return new PAMAuthenticator(username, factors);
     }
 
-}
+    @Override
+    public boolean isSupported() {
+        return Sssd.isAvailable();
+    }
+}
\ No newline at end of file
diff --git a/server-spi/src/main/java/org/keycloak/provider/EnvironmentDependentProviderFactory.java b/server-spi/src/main/java/org/keycloak/provider/EnvironmentDependentProviderFactory.java
new file mode 100644
index 0000000..b4e993a
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/provider/EnvironmentDependentProviderFactory.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.provider;
+
+/**
+ * Providers that are only supported in some environments can implement this interface to be able to determine if they
+ * should be available or not.
+ *
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public interface EnvironmentDependentProviderFactory {
+
+    /**
+     * @return <code>true</code> if the provider is supported and should be available, <code>false</code> otherwise
+     */
+    boolean isSupported();
+
+}
diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
index d5474dc..36f9b7f 100755
--- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
+++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
@@ -20,6 +20,7 @@ import org.keycloak.Config;
 import org.keycloak.common.util.MultivaluedHashMap;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.provider.EnvironmentDependentProviderFactory;
 import org.keycloak.provider.Provider;
 import org.keycloak.provider.ProviderEvent;
 import org.keycloak.provider.ProviderEventListener;
@@ -190,8 +191,7 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory, Pr
                 }
 
                 Config.Scope scope = Config.scope(spi.getName(), provider);
-                if (scope.getBoolean("enabled", true)) {
-
+                if (isEnabled(factory, scope)) {
                     factory.init(scope);
 
                     if (spi.isInternal() && !isInternal(factory)) {
@@ -202,10 +202,11 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory, Pr
 
                     logger.debugv("Loaded SPI {0} (provider = {1})", spi.getName(), provider);
                 }
+
             } else {
                 for (ProviderFactory factory : pm.load(spi)) {
                     Config.Scope scope = Config.scope(spi.getName(), factory.getId());
-                    if (scope.getBoolean("enabled", true)) {
+                    if (isEnabled(factory, scope)) {
                         factory.init(scope);
 
                         if (spi.isInternal() && !isInternal(factory)) {
@@ -220,7 +221,16 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory, Pr
             }
         }
         return factoryMap;
+    }
 
+    private boolean isEnabled(ProviderFactory factory, Config.Scope scope) {
+        if (!scope.getBoolean("enabled", true)) {
+            return false;
+        }
+        if (factory instanceof EnvironmentDependentProviderFactory) {
+            return ((EnvironmentDependentProviderFactory) factory).isSupported();
+        }
+        return true;
     }
 
     protected void loadSPIs(ProviderManager pm, List<Spi> spiList) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java
index 7a939c3..8cef8a1 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java
@@ -51,7 +51,7 @@ public class UserFederationTest extends AbstractAdminTest {
     @Test
     public void testProviderFactories() {
         List<UserFederationProviderFactoryRepresentation> providerFactories = userFederation().getProviderFactories();
-        Assert.assertNames(providerFactories, "ldap", "kerberos", "dummy", "dummy-configurable", "sssd");
+        Assert.assertNames(providerFactories, "ldap", "kerberos", "dummy", "dummy-configurable");
 
         // Builtin provider without properties
         UserFederationProviderFactoryRepresentation ldapProvider = userFederation().getProviderFactory("ldap");