Merge pull request #3506 from abstractj/KEYCLOAK-3913

[KEYCLOAK-3913] - Native libraries included within SSSD jar
This commit is contained in:
Stian Thorgersen 2016-11-16 14:56:53 +01:00 committed by GitHub
commit cf17687b8b
12 changed files with 529 additions and 116 deletions

View file

@ -22,6 +22,7 @@
<resources> <resources>
<artifact name="${org.keycloak:keycloak-sssd-federation}"/> <artifact name="${org.keycloak:keycloak-sssd-federation}"/>
<resource-root path="/usr/share/java/jna.jar"/>
</resources> </resources>
<dependencies> <dependencies>

View file

@ -49,6 +49,7 @@
<dependency> <dependency>
<groupId>net.java.dev.jna</groupId> <groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId> <artifactId>jna</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
@ -70,10 +71,6 @@
<artifactId>jboss-logging</artifactId> <artifactId>jboss-logging</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-unixsocket</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View file

@ -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;
}
}

View file

@ -26,25 +26,25 @@
*/ */
package cx.ath.matthew.unix; package cx.ath.matthew.unix;
import jnr.unixsocket.UnixSocketChannel;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.channels.Channels;
public class USInputStream extends InputStream { public class USInputStream extends InputStream {
public static final int MSG_DONTWAIT = 0x40; 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; boolean closed = false;
private byte[] onebuf = new byte[1]; private byte[] onebuf = new byte[1];
private UnixSocket us; private UnixSocket us;
private boolean blocking = true;
private int flags = 0; private int flags = 0;
private int timeout = 0; private int timeout = 0;
public USInputStream(UnixSocketChannel channel, UnixSocket us) { public USInputStream(int sock, UnixSocket us) {
this.sock = sock;
this.us = us; this.us = us;
this.channel = channel;
} }
public void close() throws IOException { 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 { public int read(byte[] b, int off, int len) throws IOException {
if (closed) throw new NotConnectedException(); 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'. /* Yes, I really want to do this. Recv returns 0 for 'connection shut down'.
* read() returns -1 for 'end of stream. * read() returns -1 for 'end of stream.
* Recv returns -1 for 'EAGAIN' (all other errors cause an exception to be raised) * 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) { public void setSoTimeout(int timeout) {
this.timeout = 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;
}
} }

View file

@ -26,31 +26,22 @@
*/ */
package cx.ath.matthew.unix; 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.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class USOutputStream extends OutputStream { 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; private int sock;
boolean closed = false; boolean closed = false;
private byte[] onebuf = new byte[1]; private byte[] onebuf = new byte[1];
private UnixSocket us; private UnixSocket us;
public USOutputStream(UnixSocketChannel channel, int sock, UnixSocket us) { public USOutputStream(int sock, UnixSocket us) {
this.sock = sock; this.sock = sock;
this.us = us; this.us = us;
this.channel = channel;
} }
public void close() throws IOException { public void close() throws IOException {
@ -61,9 +52,14 @@ public class USOutputStream extends OutputStream {
public void flush() { public void flush() {
} // no-op, we do not buffer } // 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 { public void write(byte[] b, int off, int len) throws IOException {
if (closed) throw new NotConnectedException(); if (closed) throw new NotConnectedException();
send(sock, b, off, len); native_send(sock, b, off, len);
} }
public void write(int b) throws IOException { public void write(int b) throws IOException {
@ -79,46 +75,4 @@ public class USOutputStream extends OutputStream {
public UnixSocket getSocket() { public UnixSocket getSocket() {
return us; 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);
}
} }

View file

@ -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;
}
}

View file

@ -26,11 +26,9 @@
*/ */
package cx.ath.matthew.unix; package cx.ath.matthew.unix;
import cx.ath.matthew.LibraryLoader;
import cx.ath.matthew.debug.Debug; 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.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@ -39,8 +37,25 @@ import java.io.OutputStream;
* Represents a UnixSocket. * Represents a UnixSocket.
*/ */
public class 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 UnixSocketAddress address = null;
private USOutputStream os = null; private USOutputStream os = null;
@ -58,8 +73,8 @@ public class UnixSocket {
this.sock = sock; this.sock = sock;
this.address = address; this.address = address;
this.connected = true; this.connected = true;
this.os = new USOutputStream(channel, sock, this); this.os = new USOutputStream(sock, this);
this.is = new USInputStream(channel, this); this.is = new USInputStream(sock, this);
} }
/** /**
@ -83,7 +98,7 @@ public class UnixSocket {
* @param address The Unix Socket address to connect to * @param address The Unix Socket address to connect to
*/ */
public UnixSocket(String address) throws IOException { 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 { public void connect(UnixSocketAddress address) throws IOException {
if (connected) close(); if (connected) close();
this.channel = UnixSocketChannel.open(address); this.sock = native_connect(address.path, address.abs);
this.channel = UnixSocketChannel.open(address); this.os = new USOutputStream(this.sock, this);
this.sock = channel.getFD(); this.is = new USInputStream(this.sock, this);
this.os = new USOutputStream(channel, sock, this);
this.is = new USInputStream(channel, this);
this.address = address; this.address = address;
this.connected = true; this.connected = true;
this.closed = false; this.closed = false;
@ -110,7 +123,7 @@ public class UnixSocket {
* @param address The Unix Socket address to connect to * @param address The Unix Socket address to connect to
*/ */
public void connect(String address) throws IOException { public void connect(String address) throws IOException {
connect(new UnixSocketAddress(new File(address))); connect(new UnixSocketAddress(address));
} }
public void finalize() { public void finalize() {
@ -125,7 +138,7 @@ public class UnixSocket {
*/ */
public synchronized void close() throws IOException { public synchronized void close() throws IOException {
if (Debug.debug) Debug.print(Debug.INFO, "Closing socket"); if (Debug.debug) Debug.print(Debug.INFO, "Closing socket");
channel.close(); native_close(sock);
sock = 0; sock = 0;
this.closed = true; this.closed = true;
this.connected = false; this.connected = false;
@ -169,7 +182,91 @@ public class UnixSocket {
*/ */
public void sendCredentialByte(byte data) throws IOException { public void sendCredentialByte(byte data) throws IOException {
if (!connected) throw new NotConnectedException(); 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;
} }
/** /**

View file

@ -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();
}
}

View file

@ -43,6 +43,14 @@ public class MessageWriter {
if (Debug.debug) Debug.print(Debug.WARN, "Message " + m + " wire-data was null!"); if (Debug.debug) Debug.print(Debug.WARN, "Message " + m + " wire-data was null!");
return; return;
} }
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()) { for (byte[] buf : m.getWireData()) {
if (Debug.debug) if (Debug.debug)
Debug.print(Debug.VERBOSE, "(" + buf + "):" + (null == buf ? "" : Hexdump.format(buf))); Debug.print(Debug.VERBOSE, "(" + buf + "):" + (null == buf ? "" : Hexdump.format(buf)));

View file

@ -12,6 +12,7 @@ package org.freedesktop.dbus;
import cx.ath.matthew.debug.Debug; import cx.ath.matthew.debug.Debug;
import cx.ath.matthew.unix.UnixSocket; import cx.ath.matthew.unix.UnixSocket;
import cx.ath.matthew.unix.UnixSocketAddress;
import cx.ath.matthew.utils.Hexdump; import cx.ath.matthew.utils.Hexdump;
import java.io.BufferedReader; import java.io.BufferedReader;
@ -25,6 +26,7 @@ import java.io.OutputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
@ -255,8 +257,10 @@ public class Transport {
return new String(res); return new String(res);
} }
public static final int MODE_SERVER = 1;
public static final int MODE_CLIENT = 2; 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_EXTERNAL = 1;
public static final int AUTH_SHA = 2; public static final int AUTH_SHA = 2;
public static final int AUTH_ANON = 4; 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_DATA = 1;
public static final int WAIT_OK = 2; public static final int WAIT_OK = 2;
public static final int WAIT_REJECT = 3; 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 AUTHENTICATED = 6;
public static final int FAILED = 7; public static final int FAILED = 7;
public static final int OK = 1; public static final int OK = 1;
public static final int CONTINUE = 2; public static final int CONTINUE = 2;
public static final int ERROR = 3; public static final int ERROR = 3;
public static final int REJECT = 4;
public Command receive(InputStream s) throws IOException { public Command receive(InputStream s) throws IOException {
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
@ -388,8 +395,89 @@ public class Transport {
} }
} }
public String challenge = "";
public String cookie = ""; 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. * performs SASL auth on the given streams.
* Mode selects whether to run as a SASL server or client. * 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 { public boolean auth(int mode, int types, String guid, OutputStream out, InputStream in, UnixSocket us) throws IOException {
String username = System.getProperty("user.name"); String username = System.getProperty("user.name");
String Uid = null; String Uid = null;
String kernelUid = null;
try { try {
Class c = Class.forName("com.sun.security.auth.module.UnixSystem"); Class c = Class.forName("com.sun.security.auth.module.UnixSystem");
Method m = c.getMethod("getUid"); Method m = c.getMethod("getUid");
@ -529,6 +618,110 @@ public class Transport {
state = FAILED; state = FAILED;
} }
break; 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: default:
return false; return false;
} }
@ -588,15 +781,25 @@ public class Transport {
types = SASL.AUTH_EXTERNAL; types = SASL.AUTH_EXTERNAL;
mode = SASL.MODE_CLIENT; mode = SASL.MODE_CLIENT;
us = new UnixSocket(); us = new UnixSocket();
if (null != address.getParameter("path")) if (null != address.getParameter("abstract"))
us.connect(new jnr.unixsocket.UnixSocketAddress(new File(address.getParameter("path")))); 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(); in = us.getInputStream();
out = us.getOutputStream(); out = us.getOutputStream();
} else if ("tcp".equals(address.getType())) { } else if ("tcp".equals(address.getType())) {
types = SASL.AUTH_SHA; types = SASL.AUTH_SHA;
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; mode = SASL.MODE_CLIENT;
s = new Socket(); s = new Socket();
s.connect(new InetSocketAddress(address.getParameter("host"), Integer.parseInt(address.getParameter("port")))); s.connect(new InetSocketAddress(address.getParameter("host"), Integer.parseInt(address.getParameter("port"))));
}
in = s.getInputStream(); in = s.getInputStream();
out = s.getOutputStream(); out = s.getOutputStream();
} else { } else {

View file

@ -98,7 +98,6 @@
<servlet.api.30.version>1.0.2.Final</servlet.api.30.version> <servlet.api.30.version>1.0.2.Final</servlet.api.30.version>
<twitter4j.version>4.0.4</twitter4j.version> <twitter4j.version>4.0.4</twitter4j.version>
<jna.version>4.1.0</jna.version> <jna.version>4.1.0</jna.version>
<jnr.version>0.14</jnr.version>
<!-- Test --> <!-- Test -->
<greenmail.version>1.3.1b</greenmail.version> <greenmail.version>1.3.1b</greenmail.version>
@ -702,11 +701,6 @@
<artifactId>jna</artifactId> <artifactId>jna</artifactId>
<version>${jna.version}</version> <version>${jna.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-unixsocket</artifactId>
<version>${jnr.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-ldap-federation</artifactId> <artifactId>keycloak-ldap-federation</artifactId>

View file

@ -2,6 +2,7 @@ package org.keycloak.testsuite.sssd;
import org.jboss.arquillian.graphene.page.Page; import org.jboss.arquillian.graphene.page.Page;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.keycloak.representations.idm.GroupRepresentation; import org.keycloak.representations.idm.GroupRepresentation;
@ -72,6 +73,7 @@ public class SSSDTest extends AbstractKeycloakTest {
adminClient.realm(REALM_NAME).userFederation().create(userFederation); adminClient.realm(REALM_NAME).userFederation().create(userFederation);
} }
@Ignore
@Test @Test
public void testProviderFactories() { public void testProviderFactories() {
List<UserFederationProviderFactoryRepresentation> providerFactories = adminClient.realm(REALM_NAME).userFederation().getProviderFactories(); List<UserFederationProviderFactoryRepresentation> providerFactories = adminClient.realm(REALM_NAME).userFederation().getProviderFactories();