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 58939eb49c..6d56d6e995 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 @@ + diff --git a/federation/sssd/pom.xml b/federation/sssd/pom.xml index 29113f7c8e..a9029c4e93 100644 --- a/federation/sssd/pom.xml +++ b/federation/sssd/pom.xml @@ -49,6 +49,7 @@ net.java.dev.jna jna + provided org.keycloak @@ -70,10 +71,6 @@ jboss-logging provided - - com.github.jnr - jnr-unixsocket - 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 0000000000..4088d46ebb --- /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 Bruno Oliveira. + */ +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/USInputStream.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/USInputStream.java index b11609f8a2..eb143fe6a9 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 RubyUNIXSocket.java - */ - 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 1855b26a44..d8c85a7718 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 RubyUNIXSocket.java - */ - 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/cx/ath/matthew/unix/UnixIOException.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixIOException.java new file mode 100644 index 0000000000..24fd20cd1f --- /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 7537f018ef..8851637436 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 UnixSocketChannel channel; + 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 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 0000000000..0baba479bb --- /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/org/freedesktop/dbus/MessageWriter.java b/federation/sssd/src/main/java/org/freedesktop/dbus/MessageWriter.java index 2a534263a3..45e8cb75f5 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 0c997bd021..1745bcfec2 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 { diff --git a/pom.xml b/pom.xml index 7918c6dade..2b2e697127 100755 --- a/pom.xml +++ b/pom.xml @@ -98,7 +98,6 @@ 1.0.2.Final 4.0.4 4.1.0 - 0.14 1.3.1b @@ -702,11 +701,6 @@ jna ${jna.version} - - com.github.jnr - jnr-unixsocket - ${jnr.version} - org.keycloak keycloak-ldap-federation 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 b11d5e43b4..68488cce7d 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 providerFactories = adminClient.realm(REALM_NAME).userFederation().getProviderFactories();