Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Bill Burke 2016-11-05 20:05:01 -04:00
commit 14dc0ff92f
57 changed files with 1167 additions and 687 deletions

View file

@ -118,12 +118,11 @@
/**
* Obtains all entitlements from a Keycloak Server based on a give resourceServerId.
*/
this.entitlement = function (resourceSeververId) {
this.entitlement = function (resourceSeververId, entitlementRequest ) {
this.then = function (onGrant, onDeny, onError) {
var request = new XMLHttpRequest();
request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true);
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
request.onreadystatechange = function () {
if (request.readyState == 4) {
@ -149,7 +148,19 @@
}
};
request.send(null);
var erJson = null
if(entitlementRequest) {
request.open('POST', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true);
request.setRequestHeader("Content-type", "application/json");
erJson = JSON.stringify(entitlementRequest)
} else {
request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true);
}
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
request.send(erJson);
};
return this;

View file

@ -63,6 +63,8 @@ JBoss Drools, which require ``photoz-authz-policy`` artifact installed into your
cd examples/authz/photoz
mvn clean install
> Please make sure you have the environment variable M2_HOME set. It should reference the path for your Maven installation. If not set, you will see some WARN messages in the logs when booting Keycloak.
Now, let's import another configuration using the Administration Console in order to configure the client application ``photoz-restful-api`` as a resource server with all resources, scopes, permissions and policies.
@ -71,7 +73,7 @@ open the ``Client Details`` page. Once there, click on the `Authorization` tab.
Click on the ``Select file`` button, which means you want to import a resource server configuration. Now select the file that is located at:
examples/authz/photoz/photoz-restful-api/photoz-restful-api-authz-config.json
examples/authz/photoz/photoz-restful-api/src/main/resources/photoz-restful-api-authz-service.json
Now click ``Upload`` and the resource server will be updated accordingly.

View file

@ -55,6 +55,12 @@
<build>
<finalName>${project.artifactId}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.jboss.as.plugins</groupId>

View file

@ -47,7 +47,7 @@
"logic": "POSITIVE",
"decisionStrategy": "UNANIMOUS",
"config": {
"mavenArtifactVersion": "2.1.0-SNAPSHOT",
"mavenArtifactVersion": "${project.version}",
"mavenArtifactId": "photoz-authz-policy",
"sessionName": "MainOwnerSession",
"mavenArtifactGroupId": "org.keycloak",

View file

@ -65,6 +65,10 @@
<artifactId>jboss-logging</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-unixsocket</artifactId>
</dependency>
</dependencies>
</project>

View file

@ -1,46 +0,0 @@
/*
* 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;
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(int sock, UnixSocket us) {
this.sock = sock;
public USInputStream(UnixSocketChannel channel, UnixSocket us) {
this.us = us;
this.channel = channel;
}
public void close() throws IOException {
@ -65,7 +65,8 @@ public class USInputStream extends InputStream {
public int read(byte[] b, int off, int len) throws IOException {
if (closed) throw new NotConnectedException();
int count = native_recv(sock, b, off, len, flags, timeout);
int count = receive(b, off, len);
/* 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)
@ -91,4 +92,21 @@ 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;
}
}

View file

@ -26,22 +26,31 @@
*/
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 native int native_send(int sock, byte[][] b) throws IOException;
private UnixSocketChannel channel;
private int sock;
boolean closed = false;
private byte[] onebuf = new byte[1];
private UnixSocket us;
public USOutputStream(int sock, UnixSocket us) {
public USOutputStream(UnixSocketChannel channel, int sock, UnixSocket us) {
this.sock = sock;
this.us = us;
this.channel = channel;
}
public void close() throws IOException {
@ -52,14 +61,9 @@ 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();
native_send(sock, b, off, len);
send(sock, b, off, len);
}
public void write(int b) throws IOException {
@ -75,4 +79,46 @@ 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);
}
}

View file

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

View file

