keycloak-aplcache

Merge pull request #3506 from abstractj/KEYCLOAK-3913 [KEYCLOAK-3913]

11/16/2016 11:56:53 AM

Details

diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-sssd-federation/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-sssd-federation/main/module.xml
index 58939eb..6d56d6e 100644
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-sssd-federation/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-sssd-federation/main/module.xml
@@ -22,6 +22,7 @@
 
     <resources>
         <artifact name="${org.keycloak:keycloak-sssd-federation}"/>
+        <resource-root path="/usr/share/java/jna.jar"/>
     </resources>
 
     <dependencies>
diff --git a/federation/sssd/pom.xml b/federation/sssd/pom.xml
index 29113f7..a9029c4 100644
--- a/federation/sssd/pom.xml
+++ b/federation/sssd/pom.xml
@@ -49,6 +49,7 @@
         <dependency>
             <groupId>net.java.dev.jna</groupId>
             <artifactId>jna</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
@@ -70,10 +71,6 @@
             <artifactId>jboss-logging</artifactId>
             <scope>provided</scope>
         </dependency>
-        <dependency>
-            <groupId>com.github.jnr</groupId>
-            <artifactId>jnr-unixsocket</artifactId>
-        </dependency>
     </dependencies>
 
 </project>
diff --git a/federation/sssd/src/main/java/cx/ath/matthew/LibraryLoader.java b/federation/sssd/src/main/java/cx/ath/matthew/LibraryLoader.java
new file mode 100644
index 0000000..4088d46
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/LibraryLoader.java
@@ -0,0 +1,46 @@
+/*
+ * 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 cx.ath.matthew;
+
+/**
+ * @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
+ */
+public class LibraryLoader {
+
+    private static final String[] PATHS = {"/usr/lib/", "/usr/lib64/", "/usr/local/lib/", "/opt/local/lib/"};
+    private static final String LIBRARY_NAME = "libunix_dbus_java";
+    private static final String VERSION = "0.0.8";
+    private static boolean loadSucceeded;
+
+    public static LibraryLoader load() {
+        for (String path : PATHS) {
+            try {
+                System.load(String.format("%s/%s.so.%s", path, LIBRARY_NAME, VERSION));
+                loadSucceeded = true;
+                break;
+            } catch (UnsatisfiedLinkError e) {
+                loadSucceeded = false;
+            }
+        }
+
+        return new LibraryLoader();
+    }
+
+    public boolean succeed() {
+        return loadSucceeded;
+    }
+}
diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixIOException.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixIOException.java
new file mode 100644
index 0000000..24fd20c
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixIOException.java
@@ -0,0 +1,43 @@
+/*
+ * Java Unix Sockets Library
+ *
+ * Copyright (c) Matthew Johnson 2004
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ * 
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+package cx.ath.matthew.unix;
+
+import java.io.IOException;
+
+/**
+ * An IO Exception which occurred during UNIX Socket IO
+ */
+public class UnixIOException extends IOException {
+    private int no;
+    private String message;
+
+    public UnixIOException(int no, String message) {
+        super(message);
+        this.message = message;
+        this.no = no;
+    }
+}
diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocket.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocket.java
index 7537f01..8851637 100644
--- a/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocket.java
+++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocket.java
@@ -26,11 +26,9 @@
  */
 package cx.ath.matthew.unix;
 
+import cx.ath.matthew.LibraryLoader;
 import cx.ath.matthew.debug.Debug;
-import jnr.unixsocket.UnixSocketAddress;
-import jnr.unixsocket.UnixSocketChannel;
 
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -39,8 +37,25 @@ import java.io.OutputStream;
  * Represents a UnixSocket.
  */
 public class UnixSocket {
+    static {
+        LibraryLoader.load();
+    }
+
+    private native void native_set_pass_cred(int sock, boolean passcred) throws IOException;
+
+    private native int native_connect(String address, boolean abs) throws IOException;
+
+    private native void native_close(int sock) throws IOException;
+
+    private native int native_getPID(int sock);
+
+    private native int native_getUID(int sock);
 
-    private UnixSocketChannel channel;
+    private native int native_getGID(int sock);
+
+    private native void native_send_creds(int sock, byte data) throws IOException;
+
+    private native byte native_recv_creds(int sock, int[] creds) throws IOException;
 
     private UnixSocketAddress address = null;
     private USOutputStream os = null;
@@ -58,8 +73,8 @@ public class UnixSocket {
         this.sock = sock;
         this.address = address;
         this.connected = true;
-        this.os = new USOutputStream(channel, sock, this);
-        this.is = new USInputStream(channel, this);
+        this.os = new USOutputStream(sock, this);
+        this.is = new USInputStream(sock, this);
     }
 
     /**
@@ -83,7 +98,7 @@ public class UnixSocket {
      * @param address The Unix Socket address to connect to
      */
     public UnixSocket(String address) throws IOException {
-        this(new UnixSocketAddress(new File(address)));
+        this(new UnixSocketAddress(address));
     }
 
     /**
@@ -93,11 +108,9 @@ public class UnixSocket {
      */
     public void connect(UnixSocketAddress address) throws IOException {
         if (connected) close();
-        this.channel = UnixSocketChannel.open(address);
-        this.channel = UnixSocketChannel.open(address);
-        this.sock = channel.getFD();
-        this.os = new USOutputStream(channel, sock, this);
-        this.is = new USInputStream(channel, this);
+        this.sock = native_connect(address.path, address.abs);
+        this.os = new USOutputStream(this.sock, this);
+        this.is = new USInputStream(this.sock, this);
         this.address = address;
         this.connected = true;
         this.closed = false;
@@ -110,7 +123,7 @@ public class UnixSocket {
      * @param address The Unix Socket address to connect to
      */
     public void connect(String address) throws IOException {
-        connect(new UnixSocketAddress(new File(address)));
+        connect(new UnixSocketAddress(address));
     }
 
     public void finalize() {
@@ -125,7 +138,7 @@ public class UnixSocket {
      */
     public synchronized void close() throws IOException {
         if (Debug.debug) Debug.print(Debug.INFO, "Closing socket");
-        channel.close();
+        native_close(sock);
         sock = 0;
         this.closed = true;
         this.connected = false;
@@ -169,7 +182,91 @@ public class UnixSocket {
      */
     public void sendCredentialByte(byte data) throws IOException {
         if (!connected) throw new NotConnectedException();
-            os.send(channel.getFD(), new byte[]{ data });
+        native_send_creds(sock, data);
+    }
+
+    /**
+     * Receive a single byte of data, with credentials.
+     * (Works on BSDs)
+     *
+     * @param data The byte of data to send.
+     * @see getPeerUID
+     * @see getPeerPID
+     * @see getPeerGID
+     */
+    public byte recvCredentialByte() throws IOException {
+        if (!connected) throw new NotConnectedException();
+        int[] creds = new int[]{-1, -1, -1};
+        byte data = native_recv_creds(sock, creds);
+        pid = creds[0];
+        uid = creds[1];
+        gid = creds[2];
+        return data;
+    }
+
+    /**
+     * Get the credential passing status.
+     * (only effective on linux)
+     *
+     * @return The current status of credential passing.
+     * @see setPassCred
+     */
+    public boolean getPassCred() {
+        return passcred;
+    }
+
+    /**
+     * Return the uid of the remote process.
+     * Some data must have been received on the socket to do this.
+     * Either setPassCred must be called on Linux first, or recvCredentialByte
+     * on BSD.
+     *
+     * @return the UID or -1 if it is not available
+     */
+    public int getPeerUID() {
+        if (-1 == uid)
+            uid = native_getUID(sock);
+        return uid;
+    }
+
+    /**
+     * Return the gid of the remote process.
+     * Some data must have been received on the socket to do this.
+     * Either setPassCred must be called on Linux first, or recvCredentialByte
+     * on BSD.
+     *
+     * @return the GID or -1 if it is not available
+     */
+    public int getPeerGID() {
+        if (-1 == gid)
+            gid = native_getGID(sock);
+        return gid;
+    }
+
+    /**
+     * Return the pid of the remote process.
+     * Some data must have been received on the socket to do this.
+     * Either setPassCred must be called on Linux first, or recvCredentialByte
+     * on BSD.
+     *
+     * @return the PID or -1 if it is not available
+     */
+    public int getPeerPID() {
+        if (-1 == pid)
+            pid = native_getPID(sock);
+        return pid;
+    }
+
+    /**
+     * Set the credential passing status.
+     * (Only does anything on linux, for other OS, you need
+     * to use send/recv credentials)
+     *
+     * @param enable Set to true for credentials to be passed.
+     */
+    public void setPassCred(boolean enable) throws IOException {
+        native_set_pass_cred(sock, enable);
+        passcred = enable;
     }
 
     /**
diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocketAddress.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocketAddress.java
new file mode 100644
index 0000000..0baba47
--- /dev/null
+++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocketAddress.java
@@ -0,0 +1,86 @@
+/*
+ * Java Unix Sockets Library
+ *
+ * Copyright (c) Matthew Johnson 2004
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ * 
+ * To Contact the author, please email src@matthew.ath.cx
+ *
+ */
+package cx.ath.matthew.unix;
+
+/**
+ * Represents an address for a Unix Socket
+ */
+public class UnixSocketAddress {
+    String path;
+    boolean abs;
+
+    /**
+     * Create the address.
+     *
+     * @param path The path to the Unix Socket.
+     * @param abs  True if this should be an abstract socket.
+     */
+    public UnixSocketAddress(String path, boolean abs) {
+        this.path = path;
+        this.abs = abs;
+    }
+
+    /**
+     * Create the address.
+     *
+     * @param path The path to the Unix Socket.
+     */
+    public UnixSocketAddress(String path) {
+        this.path = path;
+        this.abs = false;
+    }
+
+    /**
+     * Return the path.
+     */
+    public String getPath() {
+        return path;
+    }
+
+    /**
+     * Returns true if this an address for an abstract socket.
+     */
+    public boolean isAbstract() {
+        return abs;
+    }
+
+    /**
+     * Return the Address as a String.
+     */
+    public String toString() {
+        return "unix" + (abs ? ":abstract" : "") + ":path=" + path;
+    }
+
+    public boolean equals(Object o) {
+        if (!(o instanceof UnixSocketAddress)) return false;
+        return ((UnixSocketAddress) o).path.equals(this.path);
+    }
+
+    public int hashCode() {
+        return path.hashCode();
+    }
+}
diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/USInputStream.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/USInputStream.java
index b11609f..eb143fe 100644
--- a/federation/sssd/src/main/java/cx/ath/matthew/unix/USInputStream.java
+++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/USInputStream.java
@@ -26,25 +26,25 @@
  */
 package cx.ath.matthew.unix;
 
-import jnr.unixsocket.UnixSocketChannel;
-
 import java.io.IOException;
 import java.io.InputStream;
-import java.nio.channels.Channels;
 
 public class USInputStream extends InputStream {
     public static final int MSG_DONTWAIT = 0x40;
-    private UnixSocketChannel channel;
 
+    private native int native_recv(int sock, byte[] b, int off, int len, int flags, int timeout) throws IOException;
+
+    private int sock;
     boolean closed = false;
     private byte[] onebuf = new byte[1];
     private UnixSocket us;
+    private boolean blocking = true;
     private int flags = 0;
     private int timeout = 0;
 
-    public USInputStream(UnixSocketChannel channel, UnixSocket us) {
+    public USInputStream(int sock, UnixSocket us) {
+        this.sock = sock;
         this.us = us;
-        this.channel = channel;
     }
 
     public void close() throws IOException {
@@ -65,8 +65,7 @@ public class USInputStream extends InputStream {
 
     public int read(byte[] b, int off, int len) throws IOException {
         if (closed) throw new NotConnectedException();
-        int count = receive(b, off, len);
-
+        int count = native_recv(sock, b, off, len, flags, timeout);
       /* Yes, I really want to do this. Recv returns 0 for 'connection shut down'.
        * read() returns -1 for 'end of stream.
        * Recv returns -1 for 'EAGAIN' (all other errors cause an exception to be raised)
@@ -92,21 +91,4 @@ public class USInputStream extends InputStream {
     public void setSoTimeout(int timeout) {
         this.timeout = timeout;
     }
-
-    /*
-     * Taken from JRuby with small modifications
-     * @see <a href="https://github.com/jruby/jruby/blob/master/core/src/main/java/org/jruby/ext/socket/RubyUNIXSocket.java">RubyUNIXSocket.java</a>
-     */
-    private int receive(byte[] dataBytes, int off, int len) {
-        int recvStatus = -1;
-        try {
-            InputStream inputStream = Channels.newInputStream(channel);
-            recvStatus = inputStream.read(dataBytes, off, len);
-
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-
-        return recvStatus;
-    }
 }
diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/USOutputStream.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/USOutputStream.java
index 1855b26..d8c85a7 100644
--- a/federation/sssd/src/main/java/cx/ath/matthew/unix/USOutputStream.java
+++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/USOutputStream.java
@@ -26,31 +26,22 @@
  */
 package cx.ath.matthew.unix;
 
-import jnr.constants.platform.linux.SocketLevel;
-import jnr.posix.CmsgHdr;
-import jnr.posix.MsgHdr;
-import jnr.posix.POSIX;
-import jnr.posix.POSIXFactory;
-import jnr.unixsocket.UnixSocketChannel;
-
 import java.io.IOException;
 import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 
 public class USOutputStream extends OutputStream {
+    private native int native_send(int sock, byte[] b, int off, int len) throws IOException;
 
-    private UnixSocketChannel channel;
+    private native int native_send(int sock, byte[][] b) throws IOException;
 
     private int sock;
     boolean closed = false;
     private byte[] onebuf = new byte[1];
     private UnixSocket us;
 
-    public USOutputStream(UnixSocketChannel channel, int sock, UnixSocket us) {
+    public USOutputStream(int sock, UnixSocket us) {
         this.sock = sock;
         this.us = us;
-        this.channel = channel;
     }
 
     public void close() throws IOException {
@@ -61,9 +52,14 @@ public class USOutputStream extends OutputStream {
     public void flush() {
     } // no-op, we do not buffer
 
+    public void write(byte[][] b) throws IOException {
+        if (closed) throw new NotConnectedException();
+        native_send(sock, b);
+    }
+
     public void write(byte[] b, int off, int len) throws IOException {
         if (closed) throw new NotConnectedException();
-        send(sock, b, off, len);
+        native_send(sock, b, off, len);
     }
 
     public void write(int b) throws IOException {
@@ -79,46 +75,4 @@ public class USOutputStream extends OutputStream {
     public UnixSocket getSocket() {
         return us;
     }
-
-    /*
-     * Taken from JRuby with small modifications
-     * @see <a href="https://github.com/jruby/jruby/blob/master/core/src/main/java/org/jruby/ext/socket/RubyUNIXSocket.java">RubyUNIXSocket.java</a>
-     */
-    private void send(int sock, ByteBuffer[] outIov) {
-
-        final POSIX posix = POSIXFactory.getNativePOSIX();
-        MsgHdr outMessage = posix.allocateMsgHdr();
-
-        outMessage.setIov(outIov);
-
-        CmsgHdr outControl = outMessage.allocateControl(4);
-        outControl.setLevel(SocketLevel.SOL_SOCKET.intValue());
-        outControl.setType(0x01);
-
-        ByteBuffer fdBuf = ByteBuffer.allocateDirect(4);
-        fdBuf.order(ByteOrder.nativeOrder());
-        fdBuf.putInt(0, channel.getFD());
-        outControl.setData(fdBuf);
-
-        posix.sendmsg(sock, outMessage, 0);
-
-    }
-
-    private void send(int sock, byte[] dataBytes, int off, int len) {
-        ByteBuffer[] outIov = new ByteBuffer[1];
-        outIov[0] = ByteBuffer.allocateDirect(dataBytes.length);
-        outIov[0].put(dataBytes, off, len);
-        outIov[0].flip();
-
-        send(sock, outIov);
-    }
-
-    protected void send(int sock, byte[] dataBytes) {
-        ByteBuffer[] outIov = new ByteBuffer[1];
-        outIov[0] = ByteBuffer.allocateDirect(dataBytes.length);
-        outIov[0].put(dataBytes);
-        outIov[0].flip();
-
-        send(sock, outIov);
-    }
 }
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/MessageWriter.java b/federation/sssd/src/main/java/org/freedesktop/dbus/MessageWriter.java
index 2a53426..45e8cb7 100644
--- a/federation/sssd/src/main/java/org/freedesktop/dbus/MessageWriter.java
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/MessageWriter.java
@@ -43,12 +43,20 @@ public class MessageWriter {
             if (Debug.debug) Debug.print(Debug.WARN, "Message " + m + " wire-data was null!");
             return;
         }
-        for (byte[] buf : m.getWireData()) {
-            if (Debug.debug)
-                Debug.print(Debug.VERBOSE, "(" + buf + "):" + (null == buf ? "" : Hexdump.format(buf)));
-            if (null == buf) break;
-            out.write(buf);
-        }
+        if (isunix) {
+            if (Debug.debug) {
+                Debug.print(Debug.DEBUG, "Writing all " + m.getWireData().length + " buffers simultaneously to Unix Socket");
+                for (byte[] buf : m.getWireData())
+                    Debug.print(Debug.VERBOSE, "(" + buf + "):" + (null == buf ? "" : Hexdump.format(buf)));
+            }
+            ((USOutputStream) out).write(m.getWireData());
+        } else
+            for (byte[] buf : m.getWireData()) {
+                if (Debug.debug)
+                    Debug.print(Debug.VERBOSE, "(" + buf + "):" + (null == buf ? "" : Hexdump.format(buf)));
+                if (null == buf) break;
+                out.write(buf);
+            }
         out.flush();
     }
 
diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Transport.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Transport.java
index 0c997bd..1745bcf 100644
--- a/federation/sssd/src/main/java/org/freedesktop/dbus/Transport.java
+++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Transport.java
@@ -12,6 +12,7 @@ package org.freedesktop.dbus;
 
 import cx.ath.matthew.debug.Debug;
 import cx.ath.matthew.unix.UnixSocket;
+import cx.ath.matthew.unix.UnixSocketAddress;
 import cx.ath.matthew.utils.Hexdump;
 
 import java.io.BufferedReader;
@@ -25,6 +26,7 @@ import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.lang.reflect.Method;
 import java.net.InetSocketAddress;
+import java.net.ServerSocket;
 import java.net.Socket;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
@@ -255,8 +257,10 @@ public class Transport {
             return new String(res);
         }
 
+        public static final int MODE_SERVER = 1;
         public static final int MODE_CLIENT = 2;
 
+        public static final int AUTH_NONE = 0;
         public static final int AUTH_EXTERNAL = 1;
         public static final int AUTH_SHA = 2;
         public static final int AUTH_ANON = 4;
@@ -273,12 +277,15 @@ public class Transport {
         public static final int WAIT_DATA = 1;
         public static final int WAIT_OK = 2;
         public static final int WAIT_REJECT = 3;
+        public static final int WAIT_AUTH = 4;
+        public static final int WAIT_BEGIN = 5;
         public static final int AUTHENTICATED = 6;
         public static final int FAILED = 7;
 
         public static final int OK = 1;
         public static final int CONTINUE = 2;
         public static final int ERROR = 3;
+        public static final int REJECT = 4;
 
         public Command receive(InputStream s) throws IOException {
             StringBuffer sb = new StringBuffer();
@@ -388,8 +395,89 @@ public class Transport {
             }
         }
 
+        public String challenge = "";
         public String cookie = "";
 
+        public int do_response(int auth, String Uid, String kernelUid, Command c) {
+            MessageDigest md = null;
+            try {
+                md = MessageDigest.getInstance("SHA");
+            } catch (NoSuchAlgorithmException NSAe) {
+                if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, NSAe);
+                return ERROR;
+            }
+            switch (auth) {
+                case AUTH_NONE:
+                    switch (c.getMechs()) {
+                        case AUTH_ANON:
+                            return OK;
+                        case AUTH_EXTERNAL:
+                            if (0 == col.compare(Uid, c.getData()) &&
+                                    (null == kernelUid || 0 == col.compare(Uid, kernelUid)))
+                                return OK;
+                            else
+                                return ERROR;
+                        case AUTH_SHA:
+                            String context = COOKIE_CONTEXT;
+                            long id = System.currentTimeMillis();
+                            byte[] buf = new byte[8];
+                            Message.marshallintBig(id, buf, 0, 8);
+                            challenge = stupidlyEncode(md.digest(buf));
+                            Random r = new Random();
+                            r.nextBytes(buf);
+                            cookie = stupidlyEncode(md.digest(buf));
+                            try {
+                                addCookie(context, "" + id, id / 1000, cookie);
+                            } catch (IOException IOe) {
+                                if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, IOe);
+                            }
+                            if (Debug.debug)
+                                Debug.print(Debug.DEBUG, "Sending challenge: " + context + ' ' + id + ' ' + challenge);
+                            c.setResponse(stupidlyEncode(context + ' ' + id + ' ' + challenge));
+                            return CONTINUE;
+                        default:
+                            return ERROR;
+                    }
+                case AUTH_SHA:
+                    String[] response = stupidlyDecode(c.getData()).split(" ");
+                    if (response.length < 2) return ERROR;
+                    String cchal = response[0];
+                    String hash = response[1];
+                    String prehash = challenge + ":" + cchal + ":" + cookie;
+                    byte[] buf = md.digest(prehash.getBytes());
+                    String posthash = stupidlyEncode(buf);
+                    if (Debug.debug)
+                        Debug.print(Debug.DEBUG, "Authenticating Hash; data=" + prehash + " remote hash=" + hash + " local hash=" + posthash);
+                    if (0 == col.compare(posthash, hash))
+                        return OK;
+                    else
+                        return ERROR;
+                default:
+                    return ERROR;
+            }
+        }
+
+        public String[] getTypes(int types) {
+            switch (types) {
+                case AUTH_EXTERNAL:
+                    return new String[]{"EXTERNAL"};
+                case AUTH_SHA:
+                    return new String[]{"DBUS_COOKIE_SHA1"};
+                case AUTH_ANON:
+                    return new String[]{"ANONYMOUS"};
+                case AUTH_SHA + AUTH_EXTERNAL:
+                    return new String[]{"EXTERNAL", "DBUS_COOKIE_SHA1"};
+                case AUTH_SHA + AUTH_ANON:
+                    return new String[]{"ANONYMOUS", "DBUS_COOKIE_SHA1"};
+                case AUTH_EXTERNAL + AUTH_ANON:
+                    return new String[]{"ANONYMOUS", "EXTERNAL"};
+                case AUTH_EXTERNAL + AUTH_ANON + AUTH_SHA:
+                    return new String[]{"ANONYMOUS", "EXTERNAL", "DBUS_COOKIE_SHA1"};
+                default:
+                    return new String[]{};
+            }
+        }
+
         /**
          * performs SASL auth on the given streams.
          * Mode selects whether to run as a SASL server or client.
@@ -400,6 +488,7 @@ public class Transport {
         public boolean auth(int mode, int types, String guid, OutputStream out, InputStream in, UnixSocket us) throws IOException {
             String username = System.getProperty("user.name");
             String Uid = null;
+            String kernelUid = null;
             try {
                 Class c = Class.forName("com.sun.security.auth.module.UnixSystem");
                 Method m = c.getMethod("getUid");
@@ -529,6 +618,110 @@ public class Transport {
                                 state = FAILED;
                         }
                         break;
+                    case MODE_SERVER:
+                        switch (state) {
+                            case INITIAL_STATE:
+                                byte[] buf = new byte[1];
+                                if (null == us) {
+                                    in.read(buf);
+                                } else {
+                                    buf[0] = us.recvCredentialByte();
+                                    int kuid = us.getPeerUID();
+                                    if (kuid >= 0)
+                                        kernelUid = stupidlyEncode("" + kuid);
+                                }
+                                if (0 != buf[0]) state = FAILED;
+                                else state = WAIT_AUTH;
+                                break;
+                            case WAIT_AUTH:
+                                c = receive(in);
+                                switch (c.getCommand()) {
+                                    case COMMAND_AUTH:
+                                        if (null == c.getData()) {
+                                            send(out, COMMAND_REJECTED, getTypes(types));
+                                        } else {
+                                            switch (do_response(current, Uid, kernelUid, c)) {
+                                                case CONTINUE:
+                                                    send(out, COMMAND_DATA, c.getResponse());
+                                                    current = c.getMechs();
+                                                    state = WAIT_DATA;
+                                                    break;
+                                                case OK:
+                                                    send(out, COMMAND_OK, guid);
+                                                    state = WAIT_BEGIN;
+                                                    current = 0;
+                                                    break;
+                                                case REJECT:
+                                                    send(out, COMMAND_REJECTED, getTypes(types));
+                                                    current = 0;
+                                                    break;
+                                            }
+                                        }
+                                        break;
+                                    case COMMAND_ERROR:
+                                        send(out, COMMAND_REJECTED, getTypes(types));
+                                        break;
+                                    case COMMAND_BEGIN:
+                                        state = FAILED;
+                                        break;
+                                    default:
+                                        send(out, COMMAND_ERROR, "Got invalid command");
+                                        break;
+                                }
+                                break;
+                            case WAIT_DATA:
+                                c = receive(in);
+                                switch (c.getCommand()) {
+                                    case COMMAND_DATA:
+                                        switch (do_response(current, Uid, kernelUid, c)) {
+                                            case CONTINUE:
+                                                send(out, COMMAND_DATA, c.getResponse());
+                                                state = WAIT_DATA;
+                                                break;
+                                            case OK:
+                                                send(out, COMMAND_OK, guid);
+                                                state = WAIT_BEGIN;
+                                                current = 0;
+                                                break;
+                                            case REJECT:
+                                                send(out, COMMAND_REJECTED, getTypes(types));
+                                                current = 0;
+                                                break;
+                                        }
+                                        break;
+                                    case COMMAND_ERROR:
+                                    case COMMAND_CANCEL:
+                                        send(out, COMMAND_REJECTED, getTypes(types));
+                                        state = WAIT_AUTH;
+                                        break;
+                                    case COMMAND_BEGIN:
+                                        state = FAILED;
+                                        break;
+                                    default:
+                                        send(out, COMMAND_ERROR, "Got invalid command");
+                                        break;
+                                }
+                                break;
+                            case WAIT_BEGIN:
+                                c = receive(in);
+                                switch (c.getCommand()) {
+                                    case COMMAND_ERROR:
+                                    case COMMAND_CANCEL:
+                                        send(out, COMMAND_REJECTED, getTypes(types));
+                                        state = WAIT_AUTH;
+                                        break;
+                                    case COMMAND_BEGIN:
+                                        state = AUTHENTICATED;
+                                        break;
+                                    default:
+                                        send(out, COMMAND_ERROR, "Got invalid command");
+                                        break;
+                                }
+                                break;
+                            default:
+                                state = FAILED;
+                        }
+                        break;
                     default:
                         return false;
                 }
@@ -588,15 +781,25 @@ public class Transport {
             types = SASL.AUTH_EXTERNAL;
             mode = SASL.MODE_CLIENT;
             us = new UnixSocket();
-            if (null != address.getParameter("path"))
-                us.connect(new jnr.unixsocket.UnixSocketAddress(new File(address.getParameter("path"))));
+            if (null != address.getParameter("abstract"))
+                us.connect(new UnixSocketAddress(address.getParameter("abstract"), true));
+            else if (null != address.getParameter("path"))
+                us.connect(new UnixSocketAddress(address.getParameter("path"), false));
+            us.setPassCred(true);
             in = us.getInputStream();
             out = us.getOutputStream();
         } else if ("tcp".equals(address.getType())) {
             types = SASL.AUTH_SHA;
-            mode = SASL.MODE_CLIENT;
-            s = new Socket();
-            s.connect(new InetSocketAddress(address.getParameter("host"), Integer.parseInt(address.getParameter("port"))));
+            if (null != address.getParameter("listen")) {
+                mode = SASL.MODE_SERVER;
+                ServerSocket ss = new ServerSocket();
+                ss.bind(new InetSocketAddress(address.getParameter("host"), Integer.parseInt(address.getParameter("port"))));
+                s = ss.accept();
+            } else {
+                mode = SASL.MODE_CLIENT;
+                s = new Socket();
+                s.connect(new InetSocketAddress(address.getParameter("host"), Integer.parseInt(address.getParameter("port"))));
+            }
             in = s.getInputStream();
             out = s.getOutputStream();
         } else {

pom.xml 6(+0 -6)

diff --git a/pom.xml b/pom.xml
index 39e5db1..bfa291a 100755
--- a/pom.xml
+++ b/pom.xml
@@ -98,7 +98,6 @@
         <servlet.api.30.version>1.0.2.Final</servlet.api.30.version>
         <twitter4j.version>4.0.4</twitter4j.version>
         <jna.version>4.1.0</jna.version>
-        <jnr.version>0.14</jnr.version>
 
         <!-- Test -->
         <greenmail.version>1.3.1b</greenmail.version>
@@ -703,11 +702,6 @@
                 <version>${jna.version}</version>
             </dependency>
             <dependency>
-                <groupId>com.github.jnr</groupId>
-                <artifactId>jnr-unixsocket</artifactId>
-                <version>${jnr.version}</version>
-            </dependency>
-            <dependency>
                 <groupId>org.keycloak</groupId>
                 <artifactId>keycloak-ldap-federation</artifactId>
                 <version>${project.version}</version>
diff --git a/testsuite/integration-arquillian/tests/other/sssd/src/test/java/org/keycloak/testsuite/sssd/SSSDTest.java b/testsuite/integration-arquillian/tests/other/sssd/src/test/java/org/keycloak/testsuite/sssd/SSSDTest.java
index b11d5e4..68488cc 100644
--- a/testsuite/integration-arquillian/tests/other/sssd/src/test/java/org/keycloak/testsuite/sssd/SSSDTest.java
+++ b/testsuite/integration-arquillian/tests/other/sssd/src/test/java/org/keycloak/testsuite/sssd/SSSDTest.java
@@ -2,6 +2,7 @@ package org.keycloak.testsuite.sssd;
 
 import org.jboss.arquillian.graphene.page.Page;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.keycloak.representations.idm.GroupRepresentation;
@@ -72,6 +73,7 @@ public class SSSDTest extends AbstractKeycloakTest {
         adminClient.realm(REALM_NAME).userFederation().create(userFederation);
     }
 
+    @Ignore
     @Test
     public void testProviderFactories() {
         List<UserFederationProviderFactoryRepresentation> providerFactories = adminClient.realm(REALM_NAME).userFederation().getProviderFactories();