@ -1,86 +0,0 @@
/*
* 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,20 +43,12 @@ public class MessageWriter {
if (Debug.debug) Debug.print(Debug.WARN, "Message " + m + " wire-data was null!");
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()) {
if (Debug.debug)
Debug.print(Debug.VERBOSE, "(" + buf + "):" + (null == buf ? "" : Hexdump.format(buf)));
if (null == buf) break;
out.write(buf);
}
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();
}

View file

@ -12,7 +12,6 @@ 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;
@ -26,7 +25,6 @@ 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;
@ -257,10 +255,8 @@ 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;
@ -277,15 +273,12 @@ 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();
@ -395,89 +388,8 @@ 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.
@ -488,7 +400,6 @@ 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");
@ -618,110 +529,6 @@ 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;
}
@ -781,25 +588,15 @@ public class Transport {
types = SASL.AUTH_EXTERNAL;
mode = SASL.MODE_CLIENT;
us = new UnixSocket();
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);
if (null != address.getParameter("path"))
us.connect(new jnr.unixsocket.UnixSocketAddress(new File(address.getParameter("path"))));
in = us.getInputStream();
out = us.getOutputStream();
} else if ("tcp".equals(address.getType())) {
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;
s = new Socket();
s.connect(new InetSocketAddress(address.getParameter("host"), Integer.parseInt(address.getParameter("port"))));
}
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 {

View file

@ -17,8 +17,6 @@
package org.keycloak.federation.sssd.api;
import cx.ath.matthew.LibraryLoader;
import org.freedesktop.DBus;
import org.freedesktop.dbus.DBusConnection;
import org.freedesktop.dbus.Variant;
import org.freedesktop.dbus.exceptions.DBusException;
@ -26,6 +24,9 @@ import org.freedesktop.sssd.infopipe.InfoPipe;
import org.freedesktop.sssd.infopipe.User;
import org.jboss.logging.Logger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@ -110,24 +111,17 @@ public class Sssd {
return userGroups;
}
public static boolean isAvailable(){
public static boolean isAvailable() {
boolean sssdAvailable = false;
try {
if (LibraryLoader.load().succeed()) {
DBusConnection connection = DBusConnection.getConnection(DBusConnection.SYSTEM);
DBus dbus = connection.getRemoteObject(DBus.BUSNAME, DBus.OBJECTPATH, DBus.class);
sssdAvailable = Arrays.asList(dbus.ListNames()).contains(InfoPipe.BUSNAME);
if (!sssdAvailable) {
logger.debugv("SSSD is not available in your system. Federation provider will be disabled.");
} else {
sssdAvailable = true;
}
connection.disconnect();
Path path = Paths.get("/etc/sssd");
if (!Files.exists(path)) {
logger.debugv("SSSD is not available in your system. Federation provider will be disabled.");
} else {
logger.debugv("libunix_dbus_java not found. Federation provider will be disabled.");
sssdAvailable = true;
}
} catch (DBusException e) {
logger.error("Failed to check the status of SSSD", e);
} catch (Exception e) {
logger.error("SSSD check failed", e);
}
return sssdAvailable;
}

View file

@ -108,13 +108,9 @@ public class CachedResourceStore implements ResourceStore {
@Override
public List<Resource> findByOwner(String ownerId) {
List<String> cachedIds = this.cache.get(getResourceOwnerCacheKey(ownerId));
if (cachedIds == null) {
for (Resource resource : getDelegate().findByOwner(ownerId)) {
updateCachedIds(getResourceOwnerCacheKey(ownerId), resource, true);
}
cachedIds = this.cache.getOrDefault(getResourceOwnerCacheKey(ownerId), Collections.emptyList());
for (Resource resource : getDelegate().findByOwner(ownerId)) {
updateCachedIds(getResourceOwnerCacheKey(ownerId), resource, true);
}
return ((List<String>) this.cache.getOrDefault(getResourceOwnerCacheKey(ownerId), Collections.emptyList())).stream().map(this::findById)

View file

@ -98,6 +98,7 @@
<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>
@ -700,6 +701,11 @@
<artifactId>jna</artifactId>
<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>

View file

@ -21,9 +21,11 @@ package org.keycloak.authorization.store;
import org.keycloak.authorization.store.syncronization.ClientApplicationSynchronizer;
import org.keycloak.authorization.store.syncronization.RealmSynchronizer;
import org.keycloak.authorization.store.syncronization.Synchronizer;
import org.keycloak.authorization.store.syncronization.UserSynchronizer;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel.ClientRemovedEvent;
import org.keycloak.models.RealmModel.RealmRemovedEvent;
import org.keycloak.models.UserModel.UserRemovedEvent;
import org.keycloak.provider.ProviderEvent;
import org.keycloak.provider.ProviderFactory;
@ -45,6 +47,7 @@ public interface AuthorizationStoreFactory extends ProviderFactory<StoreFactory>
synchronizers.put(ClientRemovedEvent.class, new ClientApplicationSynchronizer());
synchronizers.put(RealmRemovedEvent.class, new RealmSynchronizer());
synchronizers.put(UserRemovedEvent.class, new UserSynchronizer());
factory.register(event -> {
try {

View file

@ -0,0 +1,55 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.authorization.store.syncronization;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.authorization.store.ResourceStore;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserModel.UserRemovedEvent;
import org.keycloak.provider.ProviderFactory;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class UserSynchronizer implements Synchronizer<UserRemovedEvent> {
@Override
public void synchronize(UserRemovedEvent event, KeycloakSessionFactory factory) {
ProviderFactory<AuthorizationProvider> providerFactory = factory.getProviderFactory(AuthorizationProvider.class);
AuthorizationProvider authorizationProvider = providerFactory.create(event.getKeycloakSession());
StoreFactory storeFactory = authorizationProvider.getStoreFactory();
UserModel userModel = event.getUser();
ResourceStore resourceStore = storeFactory.getResourceStore();
PolicyStore policyStore = storeFactory.getPolicyStore();
resourceStore.findByOwner(userModel.getId()).forEach(resource -> {
String resourceId = resource.getId();
policyStore.findByResource(resourceId).forEach(policy -> {
if (policy.getResources().size() == 1) {
policyStore.delete(policy.getId());
} else {
policy.removeResource(resource);
}
});
resourceStore.delete(resourceId);
});
}
}

View file

@ -28,8 +28,11 @@ import org.keycloak.authorization.store.ResourceStore;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserFederationManager;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.services.ErrorResponse;
import org.keycloak.services.resources.admin.RealmAuth;
@ -76,12 +79,36 @@ public class ResourceSetService {
requireManage();
StoreFactory storeFactory = this.authorization.getStoreFactory();
Resource existingResource = storeFactory.getResourceStore().findByName(resource.getName(), this.resourceServer.getId());
ResourceOwnerRepresentation owner = resource.getOwner();
if (existingResource != null && existingResource.getResourceServer().getId().equals(this.resourceServer.getId())
&& existingResource.getOwner().equals(resource.getOwner())) {
&& existingResource.getOwner().equals(owner)) {
return ErrorResponse.exists("Resource with name [" + resource.getName() + "] already exists.");
}
if (owner != null) {
String ownerId = owner.getId();
if (ownerId != null) {
if (!resourceServer.getClientId().equals(ownerId)) {
RealmModel realm = authorization.getRealm();
KeycloakSession keycloakSession = authorization.getKeycloakSession();
UserFederationManager users = keycloakSession.users();
UserModel ownerModel = users.getUserById(ownerId, realm);
if (ownerModel == null) {
ownerModel = users.getUserByUsername(ownerId, realm);
}
if (ownerModel == null) {
return ErrorResponse.error("Owner must be a valid username or user identifier. If the resource server, the client id or null.", Status.BAD_REQUEST);
}
owner.setId(ownerModel.getId());
}
}
}
Resource model = toModel(resource, this.resourceServer, authorization);
ResourceRepresentation representation = new ResourceRepresentation();
@ -129,7 +156,7 @@ public class ResourceSetService {
if (policyModel.getResources().size() == 1) {
policyStore.delete(policyModel.getId());
} else {
policyModel.addResource(resource);
policyModel.removeResource(resource);
}
}

View file

@ -0,0 +1,40 @@
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="keycloakNamespace" select="'urn:jboss:domain:keycloak:'"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//*[local-name()='system-properties']">
<system-properties>
<property name="hawtio.authenticationEnabled" value="true" />
<property name="hawtio.realm" value="hawtio" />
<property name="hawtio.roles" value="admin,viewer" />
<property name="hawtio.rolePrincipalClasses" value="org.keycloak.adapters.jaas.RolePrincipal" />
<property name="hawtio.keycloakEnabled" value="true" />
<property name="hawtio.keycloakClientConfig" value="${{jboss.server.config.dir}}/keycloak-hawtio-client.json" />
<property name="hawtio.keycloakServerConfig" value="${{jboss.server.config.dir}}/keycloak-hawtio.json" />
</system-properties>
</xsl:template>
<xsl:template match="//*[local-name()='security-domain' and @name = 'hawtio-domain']">
<security-domain name="hawtio" cache-type="default">
<authentication>
<login-module code="org.keycloak.adapters.jaas.BearerTokenLoginModule" flag="required">
<module-option name="keycloak-config-file" value="${{hawtio.keycloakServerConfig}}"/>
</login-module>
</authentication>
</security-domain>
</xsl:template>
<xsl:template match="//*[local-name()='subsystem' and starts-with(namespace-uri(), $keycloakNamespace)]">
<xsl:copy>
<secure-deployment name="hawtio.war" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

View file

@ -0,0 +1,12 @@
#!/bin/bash
echo "FUSE_INSTALLER=$JBOSS_HOME/$FUSE_INSTALLER_NAME"
if [ ! -f "$JBOSS_HOME/$FUSE_INSTALLER_NAME" ] ; then
>&2 echo "JBOSS_HOME/$FUSE_INSTALLER_NAME doesn't exist"
exit 1
fi
cd $JBOSS_HOME
java -jar $FUSE_INSTALLER_NAME
rm $FUSE_INSTALLER_NAME
exit 0

View file

@ -0,0 +1,7 @@
{
"realm" : "demo",
"resource" : "hawtio-client",
"auth-server-url" : "http://localhost:8180/auth",
"ssl-required" : "external",
"public-client" : true
}

View file

@ -0,0 +1,9 @@
{
"realm" : "demo",
"resource" : "jaas",
"bearer-only" : true,
"auth-server-url" : "http://localhost:8180/auth",
"ssl-required" : "external",
"use-resource-role-mappings": false,
"principal-attribute": "preferred_username"
}

View file

@ -0,0 +1,132 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>integration-arquillian-servers-app-server-jboss</artifactId>
<groupId>org.keycloak.testsuite</groupId>
<version>2.4.0.CR1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>integration-arquillian-servers-app-server-eap6-fuse</artifactId>
<packaging>pom</packaging>
<name>App Server - JBoss - EAP 6 + Fuse integration</name>
<properties>
<app.server.jboss>eap6-fuse</app.server.jboss>
<app.server.jboss.groupId>org.jboss.as</app.server.jboss.groupId>
<app.server.jboss.artifactId>jboss-as-dist</app.server.jboss.artifactId>
<app.server.jboss.version>${eap6.version}</app.server.jboss.version>
<app.server.jboss.unpacked.folder.name>jboss-eap-6.4</app.server.jboss.unpacked.folder.name>
<fuse.installer.groupId>com.redhat.fuse.eap</fuse.installer.groupId>
<fuse.installer.artifactId>fuse-eap-installer</fuse.installer.artifactId>
<fuse.installer.version>6.3.0.redhat-187</fuse.installer.version>
<app.server.oidc.adapter.artifactId>keycloak-eap6-adapter-dist</app.server.oidc.adapter.artifactId>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack-fuse-installer</id>
<phase>generate-resources</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>${fuse.installer.groupId}</groupId>
<artifactId>${fuse.installer.artifactId}</artifactId>
<version>${fuse.installer.version}</version>
<type>jar</type>
<outputDirectory>${app.server.jboss.home}</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>install-fuse</id>
<phase>process-resources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>${common.resources}/install-fuse.${script.suffix}</executable>
<workingDirectory>${app.server.jboss.home}</workingDirectory>
<environmentVariables>
<JAVA_HOME>${app.server.java.home}</JAVA_HOME>
<JBOSS_HOME>${app.server.jboss.home}</JBOSS_HOME>
<FUSE_INSTALLER_NAME>${fuse.installer.artifactId}-${fuse.installer.version}.jar</FUSE_INSTALLER_NAME>
</environmentVariables>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>copy-hawtio-jsons</id>
<phase>process-test-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${app.server.jboss.home}/standalone/configuration</outputDirectory>
<resources>
<resource>
<directory>${common.resources}</directory>
<includes>
<include>keycloak-hawtio.json</include>
<include>keycloak-hawtio-client.json</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>xml-maven-plugin</artifactId>
<executions>
<execution>
<id>add-hawtio-to-standalone</id>
<phase>process-test-resources</phase>
<goals>
<goal>transform</goal>
</goals>
<configuration>
<transformationSets>
<transformationSet>
<dir>${app.server.jboss.home}/standalone/configuration</dir>
<includes>
<include>standalone.xml</include>
</includes>
<stylesheet>${common.resources}/add-hawtio.xsl</stylesheet>
<outputDir>${app.server.jboss.home}/standalone/configuration</outputDir>
</transformationSet>
</transformationSets>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View file

@ -108,7 +108,7 @@
<executions>
<execution>
<id>configure-adapter-debug-log</id>
<phase>process-resources</phase>
<phase>process-test-resources</phase>
<goals>
<goal>transform</goal>
</goals>
@ -189,7 +189,7 @@
<executions>
<execution>
<id>install-adapters</id>
<phase>process-test-resources</phase>
<phase>process-resources</phase>
<goals>
<goal>exec</goal>
</goals>
@ -437,7 +437,13 @@
<modules>
<module>relative</module>
</modules>
</profile>
</profile>
<profile>
<id>app-server-eap6-fuse</id>
<modules>
<module>eap6-fuse</module>
</modules>
</profile>
</profiles>
</project>

View file

@ -14,7 +14,7 @@
<name>Test apps distribution</name>
<build>
<finalName>${product.name}-${product.version}-test-apps</finalName>
<finalName>test-apps-dist</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>

View file

@ -0,0 +1,24 @@
package org.keycloak.testsuite.adapter.page;
import org.keycloak.testsuite.page.AbstractPage;
import javax.ws.rs.core.UriBuilder;
import java.net.URL;
/**
* @author mhajas
*/
public class HawtioPage extends AbstractPage {
public String getUrl() {
if (Boolean.parseBoolean(System.getProperty("app.server.ssl.required"))) {
return "https://localhost:" + System.getProperty("app.server.https.port", "8543") + "/hawtio";
}
return "http://localhost:" + System.getProperty("app.server.http.port", "8180") + "/hawtio";
}
@Override
public UriBuilder createUriBuilder() {
return UriBuilder.fromUri(getUrl());
}
}

View file

@ -74,7 +74,7 @@ public class URLProvider extends URLResourceProvider {
}
try {
if ("eap6".equals(System.getProperty("app.server"))) {
if (System.getProperty("app.server","").startsWith("eap6")) {
if (url == null) {
url = new URL("http://localhost:8080/");
}

View file

@ -32,7 +32,7 @@ public abstract class AbstractPageWithInjectedUrl extends AbstractPage {
//EAP6 URL fix
protected URL createInjectedURL(String url) {
if (!System.getProperty("app.server").equals("eap6")) {
if (!System.getProperty("app.server","").startsWith("eap6")) {
return null;
}
try {

View file

@ -68,6 +68,7 @@ public abstract class AbstractAdapterTest extends AbstractAuthTest {
} else {
modifyClientRedirectUris(tr, "^(/.*/\\*)", appServerContextRootPage.toString() + "$1");
modifyClientUrls(tr, "^(/.*)", appServerContextRootPage.toString() + "$1");
modifyClientWebOrigins(tr, "8080", System.getProperty("app.server.http.port", null));
modifySamlMasterURLs(tr, "8080", System.getProperty("auth.server.http.port", null));
modifySAMLClientsAttributes(tr, "8080", System.getProperty("app.server.http.port", "8280"));
modifyClientJWKSUrl(tr, "^(/.*)", appServerContextRootPage.toString() + "$1");

View file

@ -51,13 +51,7 @@ public abstract class AbstractExampleAdapterTest extends AbstractAdapterTest {
System.out.println(EXAMPLES_VERSION_SUFFIX);
EXAMPLES_HOME_DIR = EXAMPLES_HOME + "/example-realms";
if (!System.getProperty("unpacked.container.folder.name","").isEmpty()) {
TEST_APPS_HOME_DIR = EXAMPLES_HOME + "/" + System.getProperty("unpacked.container.folder.name","") + "-test-apps";
} else {
TEST_APPS_HOME_DIR = EXAMPLES_HOME + "/Keycloak-" + EXAMPLES_VERSION_SUFFIX + "-test-apps";
}
TEST_APPS_HOME_DIR = EXAMPLES_HOME + "/test-apps-dist";
EXAMPLES_WEB_XML = EXAMPLES_HOME + "/web.xml";
}

View file

@ -0,0 +1,41 @@
package org.keycloak.testsuite.adapter.example;
import org.jboss.arquillian.graphene.page.Page;
import org.junit.Ignore;
import org.junit.Test;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
import org.keycloak.testsuite.adapter.page.HawtioPage;
import java.io.File;
import java.util.List;
import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO;
import static org.keycloak.testsuite.util.IOUtil.loadRealm;
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
/**
* @author mhajas
*/
public class AbstractHawtioAdapterTest extends AbstractExampleAdapterTest {
@Page
private HawtioPage hawtioPage;
@Override
public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
testRealms.add(loadRealm("/adapter-test/hawtio-realm/demorealm.json"));
}
@Test
@Ignore //Waiting for PATCH-1446
public void hawtioTest() {
testRealmLoginPage.setAuthRealm(DEMO);
hawtioPage.navigateTo();
assertCurrentUrlStartsWith(testRealmLoginPage);
testRealmLoginPage.form().login("root", "password");
assertCurrentUrlStartsWith(hawtioPage.getDriver(), hawtioPage.toString() + "/welcome");
}
}

View file

@ -20,6 +20,7 @@ import org.jboss.arquillian.container.test.api.Deployer;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.BeforeClass;
import org.junit.Test;
import org.keycloak.admin.client.resource.AuthorizationResource;
import org.keycloak.admin.client.resource.ClientResource;
@ -27,6 +28,7 @@ import org.keycloak.admin.client.resource.ClientsResource;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.testsuite.ProfileAssume;
import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
import java.io.File;
@ -47,6 +49,9 @@ public abstract class AbstractDefaultAuthzConfigAdapterTest extends AbstractExam
private static final String REALM_NAME = "hello-world-authz";
private static final String RESOURCE_SERVER_ID = "hello-world-authz-service";
@BeforeClass
public static void enabled() { ProfileAssume.assumePreview(); }
@ArquillianResource
private Deployer deployer;

View file

@ -22,6 +22,7 @@ import org.jboss.arquillian.graphene.page.Page;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.keycloak.admin.client.resource.AuthorizationResource;
import org.keycloak.admin.client.resource.ClientResource;
@ -37,6 +38,7 @@ import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
import org.keycloak.testsuite.ProfileAssume;
import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
import org.keycloak.testsuite.adapter.page.PhotozClientAuthzTestApp;
import org.keycloak.util.JsonSerialization;
@ -79,6 +81,9 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractExampleAd
testRealmPage.setAuthRealm(REALM_NAME);
}
@BeforeClass
public static void enabled() { ProfileAssume.assumePreview(); }
@Before
public void beforePhotozExampleAdapterTest() throws FileNotFoundException {
deleteAllCookiesForClientPage();

View file

@ -20,6 +20,7 @@ import org.jboss.arquillian.container.test.api.Deployer;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.BeforeClass;
import org.junit.Test;
import org.keycloak.admin.client.resource.AuthorizationResource;
import org.keycloak.admin.client.resource.ClientResource;
@ -33,6 +34,7 @@ import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
import org.keycloak.testsuite.ProfileAssume;
import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
import org.keycloak.testsuite.util.WaitUtils;
import org.keycloak.util.JsonSerialization;
@ -63,6 +65,9 @@ public abstract class AbstractServletAuthzAdapterTest extends AbstractExampleAda
private static final String REALM_NAME = "servlet-authz";
private static final String RESOURCE_SERVER_ID = "servlet-authz-app";
@BeforeClass
public static void enabled() { ProfileAssume.assumePreview(); }
@ArquillianResource
private Deployer deployer;

View file

@ -78,6 +78,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import static org.keycloak.services.resources.admin.RealmAuth.Resource.AUTHORIZATION;
import static org.keycloak.services.resources.admin.RealmAuth.Resource.CLIENT;
import org.keycloak.testsuite.ProfileAssume;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@ -782,6 +783,7 @@ public class PermissionsTest extends AbstractKeycloakTest {
@Test
public void clientAuthorization() {
ProfileAssume.assumePreview();
invoke(new InvocationWithResponse() {
public void invoke(RealmResource realm, AtomicReference<Response> response) {
realm.clients().create(ClientBuilder.create().clientId("foo-authz").build());

View file

@ -32,6 +32,8 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import static org.keycloak.common.Profile.isPreviewEnabled;
/**
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
*/
@ -135,7 +137,9 @@ public class ProvidersTest extends AbstractAuthenticationTest {
"Validates a OTP on a separate OTP form. Only shown if required based on the configured conditions.");
addProviderInfo(result, "auth-cookie", "Cookie", "Validates the SSO cookie set by the auth server.");
addProviderInfo(result, "auth-otp-form", "OTP Form", "Validates a OTP on a separate OTP form.");
addProviderInfo(result, "auth-script-based", "Script", "Script based authentication. Allows to define custom authentication logic via JavaScript.");
if (isPreviewEnabled()) {
addProviderInfo(result, "auth-script-based", "Script", "Script based authentication. Allows to define custom authentication logic via JavaScript.");
}
addProviderInfo(result, "auth-spnego", "Kerberos", "Initiates the SPNEGO protocol. Most often used with Kerberos.");
addProviderInfo(result, "auth-username-password-form", "Username Password Form",
"Validates a username and password from login form.");

View file

@ -0,0 +1,31 @@
package org.keycloak.testsuite.admin.authentication;
import org.junit.Assert;
import org.junit.Test;
import org.keycloak.testsuite.ProfileAssume;
import javax.ws.rs.BadRequestException;
import java.util.HashMap;
/**
* @author mhajas
*/
public class ScriptBasedAuthenticatorTest extends AbstractAuthenticationTest {
@Test
public void checkIfTurnedOffWithProductProfile() throws InterruptedException {
ProfileAssume.assumePreviewDisabled();
HashMap<String, String> params = new HashMap<>();
params.put("newName", "Copy-of-browser");
authMgmtResource.copy("browser", params);
params.put("provider", "auth-script-based");
try {
authMgmtResource.addExecution("Copy-of-browser", params);
Assert.fail("Adding script based authenticator should fail with product profile");
} catch (BadRequestException ex) {
//Expected
}
}
}

View file

@ -14,8 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.adapter.example.authorization;
package org.keycloak.testsuite.admin.client.authorization;
import org.junit.BeforeClass;
import org.junit.Test;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
@ -23,6 +24,7 @@ import org.keycloak.adapters.authorization.PolicyEnforcer;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.ProfileAssume;
import java.util.List;
@ -34,6 +36,9 @@ import static org.keycloak.testsuite.util.IOUtil.loadRealm;
*/
public class EnforcerConfigTest extends AbstractKeycloakTest {
@BeforeClass
public static void enabled() { ProfileAssume.assumePreview(); }
@Override
public void addTestRealms(List<RealmRepresentation> testRealms) {
RealmRepresentation realm = loadRealm(getClass().getResourceAsStream("/authorization-test/test-authz-realm.json"));

View file

@ -28,8 +28,15 @@ import java.net.URLEncoder;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient;
import static org.keycloak.testsuite.admin.ApiUtil.resetUserPassword;
import static org.keycloak.testsuite.broker.BrokerTestConstants.USER_EMAIL;
import org.keycloak.testsuite.pages.IdpConfirmLinkPage;
import static org.keycloak.testsuite.util.MailAssert.assertEmailAndGetUrl;
import org.keycloak.testsuite.util.MailServer;
import org.keycloak.testsuite.util.MailServerConfiguration;
import org.keycloak.testsuite.util.UserBuilder;
public abstract class AbstractBrokerTest extends AbstractKeycloakTest {
@ -61,6 +68,9 @@ public abstract class AbstractBrokerTest extends AbstractKeycloakTest {
@Page
protected ErrorPage errorPage;
@Page
protected IdpConfirmLinkPage idpConfirmLinkPage;
@Override
public void addTestRealms(List<RealmRepresentation> testRealms) {
@ -199,6 +209,68 @@ public abstract class AbstractBrokerTest extends AbstractKeycloakTest {
assertEquals(userCount, adminClient.realm(consumerRealmName()).users().count());
}
// KEYCLOAK-2957
@Test
public void testLinkAccountWithEmailVerified() {
//start mail server
MailServer.start();
MailServer.createEmailAccount(USER_EMAIL, "password");
try {
//configure smpt server in the realm
RealmRepresentation master = adminClient.realm(consumerRealmName()).toRepresentation();
master.setSmtpServer(suiteContext.getSmtpServer());
adminClient.realm(consumerRealmName()).update(master);
//create user on consumer's site who should be linked later
UserRepresentation newUser = UserBuilder.create().username("consumer").email(USER_EMAIL).enabled(true).build();
String userId = createUserWithAdminClient(adminClient.realm(consumerRealmName()), newUser);
resetUserPassword(adminClient.realm(consumerRealmName()).users().get(userId), "password", false);
//test
driver.navigate().to(getAccountUrl(consumerRealmName()));
log.debug("Clicking social " + getIDPAlias());
accountLoginPage.clickSocial(getIDPAlias());
waitForPage("log in to");
Assert.assertTrue("Driver should be on the provider realm page right now",
driver.getCurrentUrl().contains("/auth/realms/" + providerRealmName() + "/"));
log.debug("Logging in");
accountLoginPage.login(getUserLogin(), getUserPassword());
waitForPage("update account information");
Assert.assertTrue(updateAccountInformationPage.isCurrent());
Assert.assertTrue("We must be on correct realm right now",
driver.getCurrentUrl().contains("/auth/realms/" + consumerRealmName() + "/"));
log.debug("Updating info on updateAccount page");
updateAccountInformationPage.updateAccountInformation("Firstname", "Lastname");
//link account by email
waitForPage("account already exists");
idpConfirmLinkPage.clickLinkAccount();
String url = assertEmailAndGetUrl(MailServerConfiguration.FROM, USER_EMAIL,
"Someone wants to link your ", false);
log.info("navigating to url from email: " + url);
driver.navigate().to(url);
//test if user is logged in
assertEquals(accountPage.buildUri().toASCIIString().replace("master", "consumer") + "/", driver.getCurrentUrl());
//test if the user has verified email
assertTrue(adminClient.realm(consumerRealmName()).users().get(userId).toRepresentation().isEmailVerified());
} finally {
// stop mail server
MailServer.stop();
}
}
// KEYCLOAK-3267
@Test

View file

@ -61,6 +61,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import org.keycloak.common.Profile;
/**
*
@ -374,8 +375,10 @@ public class ExportImportUtil {
UserRepresentation linked = testingClient.testing().getUserByServiceAccountClient(realm.getRealm(), otherApp.getClientId());//session.users().getUserByServiceAccountClient(otherApp);
Assert.assertNotNull(linked);
Assert.assertEquals("my-service-user", linked.getUsername());
assertAuthorizationSettings(realmRsc);
if (Profile.isPreviewEnabled()) {
assertAuthorizationSettings(realmRsc);
}
}
private static boolean isProtocolMapperGranted(Map<String, Object> consent, ProtocolMapperRepresentation mapperRep) {

View file

@ -18,10 +18,7 @@ package org.keycloak.testsuite.forms;
import org.apache.commons.io.IOUtils;
import org.jboss.arquillian.graphene.page.Page;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.*;
import org.keycloak.authentication.authenticators.browser.ScriptBasedAuthenticatorFactory;
import org.keycloak.authentication.authenticators.browser.UsernamePasswordFormFactory;
import org.keycloak.events.Details;
@ -34,6 +31,7 @@ import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.ProfileAssume;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.util.ExecutionBuilder;
import org.keycloak.testsuite.util.FlowBuilder;
@ -62,6 +60,9 @@ public class ScriptAuthenticatorTest extends AbstractFlowTest {
private AuthenticationFlowRepresentation flow;
@BeforeClass
public static void enabled() { ProfileAssume.assumePreview(); }
@Override
public void configureTestRealm(RealmRepresentation testRealm) {

View file

@ -30,10 +30,9 @@ import org.keycloak.testsuite.util.GreenMailRule;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import static org.junit.Assert.assertEquals;
import org.keycloak.testsuite.ProfileAssume;
/**
* @author <a href="mailto:gerbermichi@me.com">Michael Gerber</a>
@ -84,6 +83,8 @@ public class EmailTest extends AbstractI18NTest {
@Test
public void restPasswordEmailGerman() throws IOException, MessagingException {
ProfileAssume.assumePreview();
changeUserLocale("de");
loginPage.open();

View file

@ -17,7 +17,6 @@
package org.keycloak.testsuite.i18n;
import org.apache.http.impl.client.DefaultHttpClient;
import org.jboss.arquillian.graphene.page.Page;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine;
@ -29,6 +28,7 @@ import org.keycloak.testsuite.pages.LoginPage;
import javax.ws.rs.core.Response;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.testsuite.ProfileAssume;
import org.keycloak.testsuite.util.IdentityProviderBuilder;
/**
@ -97,6 +97,8 @@ public class LoginPageTest extends AbstractI18NTest {
@Test
public void acceptLanguageHeader() {
ProfileAssume.assumePreview();
DefaultHttpClient httpClient = (DefaultHttpClient) new HttpClientBuilder().build();
ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient);
ResteasyClient client = new ResteasyClientBuilder().httpEngine(engine).build();

View file

@ -41,7 +41,8 @@ public class MailAssert {
message= SslMailServer.getLastReceivedMessage();
} else {
message = MailServer.getLastReceivedMessage();
} assertNotNull("There is no received email.", message);
}
assertNotNull("There is no received email.", message);
assertEquals(recipient, message.getRecipients(RecipientType.TO)[0].toString());
assertEquals(from, message.getFrom()[0].toString());

View file

@ -0,0 +1,285 @@
{
"realm": "demo",
"enabled": true,
"accessTokenLifespan": 60,
"accessCodeLifespan": 60,
"accessCodeLifespanUserAction": 300,
"ssoSessionIdleTimeout": 600,
"ssoSessionMaxLifespan": 36000,
"sslRequired": "external",
"registrationAllowed": false,
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"requiredCredentials": [ "password" ],
"users" : [
{
"username" : "bburke@redhat.com",
"enabled": true,
"email" : "bburke@redhat.com",
"firstName": "Bill",
"lastName": "Burke",
"credentials" : [
{ "type" : "password",
"value" : "password" }
],
"realmRoles": [ "user" ],
"clientRoles": {
"account": [ "manage-account" ]
}
},
{
"username" : "stian",
"enabled": true,
"email" : "stian@redhat.com",
"firstName": "Stian",
"lastName": "Thorgersen",
"credentials" : [
{ "type" : "password",
"value" : "password" }
],
"realmRoles": [ "user" ],
"clientRoles": {
"account": [ "manage-account" ]
}
},
{
"username" : "mposolda@redhat.com",
"enabled": true,
"email" : "mposolda@redhat.com",
"firstName": "Marek",
"lastName": "Posolda",
"credentials" : [
{ "type" : "password",
"value" : "password" }
],
"realmRoles": [ "user" ],
"clientRoles": {
"account": [ "manage-account" ]
}
},
{
"username" : "admin",
"enabled": true,
"email" : "admin@admin.com",
"firstName": "Admin",
"lastName": "Burke",
"credentials" : [
{ "type" : "password",
"value" : "password" }
],
"realmRoles": [ "user","admin" ],
"clientRoles": {
"realm-management": [ "realm-admin" ],
"account": [ "manage-account" ]
}
},
{
"username" : "jmxadmin",
"enabled": true,
"email" : "jmxadmin@admin.com",
"firstName": "JmxAdmin",
"lastName": "Burke",
"credentials" : [
{ "type" : "password",
"value" : "password" }
],
"realmRoles": [ "user", "jmxAdmin" ],
"clientRoles": {
"account": [ "manage-account" ],
"realm-management": [ "realm-admin" ]
}
},
{
"username" : "john",
"firstName" : "John",
"lastName" : "Anthony",
"email" : "john@hawt.io",
"enabled" : true,
"credentials" : [
{
"type" : "password",
"value" : "password"
}
],
"realmRoles" : [ "viewer" ],
"applicationRoles": {
"account" : [ "view-profile", "manage-account" ]
}
},
{
"username" : "mary",
"firstName" : "Mary",
"lastName" : "Kelly",
"email" : "mary@hawt.io",
"enabled" : true,
"credentials" : [
{
"type" : "password",
"value" : "password"
}
],
"applicationRoles": {
"account" : [ "view-profile", "manage-account" ]
}
},
{
"username" : "root",
"firstName" : "Root",
"lastName" : "Root",
"email" : "root@hawt.io",
"enabled" : true,
"credentials" : [
{
"type" : "password",
"value" : "password"
}
],
"realmRoles" : [ "jmxAdmin" ],
"applicationRoles": {
"account" : [ "view-profile", "manage-account" ],
"realm-management" : [ "realm-admin" ]
}
}
],
"roles" : {
"realm" : [
{
"name": "user",
"description": "User privileges"
},
{
"name": "admin",
"description": "Administrator privileges"
},
{
"name": "manager"
},
{
"name": "viewer"
},
{
"name": "Operator"
},
{
"name": "Maintainer"
},
{
"name": "Deployer"
},
{
"name": "Auditor"
},
{
"name": "Administrator"
},
{
"name": "SuperUser"
},
{
"name": "jmxAdmin",
"description": "Admin role with all privileges to SSH and JMX access",
"composite": true,
"composites": {
"realm": [ "admin", "manager", "viewer", "Operator", "Maintainer", "Deployer", "Auditor", "Administrator", "SuperUser" ]
}
}
]
},
"clients": [
{
"clientId": "customer-portal",
"enabled": true,
"adminUrl": "http://localhost:8181/customer-portal",
"baseUrl": "http://localhost:8181/customer-portal",
"redirectUris": [
"http://localhost:8181/customer-portal/*"
],
"secret": "password"
},
{
"clientId": "example-camel-cdi",
"enabled": true,
"adminUrl": "http://localhost:8080/example-camel-cdi",
"baseUrl": "http://localhost:8080/example-camel-cdi",
"redirectUris": [
"http://localhost:8080/example-camel-cdi/*"
],
"secret": "password"
},
{
"clientId": "product-portal",
"enabled": true,
"adminUrl": "http://localhost:8181/product-portal",
"baseUrl": "http://localhost:8181/product-portal",
"redirectUris": [
"http://localhost:8181/product-portal/*"
],
"secret": "password"
},
{
"clientId": "builtin-cxf-app",
"enabled": true,
"adminUrl": "http://localhost:8181/cxf",
"baseUrl": "http://localhost:8181/cxf",
"redirectUris": [
"http://localhost:8181/cxf/*"
],
"secret": "password"
},
{
"clientId": "custom-cxf-endpoint",
"enabled": true,
"adminUrl": "http://localhost:8282/PersonServiceCF",
"baseUrl": "http://localhost:8282/PersonServiceCF",
"bearerOnly": true
},
{
"clientId": "admin-camel-endpoint",
"enabled": true,
"adminUrl": "http://localhost:8383/admin-camel-endpoint",
"baseUrl": "http://localhost:8383/admin-camel-endpoint",
"bearerOnly": true
},
{
"clientId": "ssh-jmx-admin-client",
"enabled": true,
"publicClient": false,
"standardFlowEnabled": false,
"directAccessGrantsEnabled": true,
"secret": "password"
},
{
"clientId": "external-config",
"enabled": true,
"adminUrl": "http://localhost:8181/external-config",
"baseUrl": "http://localhost:8181/external-config",
"redirectUris": [
"http://localhost:8181/external-config",
"http://localhost:8181/external-config/*"
],
"secret": "password"
},
{
"clientId" : "hawtio-client",
"surrogateAuthRequired" : false,
"fullScopeAllowed" : false,
"enabled" : true,
"redirectUris" : ["http://localhost:8080/hawtio/*" ],
"webOrigins" : [ "http://localhost:8080"],
"bearerOnly" : false,
"publicClient" : true,
"protocol" : "openid-connect"
}
],
"scopeMappings": [
{
"client": "ssh-jmx-admin-client",
"roles": [ "admin", "jmxAdmin" ]
},
{
"client": "hawtio-client",
"roles": [ "viewer", "jmxAdmin" ]
}
]
}

View file

@ -67,6 +67,7 @@
-Djboss.bind.address=0.0.0.0
${adapter.test.props}
${migration.import.properties}
${auth.server.profile}
</property>
<property name="javaVmArguments">
${auth.server.memory.settings}
@ -89,6 +90,7 @@
-Djboss.socket.binding.port-offset=${auth.server.backend1.port.offset}
-Djboss.node.name=node1
${adapter.test.props}
${auth.server.profile}
</property>
<property name="javaVmArguments">
${auth.server.memory.settings}
@ -109,6 +111,7 @@
-Djboss.socket.binding.port-offset=${auth.server.backend2.port.offset}
-Djboss.node.name=node2
${adapter.test.props}
${auth.server.profile}
</property>
<property name="javaVmArguments">
${auth.server.memory.settings}

View file

@ -0,0 +1,41 @@
<?xml version="1.0"?>
<!--
~ 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.
-->
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.keycloak.testsuite</groupId>
<artifactId>integration-arquillian-tests-adapters-jboss</artifactId>
<version>2.4.0.CR1-SNAPSHOT</version>
</parent>
<artifactId>integration-arquillian-tests-adapters-eap6-fuse</artifactId>
<name>Adapter Tests - JBoss - EAP 6</name>
<properties>
<app.server>eap6-fuse</app.server>
<app.server.management.protocol>remote</app.server.management.protocol>
<app.server.management.port>${app.server.management.port.jmx}</app.server.management.port>
</properties>
</project>

View file

@ -0,0 +1,10 @@
package org.keycloak.testsuite.adapter.example;
import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
/**
* @author mhajas
*/
@AppServerContainer("app-server-eap6-fuse")
public class EAP6FUSEHawtioAdapterTest extends AbstractHawtioAdapterTest {
}

View file

@ -176,8 +176,13 @@
<modules>
<module>relative</module>
</modules>
</profile>
</profile>
<profile>
<id>app-server-eap6-fuse</id>
<modules>
<module>eap6-fuse</module>
</modules>
</profile>
</profiles>
</project>

View file

@ -88,6 +88,7 @@ public class AdminEventsTest extends AbstractConsoleTest {
assertEquals(1, resultList.size());
resultList.get(0).findElement(By.xpath("//td[text()='CREATE']"));
resultList.get(0).findElement(By.xpath("//td[text()='clients/" + id + "']"));
resultList.get(0).findElement(By.xpath("//td[text()='CLIENT']"));
adminEventsPage.table().reset();
adminEventsPage.table().filterForm().addOperationType("UPDATE");
@ -97,6 +98,7 @@ public class AdminEventsTest extends AbstractConsoleTest {
assertEquals(1, resultList.size());
resultList.get(0).findElement(By.xpath("//td[text()='UPDATE']"));
resultList.get(0).findElement(By.xpath("//td[text()='clients/" + id + "']"));
resultList.get(0).findElement(By.xpath("//td[text()='CLIENT']"));
adminEventsPage.table().reset();
adminEventsPage.table().filterForm().addOperationType("DELETE");
@ -106,6 +108,7 @@ public class AdminEventsTest extends AbstractConsoleTest {
assertEquals(1, resultList.size());
resultList.get(0).findElement(By.xpath("//td[text()='DELETE']"));
resultList.get(0).findElement(By.xpath("//td[text()='clients/" + id + "']"));
resultList.get(0).findElement(By.xpath("//td[text()='CLIENT']"));
}
public ClientsResource clientsResource() {

View file

@ -61,8 +61,9 @@
<auth.server.jboss.artifactId>integration-arquillian-servers-auth-server-${auth.server}</auth.server.jboss.artifactId>
<auth.server.jboss.skip.unpack>${auth.server.undertow}</auth.server.jboss.skip.unpack>
<auth.server.jboss.startup.timeout>300</auth.server.jboss.startup.timeout>
<auth.server.remote>false</auth.server.remote>
<auth.server.profile/>
<adapter.test.props/>
<migration.import.properties/>
@ -163,6 +164,8 @@
<auth.server.config.property.value>${auth.server.config.property.value}</auth.server.config.property.value>
<auth.server.adapter.impl.class>${auth.server.adapter.impl.class}</auth.server.adapter.impl.class>
<auth.server.profile>${auth.server.profile}</auth.server.profile>
<frontend.console.output>${frontend.console.output}</frontend.console.output>
<backends.console.output>${backend.console.output}</backends.console.output>
@ -246,6 +249,18 @@
</dependencies>
</profile>
<profile>
<id>auth-server-profile</id>
<activation>
<property>
<name>keycloak.profile</name>
</property>
</activation>
<properties>
<auth.server.profile>-Dkeycloak.profile=${keycloak.profile}</auth.server.profile>
</properties>
</profile>
<profile>
<id>auth-server-cluster</id>
<properties>
@ -412,74 +427,73 @@
<profile>
<id>auth-server-migration</id>
<properties>
<migration.import.file>src/test/resources/migration-test/migration-realm-${migrated.auth.server.version}.json</migration.import.file>
<migration.import.props.previous>
-Dkeycloak.migration.action=import
-Dkeycloak.migration.provider=singleFile
-Dkeycloak.migration.file=src/test/resources/migration-test/migration-realm-${migrated.auth.server.version}.json
-Dkeycloak.migration.file=${migration.import.file}
-Dkeycloak.migration.strategy=OVERWRITE_EXISTING
</migration.import.props.previous>
<skip.add.user.json>true</skip.add.user.json>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireProperty>
<property>migrated.auth.server.version</property>
</requireProperty>
<requireProperty>
<property>migration.mode</property>
</requireProperty>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack-migrated-auth-server-jboss</id>
<phase>generate-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.keycloak.testsuite</groupId>
<artifactId>integration-arquillian-migration-server</artifactId>
<version>${project.version}</version>
<type>zip</type>
</artifactItem>
</artifactItems>
<outputDirectory>${containers.home}</outputDirectory>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<migrated.auth.server.version>${migrated.auth.server.version}</migrated.auth.server.version>
<auth.server.jboss.migration>true</auth.server.jboss.migration>
<keycloak.migration.home>${containers.home}/keycloak-${migrated.auth.server.version}</keycloak.migration.home>
<migration.import.props.previous>${migration.import.props.previous}</migration.import.props.previous>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireProperty>
<property>migrated.auth.server.version</property>
</requireProperty>
<requireProperty>
<property>migration.mode</property>
</requireProperty>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack-migrated-auth-server-jboss</id>
<phase>generate-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.keycloak.testsuite</groupId>
<artifactId>integration-arquillian-migration-server</artifactId>
<version>${project.version}</version>
<type>zip</type>
</artifactItem>
</artifactItems>
<outputDirectory>${containers.home}</outputDirectory>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<migrated.auth.server.version>${migrated.auth.server.version}</migrated.auth.server.version>
<auth.server.jboss.migration>true</auth.server.jboss.migration>
<keycloak.migration.home>${containers.home}/keycloak-${migrated.auth.server.version}</keycloak.migration.home>
<migration.import.props.previous>${migration.import.props.previous}</migration.import.props.previous>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
@ -492,47 +506,58 @@
</property>
</activation>
<properties>
<migration.import.file>src/test/resources/migration-test/migration-realm-${migrated.auth.server.version}.json</migration.import.file>
<migration.import.properties>
-Dkeycloak.migration.action=import
-Dkeycloak.migration.provider=singleFile
-Dkeycloak.migration.file=src/test/resources/migration-test/migration-realm-${migrated.auth.server.version}.json
-Dkeycloak.migration.file=${migration.import.file}
-Dkeycloak.migration.strategy=OVERWRITE_EXISTING
</migration.import.properties>
<skip.add.user.json>true</skip.add.user.json>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireProperty>
<property>migrated.auth.server.version</property>
</requireProperty>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<migrated.auth.server.version>${migrated.auth.server.version}</migrated.auth.server.version>
<migration.import.properties>${migration.import.properties}</migration.import.properties>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireProperty>
<property>migrated.auth.server.version</property>
</requireProperty>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<migrated.auth.server.version>${migrated.auth.server.version}</migrated.auth.server.version>
<migration.import.properties>${migration.import.properties}</migration.import.properties>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>migration-productized</id>
<activation>
<property>
<name>migrated.version.import.file.suffix</name>
</property>
</activation>
<properties>
<migration.import.file>src/test/resources/migration-test/migration-realm-${migrated.version.import.file.suffix}.json</migration.import.file>
</properties>
</profile>
<profile>
<id>no-account</id>

View file

@ -956,7 +956,7 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
id: $scope.identityProvider.internalId
}, $scope.identityProvider, function () {
$route.reload();
Notifications.success("The " + $scope.identityProvider.alias + " provider has been update.");
Notifications.success("The " + $scope.identityProvider.alias + " provider has been updated.");
});
}
};

View file

@ -222,8 +222,11 @@
<input class="form-control" id="fromUrl" type="text" ng-model="fromUrl.data">
</div>
<kc-tooltip>{{:: 'identity-provider.import-from-url.tooltip' | translate}}</kc-tooltip>
<div class="col-md-6" data-ng-show="importUrl">
<button type="submit" data-ng-click="importFrom()" data-ng-show="importUrl" class="btn btn-primary">{{:: 'import' | translate}}</button>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="importFrom"></label>
<div class="col-md-6">
<button id="importFrom" type="button" data-ng-click="importFrom()" data-ng-show="importUrl" class="btn btn-primary">{{:: 'import' | translate}}</button>
</div>
</div>
<div class="form-group" data-ng-show="newIdentityProvider">
@ -238,8 +241,11 @@
{{files[0].name}}
</span>
</div>
<div class="col-md-6" data-ng-show="importFile">
<button type="submit" data-ng-click="uploadFile()" data-ng-show="importFile" class="btn btn-primary">{{:: 'import' | translate}}</button>
<div class="form-group">
<label class="col-md-2 control-label" for="importFile"></label>
<div class="col-md-6" data-ng-show="importFile">
<button id="importFile" type="button" data-ng-click="uploadFile()" data-ng-show="importFile" class="btn btn-primary">{{:: 'import' | translate}}</button>
</div>
</div>
</div>
</fieldset>

View file

@ -191,8 +191,11 @@
<input class="form-control" id="fromUrl" type="text" ng-model="fromUrl.data">
</div>
<kc-tooltip>{{:: 'saml.import-from-url.tooltip' | translate}}</kc-tooltip>
<div class="col-sm-4" data-ng-show="importUrl">
<button type="submit" data-ng-click="importFrom()" data-ng-show="importUrl" class="btn btn-primary">{{:: 'import' | translate}}</button>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="importFrom"></label>
<div class="col-md-6">
<button id="importFrom" type="button" data-ng-click="importFrom()" data-ng-show="importUrl" class="btn btn-primary">{{:: 'import' | translate}}</button>
</div>
</div>
<div class="form-group" data-ng-show="newIdentityProvider">
@ -206,8 +209,11 @@
{{files[0].name}}
</span>
</div>
<div class="col-sm-4" data-ng-show="importFile">
<button type="submit" data-ng-click="uploadFile()" data-ng-show="importFile" class="btn btn-primary">{{:: 'import' | translate}}</button>
<div class="form-group">
<label class="col-md-2 control-label" for="importFile"></label>
<div class="col-sm-6" data-ng-show="importFile">
<button id="importFile" type="button" data-ng-click="uploadFile()" data-ng-show="importFile" class="btn btn-primary">{{:: 'import' | translate}}</button>
</div>
</div>
</div>
</fieldset>

View file

@ -244,18 +244,26 @@ ol#kc-totp-settings li:first-of-type {
.zocial.microsoft {background-color: #0052a4; color: #fff;}
.zocial.microsoft:before { content: "\f15d"; }
@media (min-width: 1281px) {
#kc-container-wrapper {
bottom: 13%;
}
#kc-logo-wrapper {
position: absolute;
top: 50px;
right: 50px;
}
}
@media (min-width: 768px) {
#kc-container-wrapper {
bottom: 13%;
position: absolute;
width: 100%;
}
#kc-logo-wrapper {
position: absolute;
top: 50px;
right: 50px;
margin-left: auto;
}
.login-pf .container {