Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
fd212a2a2a
76 changed files with 1328 additions and 512 deletions
|
@ -41,7 +41,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -64,25 +64,25 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.as</groupId>
|
<groupId>org.jboss.as</groupId>
|
||||||
<artifactId>jboss-as-naming</artifactId>
|
<artifactId>jboss-as-naming</artifactId>
|
||||||
<version>${jboss.version}</version>
|
<version>${jboss.as.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.as</groupId>
|
<groupId>org.jboss.as</groupId>
|
||||||
<artifactId>jboss-as-server</artifactId>
|
<artifactId>jboss-as-server</artifactId>
|
||||||
<version>${jboss.version}</version>
|
<version>${jboss.as.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.as</groupId>
|
<groupId>org.jboss.as</groupId>
|
||||||
<artifactId>jboss-as-ee</artifactId>
|
<artifactId>jboss-as-ee</artifactId>
|
||||||
<version>${jboss.version}</version>
|
<version>${jboss.as.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.as</groupId>
|
<groupId>org.jboss.as</groupId>
|
||||||
<artifactId>jboss-as-web</artifactId>
|
<artifactId>jboss-as-web</artifactId>
|
||||||
<version>${jboss.version}</version>
|
<version>${jboss.as.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -236,7 +236,7 @@
|
||||||
kc.createLogoutUrl = function(options) {
|
kc.createLogoutUrl = function(options) {
|
||||||
var url = getRealmUrl()
|
var url = getRealmUrl()
|
||||||
+ '/protocol/openid-connect/logout'
|
+ '/protocol/openid-connect/logout'
|
||||||
+ '?redirect_uri=' + encodeURIComponent(adapter.redirectUri(options));
|
+ '?redirect_uri=' + encodeURIComponent(adapter.redirectUri(options, false));
|
||||||
|
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
@ -842,14 +842,18 @@
|
||||||
return createPromise().promise;
|
return createPromise().promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
redirectUri: function(options) {
|
redirectUri: function(options, encodeHash) {
|
||||||
|
if (arguments.length == 1) {
|
||||||
|
encodeHash = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (options && options.redirectUri) {
|
if (options && options.redirectUri) {
|
||||||
return options.redirectUri;
|
return options.redirectUri;
|
||||||
} else if (kc.redirectUri) {
|
} else if (kc.redirectUri) {
|
||||||
return kc.redirectUri;
|
return kc.redirectUri;
|
||||||
} else {
|
} else {
|
||||||
var redirectUri = location.href;
|
var redirectUri = location.href;
|
||||||
if (location.hash) {
|
if (location.hash && encodeHash) {
|
||||||
redirectUri = redirectUri.substring(0, location.href.indexOf('#'));
|
redirectUri = redirectUri.substring(0, location.href.indexOf('#'));
|
||||||
redirectUri += (redirectUri.indexOf('?') == -1 ? '?' : '&') + 'redirect_fragment=' + encodeURIComponent(location.hash.substring(1));
|
redirectUri += (redirectUri.indexOf('?') == -1 ? '?' : '&') + 'redirect_fragment=' + encodeURIComponent(location.hash.substring(1));
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -41,7 +41,6 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-core</artifactId>
|
<artifactId>keycloak-core</artifactId>
|
||||||
<version>${project.version}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
|
@ -50,11 +49,10 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-adapter-core</artifactId>
|
<artifactId>keycloak-adapter-core</artifactId>
|
||||||
<version>${project.version}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -82,7 +80,6 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.bouncycastle</groupId>
|
<groupId>org.bouncycastle</groupId>
|
||||||
<artifactId>bcprov-jdk15on</artifactId>
|
<artifactId>bcprov-jdk15on</artifactId>
|
||||||
<version>${bouncycastle.crypto.version}</version>
|
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -75,7 +75,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
|
@ -79,21 +79,15 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.logging</groupId>
|
<groupId>org.jboss.logging</groupId>
|
||||||
<artifactId>jboss-logging-annotations</artifactId>
|
<artifactId>jboss-logging-annotations</artifactId>
|
||||||
<version>${jboss-logging-tools.version}</version>
|
<version>${jboss.logging.tools.wf8.version}</version>
|
||||||
<!-- This is a compile-time dependency of this project, but is not needed at compile or runtime by other
|
|
||||||
projects that depend on this project.-->
|
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.logging</groupId>
|
<groupId>org.jboss.logging</groupId>
|
||||||
<artifactId>jboss-logging-processor</artifactId>
|
<artifactId>jboss-logging-processor</artifactId>
|
||||||
<version>${jboss-logging-tools.version}</version>
|
<version>${jboss.logging.tools.wf8.version}</version>
|
||||||
<!-- This is a compile-time dependency of this project, but is not needed at compile or runtime by other
|
|
||||||
projects that depend on this project.-->
|
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -89,7 +89,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -64,25 +64,25 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.as</groupId>
|
<groupId>org.jboss.as</groupId>
|
||||||
<artifactId>jboss-as-naming</artifactId>
|
<artifactId>jboss-as-naming</artifactId>
|
||||||
<version>${jboss.version}</version>
|
<version>${jboss.as.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.as</groupId>
|
<groupId>org.jboss.as</groupId>
|
||||||
<artifactId>jboss-as-server</artifactId>
|
<artifactId>jboss-as-server</artifactId>
|
||||||
<version>${jboss.version}</version>
|
<version>${jboss.as.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.as</groupId>
|
<groupId>org.jboss.as</groupId>
|
||||||
<artifactId>jboss-as-ee</artifactId>
|
<artifactId>jboss-as-ee</artifactId>
|
||||||
<version>${jboss.version}</version>
|
<version>${jboss.as.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.as</groupId>
|
<groupId>org.jboss.as</groupId>
|
||||||
<artifactId>jboss-as-web</artifactId>
|
<artifactId>jboss-as-web</artifactId>
|
||||||
<version>${jboss.version}</version>
|
<version>${jboss.as.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -104,7 +104,7 @@ projects that depend on this project.-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.as</groupId>
|
<groupId>org.jboss.as</groupId>
|
||||||
<artifactId>jboss-as-controller</artifactId>
|
<artifactId>jboss-as-controller</artifactId>
|
||||||
<version>${jboss.version}</version>
|
<version>${jboss.as.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -69,7 +69,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -69,7 +69,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.keycloak.adapters.spi.KeycloakAccount;
|
||||||
import org.keycloak.common.util.Encode;
|
import org.keycloak.common.util.Encode;
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
|
|
||||||
|
import javax.servlet.ReadListener;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletInputStream;
|
import javax.servlet.ServletInputStream;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
@ -173,11 +174,54 @@ public class FilterSessionStore implements AdapterSessionStore {
|
||||||
public ServletInputStream getInputStream() throws IOException {
|
public ServletInputStream getInputStream() throws IOException {
|
||||||
|
|
||||||
if (needRequestRestore && body != null) {
|
if (needRequestRestore && body != null) {
|
||||||
final ByteArrayInputStream is = new ByteArrayInputStream(body);
|
|
||||||
return new ServletInputStream() {
|
return new ServletInputStream() {
|
||||||
|
private int lastIndex = 0;
|
||||||
|
private ReadListener readListener = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFinished() {
|
||||||
|
return lastIndex == body.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReady() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setReadListener(ReadListener readListener) {
|
||||||
|
this.readListener = readListener;
|
||||||
|
if (!isFinished()) {
|
||||||
|
try {
|
||||||
|
readListener.onDataAvailable();
|
||||||
|
} catch (IOException e) {
|
||||||
|
readListener.onError(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
readListener.onAllDataRead();
|
||||||
|
} catch (IOException e) {
|
||||||
|
readListener.onError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read() throws IOException {
|
public int read() throws IOException {
|
||||||
return is.read();
|
int i = -1;
|
||||||
|
if (!isFinished()) {
|
||||||
|
i = body[lastIndex];
|
||||||
|
lastIndex++;
|
||||||
|
if (isFinished() && readListener != null) {
|
||||||
|
try {
|
||||||
|
readListener.onAllDataRead();
|
||||||
|
} catch (IOException e) {
|
||||||
|
readListener.onError(e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -107,6 +107,12 @@
|
||||||
(via the subsystem, or auth-method in web.xml
|
(via the subsystem, or auth-method in web.xml
|
||||||
</para>
|
</para>
|
||||||
</simplesect>
|
</simplesect>
|
||||||
|
<simplesect>
|
||||||
|
<title>Client Registration service endpoints moved</title>
|
||||||
|
<para>
|
||||||
|
The Client Registration service endpoints have been moved from <literal>{realm}/clients</literal> to <literal>{realm}/clients-registrations</literal>.
|
||||||
|
</para>
|
||||||
|
</simplesect>
|
||||||
<simplesect>
|
<simplesect>
|
||||||
<title>Deprecated OpenID Connect endpoints</title>
|
<title>Deprecated OpenID Connect endpoints</title>
|
||||||
<para>
|
<para>
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
<para>
|
<para>
|
||||||
The Client Registration Service provides built-in support for Keycloak Client Representations, OpenID Connect
|
The Client Registration Service provides built-in support for Keycloak Client Representations, OpenID Connect
|
||||||
Client Meta Data and SAML Entity Descriptors. It's also possible to plugin custom client registration providers
|
Client Meta Data and SAML Entity Descriptors. It's also possible to plugin custom client registration providers
|
||||||
if required. The Client Registration Service endpoint is <literal><KEYCLOAK URL>/realms/<realm>/clients/<provider></literal>.
|
if required. The Client Registration Service endpoint is <literal><KEYCLOAK URL>/realms/<realm>/clients-registrations/<provider></literal>.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The built-in supported <literal>providers</literal> are:
|
The built-in supported <literal>providers</literal> are:
|
||||||
|
@ -123,23 +123,23 @@ Authorization: bearer eyJhbGciOiJSUzI1NiJ9.eyJqdGkiOiJmMjJmNzQyYy04ZjNlLTQ2M....
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
To create a client create a Client Representation (JSON) then do a HTTP POST to:
|
To create a client create a Client Representation (JSON) then do a HTTP POST to:
|
||||||
<literal><KEYCLOAK URL>/realms/<realm>/clients/default</literal>. It will return a Client Representation
|
<literal><KEYCLOAK URL>/realms/<realm>/clients-registrations/default</literal>. It will return a Client Representation
|
||||||
that also includes the registration access token. You should save the registration access token somewhere
|
that also includes the registration access token. You should save the registration access token somewhere
|
||||||
if you want to retrieve the config, update or delete the client later.
|
if you want to retrieve the config, update or delete the client later.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
To retrieve the Client Representation then do a HTTP GET to:
|
To retrieve the Client Representation then do a HTTP GET to:
|
||||||
<literal><KEYCLOAK URL>/realms/<realm>/clients/default/<client id></literal>. It will also
|
<literal><KEYCLOAK URL>/realms/<realm>/clients-registrations/default/<client id></literal>. It will also
|
||||||
return a new registration access token.
|
return a new registration access token.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
To update the Client Representation then do a HTTP PUT to with the updated Client Representation to:
|
To update the Client Representation then do a HTTP PUT to with the updated Client Representation to:
|
||||||
<literal><KEYCLOAK URL>/realms/<realm>/clients/default/<client id></literal>. It will also
|
<literal><KEYCLOAK URL>/realms/<realm>/clients-registrations/default/<client id></literal>. It will also
|
||||||
return a new registration access token.
|
return a new registration access token.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
To delete the Client Representation then do a HTTP DELETE to:
|
To delete the Client Representation then do a HTTP DELETE to:
|
||||||
<literal><KEYCLOAK URL>/realms/<realm>/clients/default/<client id></literal>
|
<literal><KEYCLOAK URL>/realms/<realm>/clients-registrations/default/<client id></literal>
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ Authorization: basic BASE64(client-id + ':' + client-secret)
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
To retrieve the Adapter Configuration then do a HTTP GET to:
|
To retrieve the Adapter Configuration then do a HTTP GET to:
|
||||||
<literal><KEYCLOAK URL>//realms/<realm>/clients/installation/<client id></literal>
|
<literal><KEYCLOAK URL>//realms/<realm>/clients-registrations/installation/<client id></literal>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
No authentication is required for public clients. This means that for the JavaScript adapter you can
|
No authentication is required for public clients. This means that for the JavaScript adapter you can
|
||||||
|
@ -172,7 +172,7 @@ Authorization: basic BASE64(client-id + ':' + client-secret)
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The endpoint to use these specifications to register clients in Keycloak is:
|
The endpoint to use these specifications to register clients in Keycloak is:
|
||||||
<literal><KEYCLOAK URL>/realms/<realm>/clients/oidc[/<client id>]</literal>.
|
<literal><KEYCLOAK URL>/realms/<realm>/clients-registrations/oidc[/<client id>]</literal>.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
This endpoints can also be found in the OpenID Connect Discovery endpoint for the realm:
|
This endpoints can also be found in the OpenID Connect Discovery endpoint for the realm:
|
||||||
|
@ -190,7 +190,7 @@ Authorization: basic BASE64(client-id + ':' + client-secret)
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
To create a client do a HTTP POST with the SAML Entity Descriptor to:
|
To create a client do a HTTP POST with the SAML Entity Descriptor to:
|
||||||
<literal><KEYCLOAK URL>/realms/<realm>/clients/saml2-entity-descriptor</literal>.
|
<literal><KEYCLOAK URL>/realms/<realm>/clients-registrations/saml2-entity-descriptor</literal>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -34,8 +34,7 @@
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<version>1.0.1.Final</version>
|
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
3
examples/demo-template/third-party/pom.xml
vendored
3
examples/demo-template/third-party/pom.xml
vendored
|
@ -34,8 +34,7 @@
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<version>1.0.1.Final</version>
|
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -177,7 +177,7 @@ public class ClientRegistration {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientRegistrationBuilder url(String authUrl, String realm) {
|
public ClientRegistrationBuilder url(String authUrl, String realm) {
|
||||||
url = HttpUtil.getUrl(authUrl, "realms", realm, "clients");
|
url = HttpUtil.getUrl(authUrl, "realms", realm, "clients-registrations");
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate.javax.persistence</groupId>
|
<groupId>org.hibernate.javax.persistence</groupId>
|
||||||
<artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
|
<artifactId>hibernate-jpa-2.1-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate</groupId>
|
<groupId>org.hibernate</groupId>
|
||||||
|
|
115
pom.xml
115
pom.xml
|
@ -40,71 +40,74 @@
|
||||||
<product.version>${project.version}</product.version>
|
<product.version>${project.version}</product.version>
|
||||||
<product.build-time>${timestamp}</product.build-time>
|
<product.build-time>${timestamp}</product.build-time>
|
||||||
|
|
||||||
<apacheds.version>2.0.0-M17</apacheds.version>
|
<!-- WildFly -->
|
||||||
<apacheds.codec.version>1.0.0-M23</apacheds.codec.version>
|
<eap.version>7.0.0.Beta</eap.version>
|
||||||
<org.apache.james.apache-mime4j.version>0.6</org.apache.james.apache-mime4j.version>
|
<jboss.as.version>7.2.0.Final</jboss.as.version>
|
||||||
<bouncycastle.crypto.version>1.52</bouncycastle.crypto.version>
|
<wildfly.version>10.0.0.Final</wildfly.version>
|
||||||
|
|
||||||
|
<aesh.version>0.66.4</aesh.version>
|
||||||
|
<apache.httpcomponents.version>4.5</apache.httpcomponents.version>
|
||||||
|
<apache.httpcomponents.httpcore.version>4.4.1</apache.httpcomponents.httpcore.version>
|
||||||
|
<apache.mime4j.version>0.6</apache.mime4j.version>
|
||||||
|
<bouncycastle.version>1.52</bouncycastle.version>
|
||||||
|
<dom4j.version>1.6.1</dom4j.version>
|
||||||
|
<github.relaxng.version>2011.1</github.relaxng.version>
|
||||||
|
<h2.version>1.3.173</h2.version>
|
||||||
|
<hibernate.entitymanager.version>5.0.7.Final</hibernate.entitymanager.version>
|
||||||
|
<hibernate.javax.persistence.version>1.0.0.Final</hibernate.javax.persistence.version>
|
||||||
|
<infinispan.version>8.1.0.Final</infinispan.version>
|
||||||
<jackson.version>2.5.4</jackson.version>
|
<jackson.version>2.5.4</jackson.version>
|
||||||
<apache.httpcomponents.version>4.3.6</apache.httpcomponents.version>
|
<javax.mail.version>1.5.5</javax.mail.version>
|
||||||
<apache.httpcomponents.httpcore.version>4.3.3</apache.httpcomponents.httpcore.version>
|
|
||||||
<resteasy.version>3.0.14.Final</resteasy.version>
|
|
||||||
<keycloak.apache.httpcomponents.version>4.2.1</keycloak.apache.httpcomponents.version>
|
|
||||||
<undertow.version>1.3.10.Final</undertow.version>
|
|
||||||
<picketlink.version>2.7.0.Final</picketlink.version>
|
|
||||||
<mongo.driver.version>3.2.0</mongo.driver.version>
|
|
||||||
<jboss.logging.version>3.3.0.Final</jboss.logging.version>
|
<jboss.logging.version>3.3.0.Final</jboss.logging.version>
|
||||||
<jboss.logging.tools.version>2.0.1.Final</jboss.logging.tools.version>
|
<jboss.logging.tools.version>2.0.1.Final</jboss.logging.tools.version>
|
||||||
<jboss-logging-tools.version>1.2.0.Beta1</jboss-logging-tools.version>
|
<jboss.logging.tools.wf8.version>1.2.0.Final</jboss.logging.tools.wf8.version>
|
||||||
<jboss.spec.javax.xml.bind.jboss-jaxb-api_2.2_spec.version>1.0.4.Final</jboss.spec.javax.xml.bind.jboss-jaxb-api_2.2_spec.version>
|
|
||||||
<jboss-jaxrs-api_2.0_spec>1.0.0.Final</jboss-jaxrs-api_2.0_spec>
|
<jboss-jaxrs-api_2.0_spec>1.0.0.Final</jboss-jaxrs-api_2.0_spec>
|
||||||
<hibernate.javax.persistence.version>1.0.0.Final</hibernate.javax.persistence.version>
|
<jboss.spec.javax.xml.bind.jboss-jaxb-api_2.2_spec.version>1.0.4.Final</jboss.spec.javax.xml.bind.jboss-jaxb-api_2.2_spec.version>
|
||||||
<hibernate.javax.persistence.artifactId>hibernate-jpa-2.1-api</hibernate.javax.persistence.artifactId>
|
<log4j.version>1.2.16</log4j.version>
|
||||||
<hibernate.entitymanager.version>4.3.10.Final</hibernate.entitymanager.version>
|
<resteasy.version>3.0.14.Final</resteasy.version>
|
||||||
<h2.version>1.3.173</h2.version>
|
<servlet.api.31.version>1.0.0.Final</servlet.api.31.version>
|
||||||
<mysql.version>5.1.29</mysql.version>
|
|
||||||
<postgresql.version>9.3-1100-jdbc41</postgresql.version>
|
|
||||||
<dom4j.version>1.6.1</dom4j.version>
|
|
||||||
<xml-apis.version>1.4.01</xml-apis.version>
|
|
||||||
<slf4j.version>1.7.7</slf4j.version>
|
<slf4j.version>1.7.7</slf4j.version>
|
||||||
<wildfly.version>10.0.0.Final</wildfly.version>
|
|
||||||
<wildfly.core.version>2.0.10.Final</wildfly.core.version>
|
|
||||||
<wildfly.build-tools.version>1.1.0.Final</wildfly.build-tools.version>
|
|
||||||
|
|
||||||
<eap.version>7.0.0.Beta</eap.version>
|
|
||||||
|
|
||||||
<jboss.version>7.2.0.Final</jboss.version>
|
|
||||||
|
|
||||||
<servlet.api.30.version>1.0.2.Final</servlet.api.30.version>
|
|
||||||
<google.zxing.version>3.2.1</google.zxing.version>
|
|
||||||
<github.relaxng.version>2011.1</github.relaxng.version>
|
|
||||||
<freemarker.version>2.3.23</freemarker.version>
|
|
||||||
<twitter4j.version>4.0.4</twitter4j.version>
|
|
||||||
<selenium.version>2.35.0</selenium.version>
|
|
||||||
<sun.istack.version>2.21</sun.istack.version>
|
<sun.istack.version>2.21</sun.istack.version>
|
||||||
<sun.jaxb.version>2.2.11</sun.jaxb.version>
|
<sun.jaxb.version>2.2.11</sun.jaxb.version>
|
||||||
<sun.xsom.version>20140925</sun.xsom.version>
|
<sun.xsom.version>20140925</sun.xsom.version>
|
||||||
<javax.mail.version>1.4.5</javax.mail.version>
|
<undertow.version>1.3.15.Final</undertow.version>
|
||||||
<infinispan.version>8.1.0.Final</infinispan.version>
|
<wildfly.core.version>2.0.10.Final</wildfly.core.version>
|
||||||
<liquibase.version>3.4.1</liquibase.version>
|
<wildfly.build-tools.version>1.1.0.Final</wildfly.build-tools.version>
|
||||||
|
<!--<xmlsec.version>2.0.5</xmlsec.version>--> <!-- WILDFLY VERSION -->
|
||||||
|
<xmlsec.version>1.5.1</xmlsec.version>
|
||||||
|
|
||||||
|
<!-- Others -->
|
||||||
|
<apacheds.version>2.0.0-M17</apacheds.version>
|
||||||
|
<apacheds.codec.version>1.0.0-M23</apacheds.codec.version>
|
||||||
|
<google.zxing.version>3.2.1</google.zxing.version>
|
||||||
|
<freemarker.version>2.3.23</freemarker.version>
|
||||||
<jetty9.version>9.1.0.v20131115</jetty9.version>
|
<jetty9.version>9.1.0.v20131115</jetty9.version>
|
||||||
|
<liquibase.version>3.4.1</liquibase.version>
|
||||||
|
<mongo.driver.version>3.2.0</mongo.driver.version>
|
||||||
|
<mysql.version>5.1.29</mysql.version>
|
||||||
<osgi.version>4.2.0</osgi.version>
|
<osgi.version>4.2.0</osgi.version>
|
||||||
<pax.web.version>3.1.2</pax.web.version>
|
<pax.web.version>3.1.2</pax.web.version>
|
||||||
|
<postgresql.version>9.3-1100-jdbc41</postgresql.version>
|
||||||
|
<twitter4j.version>4.0.4</twitter4j.version>
|
||||||
|
|
||||||
|
<!-- Test -->
|
||||||
|
<greenmail.version>1.3.1b</greenmail.version>
|
||||||
|
<hamcrest.version>1.3</hamcrest.version>
|
||||||
<jmeter.version>2.10</jmeter.version>
|
<jmeter.version>2.10</jmeter.version>
|
||||||
<junit.version>4.12</junit.version>
|
<junit.version>4.12</junit.version>
|
||||||
<hamcrest.version>1.3</hamcrest.version>
|
<picketlink.version>2.7.0.Final</picketlink.version>
|
||||||
<log4j.version>1.2.17</log4j.version>
|
<selenium.version>2.35.0</selenium.version>
|
||||||
<greenmail.version>1.3.1b</greenmail.version>
|
<xml-apis.version>1.4.01</xml-apis.version>
|
||||||
<xmlsec.version>1.5.1</xmlsec.version>
|
|
||||||
<aesh.version>0.66.4</aesh.version>
|
|
||||||
|
|
||||||
|
<!-- Maven Plugins -->
|
||||||
|
<embedmongo.plugin.version>0.1.12</embedmongo.plugin.version>
|
||||||
<enforcer.plugin.version>1.4</enforcer.plugin.version>
|
<enforcer.plugin.version>1.4</enforcer.plugin.version>
|
||||||
<jboss.as.plugin.version>7.5.Final</jboss.as.plugin.version>
|
<jboss.as.plugin.version>7.5.Final</jboss.as.plugin.version>
|
||||||
<wildfly.plugin.version>1.0.1.Final</wildfly.plugin.version>
|
|
||||||
<minify.plugin.version>1.7.2</minify.plugin.version>
|
|
||||||
<embedmongo.plugin.version>0.1.12</embedmongo.plugin.version>
|
|
||||||
<jmeter.plugin.version>1.9.0</jmeter.plugin.version>
|
<jmeter.plugin.version>1.9.0</jmeter.plugin.version>
|
||||||
<jmeter.analysis.plugin.version>1.0.4</jmeter.analysis.plugin.version>
|
<jmeter.analysis.plugin.version>1.0.4</jmeter.analysis.plugin.version>
|
||||||
|
<minify.plugin.version>1.7.2</minify.plugin.version>
|
||||||
<osgi.bundle.plugin.version>2.3.7</osgi.bundle.plugin.version>
|
<osgi.bundle.plugin.version>2.3.7</osgi.bundle.plugin.version>
|
||||||
|
<wildfly.plugin.version>1.0.1.Final</wildfly.plugin.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<url>http://keycloak.org</url>
|
<url>http://keycloak.org</url>
|
||||||
|
@ -201,16 +204,16 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.bouncycastle</groupId>
|
<groupId>org.bouncycastle</groupId>
|
||||||
<artifactId>bcprov-jdk15on</artifactId>
|
<artifactId>bcprov-jdk15on</artifactId>
|
||||||
<version>${bouncycastle.crypto.version}</version>
|
<version>${bouncycastle.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.bouncycastle</groupId>
|
<groupId>org.bouncycastle</groupId>
|
||||||
<artifactId>bcpkix-jdk15on</artifactId>
|
<artifactId>bcpkix-jdk15on</artifactId>
|
||||||
<version>${bouncycastle.crypto.version}</version>
|
<version>${bouncycastle.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.mail</groupId>
|
<groupId>javax.mail</groupId>
|
||||||
<artifactId>mail</artifactId>
|
<artifactId>javax.mail-api</artifactId>
|
||||||
<version>${javax.mail.version}</version>
|
<version>${javax.mail.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -300,8 +303,8 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
<version>${servlet.api.30.version}</version>
|
<version>${servlet.api.31.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.picketlink</groupId>
|
<groupId>org.picketlink</groupId>
|
||||||
|
@ -343,7 +346,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate.javax.persistence</groupId>
|
<groupId>org.hibernate.javax.persistence</groupId>
|
||||||
<artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
|
<artifactId>hibernate-jpa-2.1-api</artifactId>
|
||||||
<version>${hibernate.javax.persistence.version}</version>
|
<version>${hibernate.javax.persistence.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -508,7 +511,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.james</groupId>
|
<groupId>org.apache.james</groupId>
|
||||||
<artifactId>apache-mime4j</artifactId>
|
<artifactId>apache-mime4j</artifactId>
|
||||||
<version>${org.apache.james.apache-mime4j.version}</version>
|
<version>${apache.mime4j.version}</version>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>commons-logging</groupId>
|
<groupId>commons-logging</groupId>
|
||||||
|
@ -584,12 +587,6 @@
|
||||||
<artifactId>wildfly-web-common</artifactId>
|
<artifactId>wildfly-web-common</artifactId>
|
||||||
<version>${wildfly.version}</version>
|
<version>${wildfly.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.jboss.logging</groupId>
|
|
||||||
<artifactId>jboss-logging-processor</artifactId>
|
|
||||||
<version>${jboss-logging-tools.version}</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.infinispan</groupId>
|
<groupId>org.infinispan</groupId>
|
||||||
<artifactId>infinispan-core</artifactId>
|
<artifactId>infinispan-core</artifactId>
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.mail</groupId>
|
<groupId>javax.mail</groupId>
|
||||||
<artifactId>mail</artifactId>
|
<artifactId>javax.mail-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
|
@ -63,7 +63,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.twitter4j</groupId>
|
<groupId>org.twitter4j</groupId>
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
|
|
||||||
package org.keycloak.services.clientregistration;
|
package org.keycloak.services.clientregistration;
|
||||||
|
|
||||||
import org.jboss.resteasy.spi.NotFoundException;
|
|
||||||
import org.keycloak.events.EventBuilder;
|
import org.keycloak.events.EventBuilder;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.services.ErrorResponseException;
|
import org.keycloak.services.ErrorResponseException;
|
||||||
|
|
||||||
|
import javax.ws.rs.NotFoundException;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.jboss.resteasy.spi.HttpRequest;
|
||||||
import org.keycloak.AbstractOAuthClient;
|
import org.keycloak.AbstractOAuthClient;
|
||||||
import org.keycloak.common.ClientConnection;
|
import org.keycloak.common.ClientConnection;
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
|
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
@ -113,13 +114,15 @@ public abstract class AbstractSecuredLocalService {
|
||||||
throw new BadRequestException("state not specified");
|
throw new BadRequestException("state not specified");
|
||||||
}
|
}
|
||||||
|
|
||||||
URI uri = getBaseRedirectUri();
|
KeycloakUriBuilder redirect = KeycloakUriBuilder.fromUri(getBaseRedirectUri());
|
||||||
URI redirectUri = path != null ? uri.resolve(path) : uri;
|
if (path != null) {
|
||||||
|
redirect.path(path);
|
||||||
|
}
|
||||||
if (referrer != null) {
|
if (referrer != null) {
|
||||||
redirectUri = redirectUri.resolve("?referrer=" + referrer);
|
redirect.queryParam("referrer", referrer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Response.status(302).location(redirectUri).build();
|
return Response.status(302).location(redirect.build()).build();
|
||||||
} finally {
|
} finally {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,23 +84,6 @@ public class RealmsResource {
|
||||||
return uriInfo.getBaseUriBuilder().path(RealmsResource.class).path(RealmsResource.class, "getBrokerService");
|
return uriInfo.getBaseUriBuilder().path(RealmsResource.class).path(RealmsResource.class, "getBrokerService");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("{realm}/login-status-iframe.html")
|
|
||||||
@Deprecated
|
|
||||||
public Object getLoginStatusIframe(final @PathParam("realm") String name,
|
|
||||||
@QueryParam("client_id") String client_id,
|
|
||||||
@QueryParam("origin") String origin) {
|
|
||||||
RealmModel realm = init(name);
|
|
||||||
|
|
||||||
EventBuilder event = new EventBuilder(realm, session, clientConnection);
|
|
||||||
|
|
||||||
LoginProtocolFactory factory = (LoginProtocolFactory)session.getKeycloakSessionFactory().getProviderFactory(LoginProtocol.class, OIDCLoginProtocol.LOGIN_PROTOCOL);
|
|
||||||
OIDCLoginProtocolService endpoint = (OIDCLoginProtocolService)factory.createProtocolEndpoint(realm, event);
|
|
||||||
|
|
||||||
ResteasyProviderFactory.getInstance().injectProperties(endpoint);
|
|
||||||
return endpoint.getLoginStatusIframe();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Path("{realm}/protocol/{protocol}")
|
@Path("{realm}/protocol/{protocol}")
|
||||||
public Object getProtocol(final @PathParam("realm") String name,
|
public Object getProtocol(final @PathParam("realm") String name,
|
||||||
final @PathParam("protocol") String protocol) {
|
final @PathParam("protocol") String protocol) {
|
||||||
|
@ -115,13 +98,6 @@ public class RealmsResource {
|
||||||
return endpoint;
|
return endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("{realm}/tokens")
|
|
||||||
@Deprecated
|
|
||||||
public Object getTokenService(final @PathParam("realm") String name) {
|
|
||||||
// for backward compatibility.
|
|
||||||
return getProtocol(name, "openid-connect");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Path("{realm}/login-actions")
|
@Path("{realm}/login-actions")
|
||||||
public LoginActionsService getLoginActionsService(final @PathParam("realm") String name) {
|
public LoginActionsService getLoginActionsService(final @PathParam("realm") String name) {
|
||||||
RealmModel realm = init(name);
|
RealmModel realm = init(name);
|
||||||
|
@ -131,7 +107,7 @@ public class RealmsResource {
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("{realm}/clients")
|
@Path("{realm}/clients-registrations")
|
||||||
public ClientRegistrationService getClientsService(final @PathParam("realm") String name) {
|
public ClientRegistrationService getClientsService(final @PathParam("realm") String name) {
|
||||||
RealmModel realm = init(name);
|
RealmModel realm = init(name);
|
||||||
EventBuilder event = new EventBuilder(realm, session, clientConnection);
|
EventBuilder event = new EventBuilder(realm, session, clientConnection);
|
||||||
|
|
|
@ -13,17 +13,28 @@ other options are: `auth-server-wildfly` and `auth-server-eap7`. The values corr
|
||||||
**Note 1:** For the non-default options it's necessary to build a corresponding server module prior to running any of the test modules.
|
**Note 1:** For the non-default options it's necessary to build a corresponding server module prior to running any of the test modules.
|
||||||
This can be done by building the server module directly (from `servers/wildfly`/`servers/eap7`),
|
This can be done by building the server module directly (from `servers/wildfly`/`servers/eap7`),
|
||||||
or by activating `auth-server-wildfly`/`auth-server-eap7` profile when building from the top level module.
|
or by activating `auth-server-wildfly`/`auth-server-eap7` profile when building from the top level module.
|
||||||
(The profiles will also set the proper value of the `auth.server.container` property.)
|
|
||||||
|
|
||||||
**Note 2:** Most server-side configurations are done during the build of the server module
|
**Note 2:** Most server-side configurations are done during the build of the server module
|
||||||
and included in the output artifact - which is then consumed by the test modules( if a corresponding profile is activated).
|
and included in the output artifact - which is then consumed by the test modules( if a corresponding profile is activated).
|
||||||
To reflect a change in server config in the test (e.g. a datasource) it's necessary to rebuild the server module after each change.
|
To reflect a change in server config in the test (e.g. a datasource) it's necessary to rebuild the server module after each change.
|
||||||
|
|
||||||
### Migration
|
#### Migration
|
||||||
|
|
||||||
Migration tests can be enabled by setting `-Dmigrated.auth.server.container` property or activating a corresponding profile.
|
Migration tests can be enabled by setting `-Dmigrated.auth.server.version` property. Supported versions can be found at the bottom of `tests/pom.xml`.
|
||||||
When enabled, the `AuthServerTestEnricher` class will start/stop the selected *migrated* instance
|
When enabled, the `AuthServerTestEnricher` class will start and stop the selected migrated instance
|
||||||
even **before** the *current* auth server instance is started.
|
*before* the current auth server instance is started.
|
||||||
|
|
||||||
|
#### Cluster Setup
|
||||||
|
|
||||||
|
Cluster setup can be enabled with profile `auth-server-wildfly-cluster`.
|
||||||
|
(It is also necessary to build the server modules with this profile before running the test. See *Notes 1 and 2* above.)
|
||||||
|
|
||||||
|
Clustering tests require MULTICAST to be enabled on machine's `loopback` network interface.
|
||||||
|
This can be done by running the following commands under root privileges:
|
||||||
|
```
|
||||||
|
route add -net 224.0.0.0 netmask 240.0.0.0 dev lo
|
||||||
|
ifconfig lo multicast
|
||||||
|
```
|
||||||
|
|
||||||
### App Servers
|
### App Servers
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,15 @@ package org.keycloak.testsuite.cluster;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.jboss.arquillian.container.test.api.ContainerController;
|
import org.jboss.arquillian.container.test.api.ContainerController;
|
||||||
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
import org.jboss.arquillian.test.api.ArquillianResource;
|
import org.jboss.arquillian.test.api.ArquillianResource;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import org.keycloak.admin.client.Keycloak;
|
import org.keycloak.admin.client.Keycloak;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.testsuite.AbstractKeycloakTest;
|
import org.keycloak.testsuite.AbstractKeycloakTest;
|
||||||
import org.keycloak.testsuite.arquillian.ContainerInfo;
|
import org.keycloak.testsuite.arquillian.ContainerInfo;
|
||||||
|
import org.keycloak.testsuite.auth.page.AuthRealm;
|
||||||
import static org.keycloak.testsuite.auth.page.AuthRealm.ADMIN;
|
import static org.keycloak.testsuite.auth.page.AuthRealm.ADMIN;
|
||||||
import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
|
import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
|
||||||
|
|
||||||
|
@ -35,25 +38,38 @@ public abstract class AbstractClusterTest extends AbstractKeycloakTest {
|
||||||
controller.start(backendNode.getQualifier());
|
controller.start(backendNode.getQualifier());
|
||||||
assertTrue(controller.isStarted(backendNode.getQualifier()));
|
assertTrue(controller.isStarted(backendNode.getQualifier()));
|
||||||
|
|
||||||
log.info("Initializing admin client for: '" + backendNode.getContextRoot() + "/auth'");
|
backendAdminClients.add(createAdminClientFor(backendNode));
|
||||||
backendAdminClients.add(Keycloak.getInstance(backendNode.getContextRoot() + "/auth",
|
|
||||||
MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ContainerInfo backendInfo(int i) {
|
protected Keycloak createAdminClientFor(ContainerInfo backendNode) {
|
||||||
|
log.info("Initializing admin client for " + backendNode.getContextRoot() + "/auth");
|
||||||
|
return Keycloak.getInstance(backendNode.getContextRoot() + "/auth",
|
||||||
|
MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ContainerInfo backendNode(int i) {
|
||||||
return suiteContext.getAuthServerBackendsInfo().get(i);
|
return suiteContext.getAuthServerBackendsInfo().get(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void startBackendNode(int i) {
|
protected void startBackendNode(int i) {
|
||||||
String container = backendInfo(i).getQualifier();
|
String container = backendNode(i).getQualifier();
|
||||||
if (!controller.isStarted(container)) {
|
if (!controller.isStarted(container)) {
|
||||||
controller.start(container);
|
controller.start(container);
|
||||||
|
backendAdminClients.set(i, createAdminClientFor(backendNode(i)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void stopBackendNode(int i) {
|
protected void killBackendNode(int i) {
|
||||||
controller.kill(backendInfo(i).getQualifier());
|
backendAdminClients.get(i).close();
|
||||||
|
controller.kill(backendNode(i).getQualifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void listRealms(int i) {
|
||||||
|
log.info(String.format("Node %s: AccessTokenString: %s", i + 1, backendAdminClients.get(i).tokenManager().getAccessTokenString()));
|
||||||
|
for (RealmRepresentation r : backendAdminClients.get(i).realms().findAll()) {
|
||||||
|
log.info(String.format("Node %s: Realm: %s, Id: %s", i + 1, r.getRealm(), r.getId()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
package org.keycloak.testsuite.cluster;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.keycloak.admin.client.Keycloak;
|
||||||
|
import org.keycloak.testsuite.arquillian.ContainerInfo;
|
||||||
|
import static org.keycloak.testsuite.util.WaitUtils.pause;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author tkyjovsk
|
||||||
|
*/
|
||||||
|
public abstract class AbstractTwoNodeClusterTest extends AbstractClusterTest {
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void beforeTwoNodeClusterTest() {
|
||||||
|
startBackendNodes(2);
|
||||||
|
pause(3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ContainerInfo backend1Info() {
|
||||||
|
return backendNode(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ContainerInfo backend2Info() {
|
||||||
|
return backendNode(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Keycloak backend1AdminClient() {
|
||||||
|
return backendAdminClients.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Keycloak backend2AdminClient() {
|
||||||
|
return backendAdminClients.get(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void startBackend1() {
|
||||||
|
startBackendNode(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void startBackend2() {
|
||||||
|
startBackendNode(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void failback() {
|
||||||
|
startBackend1();
|
||||||
|
startBackend2();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void killBackend1() {
|
||||||
|
killBackendNode(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void killBackend2() {
|
||||||
|
killBackendNode(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,55 +3,43 @@ package org.keycloak.testsuite.cluster;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.admin.client.Keycloak;
|
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.testsuite.arquillian.ContainerInfo;
|
|
||||||
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.pause;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author tkyjovsk
|
* @author tkyjovsk
|
||||||
*/
|
*/
|
||||||
public class TwoNodeClusterTest extends AbstractClusterTest {
|
public class EntityInvalidationClusterTest extends AbstractTwoNodeClusterTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Test
|
||||||
public void beforeTwoNodeClusterTest() {
|
public void realmCRUDWithoutFailover() {
|
||||||
startBackendNodes(2);
|
realmCRUD(TEST + "_wofo", false);
|
||||||
pause(3000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRealm() {
|
public void realmCRUDWithFailover() {
|
||||||
testRealm(TEST, false);
|
realmCRUD(TEST + "_wfo", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
public void realmCRUD(String realm, boolean containerFailover) {
|
||||||
public void testRealmWithFailover() {
|
|
||||||
testRealm(TEST + "_fo", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testRealm(String realm, boolean containerFailover) {
|
|
||||||
RealmRepresentation testRealm = new RealmRepresentation();
|
RealmRepresentation testRealm = new RealmRepresentation();
|
||||||
testRealm.setRealm(realm);
|
testRealm.setRealm(realm);
|
||||||
testRealm.setEnabled(true);
|
testRealm.setEnabled(true);
|
||||||
|
|
||||||
// CREATE on node1
|
// CREATE on node1
|
||||||
log.info("Creating test realm via node1.");
|
|
||||||
backend1AdminClient().realms().create(testRealm);
|
backend1AdminClient().realms().create(testRealm);
|
||||||
log.info("Test realm created.");
|
|
||||||
|
|
||||||
// check if created on node1
|
// check if created on node1
|
||||||
RealmRepresentation testRealmOnBackend1 = backend1AdminClient().realms().realm(realm).toRepresentation();
|
RealmRepresentation testRealmOnBackend1 = backend1AdminClient().realms().realm(realm).toRepresentation();
|
||||||
assertEquals(testRealmOnBackend1.getRealm(), testRealm.getRealm());
|
assertEquals(testRealmOnBackend1.getRealm(), testRealm.getRealm());
|
||||||
if (containerFailover) {
|
if (containerFailover) {
|
||||||
stopBackend1();
|
killBackend1();
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if created on node2
|
// check if created on node2
|
||||||
|
@ -62,27 +50,28 @@ public class TwoNodeClusterTest extends AbstractClusterTest {
|
||||||
failback();
|
failback();
|
||||||
|
|
||||||
// UPDATE on node2
|
// UPDATE on node2
|
||||||
testRealmOnBackend2.setRealm(realm + "_updated");
|
String realmUpdated = realm + "_updated";
|
||||||
|
testRealmOnBackend2.setRealm(realmUpdated);
|
||||||
backend2AdminClient().realms().realm(realm).update(testRealmOnBackend2);
|
backend2AdminClient().realms().realm(realm).update(testRealmOnBackend2);
|
||||||
if (containerFailover) {
|
if (containerFailover) {
|
||||||
stopBackend2();
|
killBackend2();
|
||||||
}
|
}
|
||||||
// check if updated on node1
|
// check if updated on node1
|
||||||
testRealmOnBackend1 = backend1AdminClient().realms().realm(realm).toRepresentation();
|
testRealmOnBackend1 = backend1AdminClient().realms().realm(realmUpdated).toRepresentation();
|
||||||
assertEquals(testRealmOnBackend1.getId(), testRealmOnBackend2.getId());
|
assertEquals(testRealmOnBackend1.getId(), testRealmOnBackend2.getId());
|
||||||
assertEquals(testRealmOnBackend1.getRealm(), testRealmOnBackend2.getRealm());
|
assertEquals(testRealmOnBackend1.getRealm(), testRealmOnBackend2.getRealm());
|
||||||
|
|
||||||
failback();
|
failback();
|
||||||
|
|
||||||
// DELETE on node1
|
// DELETE on node1
|
||||||
backend1AdminClient().realms().realm(realm).remove();
|
backend1AdminClient().realms().realm(realmUpdated).remove();
|
||||||
if (containerFailover) {
|
if (containerFailover) {
|
||||||
stopBackend1();
|
killBackend1();
|
||||||
}
|
}
|
||||||
// check if deleted on node2
|
// check if deleted on node2
|
||||||
boolean testRealmOnBackend2Exists = false;
|
boolean testRealmOnBackend2Exists = false;
|
||||||
for (RealmRepresentation realmOnBackend2 : backend2AdminClient().realms().findAll()) {
|
for (RealmRepresentation realmOnBackend2 : backend2AdminClient().realms().findAll()) {
|
||||||
if (realm.equals(realmOnBackend2.getRealm())
|
if (realmUpdated.equals(realmOnBackend2.getRealm())
|
||||||
|| testRealmOnBackend1.getId().equals(realmOnBackend2.getId())) {
|
|| testRealmOnBackend1.getId().equals(realmOnBackend2.getId())) {
|
||||||
testRealmOnBackend2Exists = true;
|
testRealmOnBackend2Exists = true;
|
||||||
break;
|
break;
|
||||||
|
@ -91,41 +80,30 @@ public class TwoNodeClusterTest extends AbstractClusterTest {
|
||||||
assertFalse(testRealmOnBackend2Exists);
|
assertFalse(testRealmOnBackend2Exists);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ContainerInfo backend1Info() {
|
@Test
|
||||||
return backendInfo(0);
|
public void createRealmViaFrontend() {
|
||||||
}
|
String realm = TEST + "_fe";
|
||||||
|
|
||||||
protected ContainerInfo backend2Info() {
|
RealmRepresentation testRealm = new RealmRepresentation();
|
||||||
return backendInfo(1);
|
testRealm.setRealm(realm);
|
||||||
}
|
testRealm.setEnabled(true);
|
||||||
|
|
||||||
protected Keycloak backend1AdminClient() {
|
// CREATE on frontend
|
||||||
return backendAdminClients.get(0);
|
adminClient.realms().create(testRealm);
|
||||||
}
|
|
||||||
|
|
||||||
protected Keycloak backend2AdminClient() {
|
// check if created on frontend
|
||||||
return backendAdminClients.get(1);
|
RealmRepresentation testRealmOnFrontend = adminClient.realms().realm(realm).toRepresentation();
|
||||||
}
|
assertEquals(testRealmOnFrontend.getRealm(), testRealm.getRealm());
|
||||||
|
|
||||||
protected void startBackend1() {
|
// check if created on node1
|
||||||
startBackendNode(0);
|
RealmRepresentation testRealmOnBackend1 = backend1AdminClient().realms().realm(realm).toRepresentation();
|
||||||
}
|
assertEquals(testRealmOnBackend1.getId(), testRealmOnFrontend.getId());
|
||||||
|
assertEquals(testRealmOnBackend1.getRealm(), testRealmOnFrontend.getRealm());
|
||||||
|
|
||||||
protected void startBackend2() {
|
// check if created on node2
|
||||||
startBackendNode(1);
|
RealmRepresentation testRealmOnBackend2 = backend2AdminClient().realms().realm(realm).toRepresentation();
|
||||||
}
|
assertEquals(testRealmOnBackend2.getId(), testRealmOnFrontend.getId());
|
||||||
|
assertEquals(testRealmOnBackend2.getRealm(), testRealmOnFrontend.getRealm());
|
||||||
protected void failback() {
|
|
||||||
startBackend1();
|
|
||||||
startBackend2();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void stopBackend1() {
|
|
||||||
stopBackendNode(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void stopBackend2() {
|
|
||||||
stopBackendNode(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
package org.keycloak.testsuite.cluster;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import static org.keycloak.testsuite.auth.page.AuthRealm.ADMIN;
|
||||||
|
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlDoesntStartWith;
|
||||||
|
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
|
||||||
|
import static org.keycloak.testsuite.util.WaitUtils.pause;
|
||||||
|
import org.openqa.selenium.Cookie;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author tkyjovsk
|
||||||
|
*/
|
||||||
|
public class SessionFailoverClusterTest extends AbstractTwoNodeClusterTest {
|
||||||
|
|
||||||
|
public static final String KEYCLOAK_SESSION_COOKIE = "KEYCLOAK_SESSION";
|
||||||
|
public static final String KEYCLOAK_IDENTITY_COOKIE = "KEYCLOAK_IDENTITY";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore("work in progress") // only works with owners="2" at the moment
|
||||||
|
public void sessionFailover() {
|
||||||
|
|
||||||
|
// LOGOUT
|
||||||
|
accountPage.navigateTo();
|
||||||
|
driver.navigate().refresh();
|
||||||
|
pause(3000);
|
||||||
|
loginPage.form().login(ADMIN, ADMIN);
|
||||||
|
assertCurrentUrlStartsWith(accountPage);
|
||||||
|
|
||||||
|
Cookie sessionCookie = driver.manage().getCookieNamed(KEYCLOAK_SESSION_COOKIE);
|
||||||
|
assertNotNull(sessionCookie);
|
||||||
|
|
||||||
|
killBackend1();
|
||||||
|
|
||||||
|
// check if session survived backend failure
|
||||||
|
|
||||||
|
driver.navigate().refresh();
|
||||||
|
pause(3000);
|
||||||
|
|
||||||
|
assertCurrentUrlStartsWith(accountPage);
|
||||||
|
Cookie sessionCookieAfterFailover = driver.manage().getCookieNamed(KEYCLOAK_SESSION_COOKIE);
|
||||||
|
assertNotNull(sessionCookieAfterFailover);
|
||||||
|
assertEquals(sessionCookieAfterFailover.getValue(), sessionCookie.getValue());
|
||||||
|
|
||||||
|
failback();
|
||||||
|
|
||||||
|
// check if session survived backend failback
|
||||||
|
driver.navigate().refresh();
|
||||||
|
pause(3000);
|
||||||
|
assertCurrentUrlStartsWith(accountPage);
|
||||||
|
Cookie sessionCookieAfterFailback = driver.manage().getCookieNamed(KEYCLOAK_SESSION_COOKIE);
|
||||||
|
assertNotNull(sessionCookieAfterFailback);
|
||||||
|
assertEquals(sessionCookieAfterFailover.getValue(), sessionCookie.getValue());
|
||||||
|
|
||||||
|
// LOGOUT
|
||||||
|
accountPage.navigateTo();
|
||||||
|
accountPage.signOut();
|
||||||
|
|
||||||
|
assertCurrentUrlDoesntStartWith(accountPage);
|
||||||
|
masterRealmPage.navigateTo();
|
||||||
|
sessionCookie = driver.manage().getCookieNamed(KEYCLOAK_SESSION_COOKIE);
|
||||||
|
assertNull(sessionCookie);
|
||||||
|
|
||||||
|
killBackend1();
|
||||||
|
|
||||||
|
// check if session survived backend failure
|
||||||
|
driver.navigate().refresh();
|
||||||
|
pause(3000);
|
||||||
|
assertCurrentUrlDoesntStartWith(accountPage);
|
||||||
|
masterRealmPage.navigateTo();
|
||||||
|
sessionCookieAfterFailover = driver.manage().getCookieNamed(KEYCLOAK_SESSION_COOKIE);
|
||||||
|
assertNull(sessionCookieAfterFailover);
|
||||||
|
|
||||||
|
failback();
|
||||||
|
|
||||||
|
// check if session survived backend failback
|
||||||
|
driver.navigate().refresh();
|
||||||
|
pause(3000);
|
||||||
|
assertCurrentUrlDoesntStartWith(accountPage);
|
||||||
|
masterRealmPage.navigateTo();
|
||||||
|
sessionCookieAfterFailback = driver.manage().getCookieNamed(KEYCLOAK_SESSION_COOKIE);
|
||||||
|
assertNull(sessionCookieAfterFailback);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -72,10 +72,12 @@
|
||||||
<property name="enabled">${auth.server.wildfly.cluster}</property>
|
<property name="enabled">${auth.server.wildfly.cluster}</property>
|
||||||
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
|
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
|
||||||
<property name="jbossHome">${keycloak.balancer.home}</property>
|
<property name="jbossHome">${keycloak.balancer.home}</property>
|
||||||
<property name="javaVmArguments">
|
<property name="jbossArguments">
|
||||||
-Djboss.socket.binding.port-offset=${auth.server.port.offset}
|
-Djboss.socket.binding.port-offset=${auth.server.port.offset}
|
||||||
-Xms64m -Xmx512m -XX:MaxPermSize=256m
|
</property>
|
||||||
${adapter.test.props}
|
<property name="javaVmArguments">
|
||||||
|
-Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m
|
||||||
|
-Djava.net.preferIPv4Stack=true
|
||||||
</property>
|
</property>
|
||||||
<property name="managementPort">${auth.server.management.port}</property>
|
<property name="managementPort">${auth.server.management.port}</property>
|
||||||
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
|
<property name="startupTimeoutInSeconds">${startup.timeout.sec}</property>
|
||||||
|
@ -87,11 +89,14 @@
|
||||||
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
|
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
|
||||||
<property name="jbossHome">${keycloak.backend1.home}</property>
|
<property name="jbossHome">${keycloak.backend1.home}</property>
|
||||||
<property name="serverConfig">standalone-ha.xml</property>
|
<property name="serverConfig">standalone-ha.xml</property>
|
||||||
<property name="javaVmArguments">
|
<property name="jbossArguments">
|
||||||
-Djboss.socket.binding.port-offset=${auth.server.backend1.port.offset}
|
-Djboss.socket.binding.port-offset=${auth.server.backend1.port.offset}
|
||||||
-Xms64m -Xmx512m -XX:MaxPermSize=256m
|
|
||||||
${adapter.test.props}
|
|
||||||
-Djboss.node.name=node1
|
-Djboss.node.name=node1
|
||||||
|
${adapter.test.props}
|
||||||
|
</property>
|
||||||
|
<property name="javaVmArguments">
|
||||||
|
-Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m
|
||||||
|
-Djava.net.preferIPv4Stack=true
|
||||||
</property>
|
</property>
|
||||||
<!--<property name="outputToConsole">false</property>-->
|
<!--<property name="outputToConsole">false</property>-->
|
||||||
<property name="managementPort">${auth.server.backend1.management.port}</property>
|
<property name="managementPort">${auth.server.backend1.management.port}</property>
|
||||||
|
@ -104,11 +109,14 @@
|
||||||
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
|
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
|
||||||
<property name="jbossHome">${keycloak.backend2.home}</property>
|
<property name="jbossHome">${keycloak.backend2.home}</property>
|
||||||
<property name="serverConfig">standalone-ha.xml</property>
|
<property name="serverConfig">standalone-ha.xml</property>
|
||||||
<property name="javaVmArguments">
|
<property name="jbossArguments">
|
||||||
-Djboss.socket.binding.port-offset=${auth.server.backend2.port.offset}
|
-Djboss.socket.binding.port-offset=${auth.server.backend2.port.offset}
|
||||||
-Xms64m -Xmx512m -XX:MaxPermSize=256m
|
|
||||||
${adapter.test.props}
|
|
||||||
-Djboss.node.name=node2
|
-Djboss.node.name=node2
|
||||||
|
${adapter.test.props}
|
||||||
|
</property>
|
||||||
|
<property name="javaVmArguments">
|
||||||
|
-Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m
|
||||||
|
-Djava.net.preferIPv4Stack=true
|
||||||
</property>
|
</property>
|
||||||
<!--<property name="outputToConsole">false</property>-->
|
<!--<property name="outputToConsole">false</property>-->
|
||||||
<property name="managementPort">${auth.server.backend2.management.port}</property>
|
<property name="managementPort">${auth.server.backend2.management.port}</property>
|
||||||
|
|
|
@ -69,7 +69,7 @@
|
||||||
<artifactItem>
|
<artifactItem>
|
||||||
<groupId>org.jboss.as</groupId>
|
<groupId>org.jboss.as</groupId>
|
||||||
<artifactId>jboss-as-dist</artifactId>
|
<artifactId>jboss-as-dist</artifactId>
|
||||||
<version>${jboss.version}</version>
|
<version>${jboss.as.version}</version>
|
||||||
<type>zip</type>
|
<type>zip</type>
|
||||||
<outputDirectory>${containers.home}</outputDirectory>
|
<outputDirectory>${containers.home}</outputDirectory>
|
||||||
</artifactItem>
|
</artifactItem>
|
||||||
|
|
|
@ -363,7 +363,7 @@
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate.javax.persistence</groupId>
|
<groupId>org.hibernate.javax.persistence</groupId>
|
||||||
<artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
|
<artifactId>hibernate-jpa-2.1-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
|
|
|
@ -57,7 +57,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
||||||
|
@ -183,7 +183,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate.javax.persistence</groupId>
|
<groupId>org.hibernate.javax.persistence</groupId>
|
||||||
<artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
|
<artifactId>hibernate-jpa-2.1-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
|
|
|
@ -1,243 +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 org.keycloak.testsuite;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.infinispan.AdvancedCache;
|
|
||||||
import org.infinispan.Cache;
|
|
||||||
import org.infinispan.context.Flag;
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
|
|
||||||
import org.keycloak.models.ClientModel;
|
|
||||||
import org.keycloak.models.ClientSessionModel;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
|
||||||
import org.keycloak.models.KeycloakSessionTask;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.models.UserModel;
|
|
||||||
import org.keycloak.models.UserSessionModel;
|
|
||||||
import org.keycloak.models.UserSessionProvider;
|
|
||||||
import org.keycloak.models.UserSessionProviderFactory;
|
|
||||||
import org.keycloak.models.session.UserSessionPersisterProvider;
|
|
||||||
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
|
|
||||||
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
|
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
|
||||||
import org.keycloak.common.util.Time;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HOWTO USE THIS:
|
|
||||||
*
|
|
||||||
* 1) Run KeycloakServer with system properties (assuming mongo up and running on localhost):
|
|
||||||
* -Dkeycloak.realm.provider=mongo -Dkeycloak.user.provider=mongo -Dkeycloak.userSessionPersister.provider=mongo -Dkeycloak.connectionsMongo.db=keycloak -Dkeycloak.connectionsInfinispan.clustered=true -Dresources -DstartInfinispanCLI
|
|
||||||
*
|
|
||||||
* 2) Write command on STDIN to persist 50000 userSessions to mongo: persistSessions 50000
|
|
||||||
*
|
|
||||||
* 3) Run command "clear" to ensure infinispan cache is cleared. Doublecheck with command "size" is 0
|
|
||||||
*
|
|
||||||
* 4) Write command to load sessions from persistent storage - 100 sessions per worker transaction: loadPersistentSessions 100
|
|
||||||
*
|
|
||||||
* See the progress in log. Finally run command "size" to ensure size is 100001 (50000 userSessions + 50000 clientSessions + 1 initializationState item)
|
|
||||||
*
|
|
||||||
* 5) Alternative to step 3+4 - Kill the server after step 2 and start two KeycloakServer in parallel on ports 8081 and 8082 . See the progress in logs of loading persistent sessions to infinispan.
|
|
||||||
* Kill the coordinator (usually 8081 node) during startup and see the node 8082 became coordinator and took ownership of loading persistent sessions. After node 8082 fully started, the size of infinispan is again 100001
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class InfinispanCLI {
|
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(InfinispanCLI.class);
|
|
||||||
|
|
||||||
private final KeycloakSessionFactory sessionFactory;
|
|
||||||
|
|
||||||
public InfinispanCLI(KeycloakServer server) {
|
|
||||||
this.sessionFactory = server.getSessionFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
// WARNING: Stdin blocking operation
|
|
||||||
public void start() throws IOException {
|
|
||||||
log.info("Starting infinispan CLI. Exit with 'exit'");
|
|
||||||
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
|
|
||||||
String line;
|
|
||||||
try {
|
|
||||||
while ((line = reader.readLine()) != null) {
|
|
||||||
log.info("Command: " + line);
|
|
||||||
|
|
||||||
if (line.equals("exit")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String finalLine = line;
|
|
||||||
|
|
||||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(KeycloakSession session) {
|
|
||||||
InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class);
|
|
||||||
Cache<String, SessionEntity> ispnCache = provider.getCache(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME);
|
|
||||||
runTask(finalLine, ispnCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
log.info("Exit infinispan CLI");
|
|
||||||
reader.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void runTask(String line, Cache<String, SessionEntity> cache) {
|
|
||||||
try {
|
|
||||||
String[] splits = line.split(" ");
|
|
||||||
if (splits[0].equals("put")) {
|
|
||||||
UserSessionEntity userSession = new UserSessionEntity();
|
|
||||||
String id = splits[1];
|
|
||||||
|
|
||||||
userSession.setId(id);
|
|
||||||
userSession.setRealm(splits[2]);
|
|
||||||
userSession.setLastSessionRefresh(Time.currentTime());
|
|
||||||
cache.put(id, userSession);
|
|
||||||
|
|
||||||
} else if (splits[0].equals("get")) {
|
|
||||||
String id = splits[1];
|
|
||||||
UserSessionEntity userSession = (UserSessionEntity) cache.get(id);
|
|
||||||
printSession(id, userSession);
|
|
||||||
} else if (splits[0].equals("remove")) {
|
|
||||||
String id = splits[1];
|
|
||||||
cache.remove(id);
|
|
||||||
} else if (splits[0].equals("clear")) {
|
|
||||||
cache.clear();
|
|
||||||
log.info("Cache cleared");
|
|
||||||
} else if (splits[0].equals("size")) {
|
|
||||||
log.info("Size: " + cache.size());
|
|
||||||
} else if (splits[0].equals("list")) {
|
|
||||||
for (String id : cache.keySet()) {
|
|
||||||
SessionEntity entity = cache.get(id);
|
|
||||||
if (!(entity instanceof UserSessionEntity)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
UserSessionEntity userSession = (UserSessionEntity) cache.get(id);
|
|
||||||
log.info("list: key=" + id + ", value=" + toString(userSession));
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (splits[0].equals("getLocal")) {
|
|
||||||
String id = splits[1];
|
|
||||||
cache = ((AdvancedCache) cache).withFlags(Flag.CACHE_MODE_LOCAL);
|
|
||||||
UserSessionEntity userSession = (UserSessionEntity) cache.get(id);
|
|
||||||
printSession(id, userSession);
|
|
||||||
|
|
||||||
} else if (splits[0].equals("persistSessions")) {
|
|
||||||
|
|
||||||
final int count = Integer.parseInt(splits[1]);
|
|
||||||
final List<String> userSessionIds = new LinkedList<>();
|
|
||||||
final List<String> clientSessionIds = new LinkedList<>();
|
|
||||||
|
|
||||||
// Create sessions in separate transaction first
|
|
||||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(KeycloakSession session) {
|
|
||||||
RealmModel realm = session.realms().getRealmByName("master");
|
|
||||||
UserModel john = session.users().getUserByUsername("admin", realm);
|
|
||||||
ClientModel testApp = realm.getClientByClientId("security-admin-console");
|
|
||||||
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
|
|
||||||
|
|
||||||
for (int i=0 ; i<count ; i++) {
|
|
||||||
UserSessionModel userSession = session.sessions().createUserSession(realm, john, "john-doh@localhost", "127.0.0.2", "form", true, null, null);
|
|
||||||
ClientSessionModel clientSession = session.sessions().createClientSession(realm, testApp);
|
|
||||||
clientSession.setUserSession(userSession);
|
|
||||||
clientSession.setRedirectUri("http://redirect");
|
|
||||||
clientSession.setNote("foo", "bar-" + i);
|
|
||||||
userSessionIds.add(userSession.getId());
|
|
||||||
clientSessionIds.add(clientSession.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
log.info("Sessions created in infinispan storage");
|
|
||||||
|
|
||||||
// Persist them now
|
|
||||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(KeycloakSession session) {
|
|
||||||
RealmModel realm = session.realms().getRealmByName("master");
|
|
||||||
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
|
|
||||||
|
|
||||||
for (String userSessionId : userSessionIds) {
|
|
||||||
UserSessionModel userSession = session.sessions().getUserSession(realm, userSessionId);
|
|
||||||
persister.createUserSession(userSession, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("userSessions persisted");
|
|
||||||
|
|
||||||
for (String clientSessionId : clientSessionIds) {
|
|
||||||
ClientSessionModel clientSession = session.sessions().getClientSession(realm, clientSessionId);
|
|
||||||
persister.createClientSession(clientSession, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("clientSessions persisted");
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Persist them now
|
|
||||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(KeycloakSession session) {
|
|
||||||
RealmModel realm = session.realms().getRealmByName("master");
|
|
||||||
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
|
|
||||||
|
|
||||||
log.info(count + " sessions persisted. Total number of sessions: " + persister.getUserSessionsCount(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
} else if (splits[0].equals("loadPersistentSessions")) {
|
|
||||||
|
|
||||||
int sessionsPerSegment = Integer.parseInt(splits[1]);
|
|
||||||
UserSessionProviderFactory sessionProviderFactory = (UserSessionProviderFactory) sessionFactory.getProviderFactory(UserSessionProvider.class);
|
|
||||||
sessionProviderFactory.loadPersistentSessions(sessionFactory, 10, sessionsPerSegment);
|
|
||||||
|
|
||||||
log.info("All persistent sessions loaded successfully");
|
|
||||||
}
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
log.error("Error occured during command. ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void printSession(String id, UserSessionEntity userSession) {
|
|
||||||
if (userSession == null) {
|
|
||||||
log.info("Not found session with Id: " + id);
|
|
||||||
} else {
|
|
||||||
log.info("Found session. ID: " + toString(userSession));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String toString(UserSessionEntity userSession) {
|
|
||||||
return "ID: " + userSession.getId() + ", realm: " + userSession.getRealm() + ", lastAccessTime: " + Time.toDate(userSession.getLastSessionRefresh()) +
|
|
||||||
", clientSessions: " + userSession.getClientSessions().size();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -33,6 +33,7 @@ import org.keycloak.services.filters.KeycloakSessionServletFilter;
|
||||||
import org.keycloak.services.managers.ApplianceBootstrap;
|
import org.keycloak.services.managers.ApplianceBootstrap;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.services.resources.KeycloakApplication;
|
import org.keycloak.services.resources.KeycloakApplication;
|
||||||
|
import org.keycloak.testsuite.util.cli.InfinispanCLI;
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
|
||||||
import javax.servlet.DispatcherType;
|
import javax.servlet.DispatcherType;
|
||||||
|
|
|
@ -774,4 +774,27 @@ public class AccountTest {
|
||||||
Assert.assertEquals(0, thirdPartyEntry.getProtocolMappersGranted().size());
|
Assert.assertEquals(0, thirdPartyEntry.getProtocolMappersGranted().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loginToSpecificPage() {
|
||||||
|
changePasswordPage.open();
|
||||||
|
loginPage.login("test-user@localhost", "password");
|
||||||
|
|
||||||
|
Assert.assertTrue(changePasswordPage.isCurrent());
|
||||||
|
|
||||||
|
events.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loginToSpecificPageWithReferrer() {
|
||||||
|
driver.navigate().to(changePasswordPage.getPath() + "?referrer=account");
|
||||||
|
System.out.println(driver.getCurrentUrl());
|
||||||
|
|
||||||
|
loginPage.login("test-user@localhost", "password");
|
||||||
|
System.out.println(driver.getCurrentUrl());
|
||||||
|
|
||||||
|
Assert.assertTrue(changePasswordPage.isCurrent());
|
||||||
|
|
||||||
|
events.clear();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -284,7 +284,7 @@ public abstract class AbstractKerberosTest {
|
||||||
SpnegoAuthenticator.bypassChallengeJavascript = true;
|
SpnegoAuthenticator.bypassChallengeJavascript = true;
|
||||||
driver.navigate().to(KERBEROS_APP_URL);
|
driver.navigate().to(KERBEROS_APP_URL);
|
||||||
String kcLoginPageLocation = driver.getCurrentUrl();
|
String kcLoginPageLocation = driver.getCurrentUrl();
|
||||||
String location = "http://localhost:8081/auth/realms/test/protocol/openid-connect/auth?response_type=code&client_id=kerberos-app&redirect_uri=http%3A%2F%2Flocalhost%3A8081%2Fkerberos-portal&state=0%2F88a96ddd-84fe-4e77-8a46-02394d7b3a7d&login=true";
|
|
||||||
// Request for SPNEGO login sent with Resteasy client
|
// Request for SPNEGO login sent with Resteasy client
|
||||||
spnegoSchemeFactory.setCredentials(username, password);
|
spnegoSchemeFactory.setCredentials(username, password);
|
||||||
Response response = client.target(kcLoginPageLocation).request().get();
|
Response response = client.target(kcLoginPageLocation).request().get();
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.security.PrivilegedExceptionAction;
|
||||||
import javax.security.auth.Subject;
|
import javax.security.auth.Subject;
|
||||||
|
|
||||||
import org.apache.http.auth.AuthScheme;
|
import org.apache.http.auth.AuthScheme;
|
||||||
|
import org.apache.http.auth.Credentials;
|
||||||
import org.apache.http.impl.auth.SPNegoScheme;
|
import org.apache.http.impl.auth.SPNegoScheme;
|
||||||
import org.apache.http.impl.auth.SPNegoSchemeFactory;
|
import org.apache.http.impl.auth.SPNegoSchemeFactory;
|
||||||
import org.apache.http.params.HttpParams;
|
import org.apache.http.params.HttpParams;
|
||||||
|
@ -72,7 +73,7 @@ public class KeycloakSPNegoSchemeFactory extends SPNegoSchemeFactory {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected byte[] generateGSSToken(byte[] input, Oid oid, String authServer) throws GSSException {
|
protected byte[] generateGSSToken(byte[] input, Oid oid, String authServer, Credentials credentials) throws GSSException {
|
||||||
KerberosUsernamePasswordAuthenticator authenticator = new KerberosUsernamePasswordAuthenticator(kerberosConfig);
|
KerberosUsernamePasswordAuthenticator authenticator = new KerberosUsernamePasswordAuthenticator(kerberosConfig);
|
||||||
try {
|
try {
|
||||||
Subject clientSubject = authenticator.authenticateSubject(username, password);
|
Subject clientSubject = authenticator.authenticateSubject(username, password);
|
||||||
|
|
|
@ -58,7 +58,7 @@ public class AccountPasswordPage extends AbstractAccountPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCurrent() {
|
public boolean isCurrent() {
|
||||||
return driver.getTitle().contains("Account Management") && driver.getCurrentUrl().endsWith("/account/password");
|
return driver.getTitle().contains("Account Management") && driver.getCurrentUrl().split("\\?")[0].endsWith("/account/password");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void open() {
|
public void open() {
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* 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.testsuite.util.cli;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
import org.keycloak.models.KeycloakSessionTask;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public abstract class AbstractCommand {
|
||||||
|
|
||||||
|
protected final Logger log = Logger.getLogger(this.getClass().getName());
|
||||||
|
|
||||||
|
protected List<String> args;
|
||||||
|
protected KeycloakSessionFactory sessionFactory;
|
||||||
|
|
||||||
|
public void injectProperties(List<String> args, InfinispanCLI cli, KeycloakSessionFactory sessionFactory) {
|
||||||
|
this.args = args;
|
||||||
|
this.sessionFactory = sessionFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runCommand() {
|
||||||
|
try {
|
||||||
|
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(KeycloakSession session) {
|
||||||
|
doRunCommand(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
} catch (HandledException handled) {
|
||||||
|
// Fine to ignore. Was handled already
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
log.error("Error occured during command. ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract String getName();
|
||||||
|
protected abstract void doRunCommand(KeycloakSession session);
|
||||||
|
|
||||||
|
protected String getArg(int index) {
|
||||||
|
try {
|
||||||
|
return args.get(index);
|
||||||
|
} catch (IndexOutOfBoundsException ex) {
|
||||||
|
log.errorf("Usage: %s", printUsage());
|
||||||
|
throw new HandledException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Integer getIntArg(int index) {
|
||||||
|
String str = getArg(index);
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(str);
|
||||||
|
} catch (NumberFormatException nex) {
|
||||||
|
log.errorf("Usage: %s", printUsage());
|
||||||
|
throw new HandledException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String printUsage() {
|
||||||
|
return getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class HandledException extends RuntimeException {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,198 @@
|
||||||
|
/*
|
||||||
|
* 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.testsuite.util.cli;
|
||||||
|
|
||||||
|
import org.infinispan.AdvancedCache;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
import org.infinispan.context.Flag;
|
||||||
|
import org.keycloak.common.util.Time;
|
||||||
|
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
|
||||||
|
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public abstract class AbstractOfflineCacheCommand extends AbstractCommand {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRunCommand(KeycloakSession session) {
|
||||||
|
InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class);
|
||||||
|
Cache<String, SessionEntity> ispnCache = provider.getCache(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME);
|
||||||
|
doRunCacheCommand(session, ispnCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void printSession(String id, UserSessionEntity userSession) {
|
||||||
|
if (userSession == null) {
|
||||||
|
log.info("Not found session with Id: " + id);
|
||||||
|
} else {
|
||||||
|
log.info("Found session. ID: " + toString(userSession));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String toString(UserSessionEntity userSession) {
|
||||||
|
int clientSessionsSize = userSession.getClientSessions()==null ? 0 : userSession.getClientSessions().size();
|
||||||
|
return "ID: " + userSession.getId() + ", realm: " + userSession.getRealm() + ", lastAccessTime: " + Time.toDate(userSession.getLastSessionRefresh()) +
|
||||||
|
", clientSessions: " + clientSessionsSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntity> cache);
|
||||||
|
|
||||||
|
|
||||||
|
// IMPLS
|
||||||
|
|
||||||
|
public static class PutCommand extends AbstractOfflineCacheCommand {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "put";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntity> cache) {
|
||||||
|
UserSessionEntity userSession = new UserSessionEntity();
|
||||||
|
String id = getArg(0);
|
||||||
|
|
||||||
|
userSession.setId(id);
|
||||||
|
userSession.setRealm(getArg(1));
|
||||||
|
|
||||||
|
userSession.setLastSessionRefresh(Time.currentTime());
|
||||||
|
cache.put(id, userSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String printUsage() {
|
||||||
|
return getName() + " <user-session-id> <realm-name>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class GetCommand extends AbstractOfflineCacheCommand {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "get";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntity> cache) {
|
||||||
|
String id = getArg(0);
|
||||||
|
UserSessionEntity userSession = (UserSessionEntity) cache.get(id);
|
||||||
|
printSession(id, userSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String printUsage() {
|
||||||
|
return getName() + " <user-session-id>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class RemoveCommand extends AbstractOfflineCacheCommand {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "remove";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntity> cache) {
|
||||||
|
String id = getArg(0);
|
||||||
|
cache.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String printUsage() {
|
||||||
|
return getName() + " <user-session-id>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class ClearCommand extends AbstractOfflineCacheCommand {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "clear";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntity> cache) {
|
||||||
|
cache.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class SizeCommand extends AbstractOfflineCacheCommand {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "size";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntity> cache) {
|
||||||
|
log.info("Size: " + cache.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class ListCommand extends AbstractOfflineCacheCommand {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "list";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntity> cache) {
|
||||||
|
for (String id : cache.keySet()) {
|
||||||
|
SessionEntity entity = cache.get(id);
|
||||||
|
if (!(entity instanceof UserSessionEntity)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
UserSessionEntity userSession = (UserSessionEntity) cache.get(id);
|
||||||
|
log.info("list: key=" + id + ", value=" + toString(userSession));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class GetLocalCommand extends AbstractOfflineCacheCommand {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "getLocal";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRunCacheCommand(KeycloakSession session, Cache<String, SessionEntity> cache) {
|
||||||
|
String id = getArg(0);
|
||||||
|
cache = ((AdvancedCache) cache).withFlags(Flag.CACHE_MODE_LOCAL);
|
||||||
|
UserSessionEntity userSession = (UserSessionEntity) cache.get(id);
|
||||||
|
printSession(id, userSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String printUsage() {
|
||||||
|
return getName() + " <user-session-id>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,187 @@
|
||||||
|
/*
|
||||||
|
* 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.testsuite.util.cli;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
import org.keycloak.testsuite.KeycloakServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HOWTO USE THIS:
|
||||||
|
*
|
||||||
|
* 1) Run KeycloakServer with system properties (assuming mongo up and running on localhost):
|
||||||
|
* -Dkeycloak.realm.provider=mongo -Dkeycloak.user.provider=mongo -Dkeycloak.userSessionPersister.provider=mongo -Dkeycloak.connectionsMongo.db=keycloak -Dkeycloak.connectionsInfinispan.clustered=true -Dresources -DstartInfinispanCLI
|
||||||
|
*
|
||||||
|
* 2) Write command on STDIN to persist 50000 userSessions to mongo: persistSessions 50000
|
||||||
|
*
|
||||||
|
* 3) Run command "clear" to ensure infinispan cache is cleared. Doublecheck with command "size" is 0
|
||||||
|
*
|
||||||
|
* 4) Write command to load sessions from persistent storage - 100 sessions per worker transaction: loadPersistentSessions 100
|
||||||
|
*
|
||||||
|
* See the progress in log. Finally run command "size" to ensure size is 100001 (50000 userSessions + 50000 clientSessions + 1 initializationState item)
|
||||||
|
*
|
||||||
|
* 5) Alternative to step 3+4 - Kill the server after step 2 and start two KeycloakServer in parallel on ports 8081 and 8082 . See the progress in logs of loading persistent sessions to infinispan.
|
||||||
|
* Kill the coordinator (usually 8081 node) during startup and see the node 8082 became coordinator and took ownership of loading persistent sessions. After node 8082 fully started, the size of infinispan is again 100001
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class InfinispanCLI {
|
||||||
|
|
||||||
|
private static final Logger log = Logger.getLogger(InfinispanCLI.class);
|
||||||
|
|
||||||
|
private static final Class<?>[] BUILTIN_COMMANDS = {
|
||||||
|
ExitCommand.class,
|
||||||
|
HelpCommand.class,
|
||||||
|
AbstractOfflineCacheCommand.PutCommand.class,
|
||||||
|
AbstractOfflineCacheCommand.GetCommand.class,
|
||||||
|
AbstractOfflineCacheCommand.GetLocalCommand.class,
|
||||||
|
AbstractOfflineCacheCommand.RemoveCommand.class,
|
||||||
|
AbstractOfflineCacheCommand.SizeCommand.class,
|
||||||
|
AbstractOfflineCacheCommand.ListCommand.class,
|
||||||
|
AbstractOfflineCacheCommand.ClearCommand.class,
|
||||||
|
PersistSessionsCommand.class,
|
||||||
|
LoadPersistentSessionsCommand.class,
|
||||||
|
UserCommands.Create.class,
|
||||||
|
UserCommands.Remove.class,
|
||||||
|
UserCommands.Count.class,
|
||||||
|
UserCommands.GetUser.class
|
||||||
|
};
|
||||||
|
|
||||||
|
private final KeycloakSessionFactory sessionFactory;
|
||||||
|
private final Map<String, Class<? extends AbstractCommand>> commands = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
public InfinispanCLI(KeycloakServer server) {
|
||||||
|
this.sessionFactory = server.getSessionFactory();
|
||||||
|
|
||||||
|
// register builtin commands
|
||||||
|
for (Class<?> clazz : BUILTIN_COMMANDS) {
|
||||||
|
Class<? extends AbstractCommand> commandClazz = (Class<? extends AbstractCommand>) clazz;
|
||||||
|
try {
|
||||||
|
AbstractCommand command = commandClazz.newInstance();
|
||||||
|
commands.put(command.getName(), commandClazz);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
log.error("Error registering command of class: " + commandClazz.getName(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerCommand(String name, Class<? extends AbstractCommand> command) {
|
||||||
|
commands.put(name, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
// WARNING: Stdin blocking operation
|
||||||
|
public void start() throws IOException {
|
||||||
|
log.info("Starting infinispan CLI. Exit with 'exit' . Available commands with 'help' ");
|
||||||
|
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
|
||||||
|
String line;
|
||||||
|
try {
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
log.info("Command: " + line);
|
||||||
|
|
||||||
|
String[] splits = line.split(" ");
|
||||||
|
String commandName = splits[0];
|
||||||
|
Class<? extends AbstractCommand> commandClass = commands.get(commandName);
|
||||||
|
if (commandClass == null) {
|
||||||
|
log.errorf("Unknown command: %s", commandName);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
AbstractCommand command = commandClass.newInstance();
|
||||||
|
List<String> args = new ArrayList<>(Arrays.asList(splits));
|
||||||
|
args.remove(0);
|
||||||
|
command.injectProperties(args, this, sessionFactory);
|
||||||
|
command.runCommand();
|
||||||
|
|
||||||
|
// Just special handling of ExitCommand
|
||||||
|
if (command instanceof ExitCommand) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (InstantiationException ex) {
|
||||||
|
log.error(ex);
|
||||||
|
} catch (IllegalAccessException ex) {
|
||||||
|
log.error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
log.info("Exit infinispan CLI");
|
||||||
|
reader.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ExitCommand extends AbstractCommand {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "exit";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runCommand() {
|
||||||
|
// no need to implement. Exit handled in parent
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRunCommand(KeycloakSession session) {
|
||||||
|
// no need to implement
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String printUsage() {
|
||||||
|
return getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class HelpCommand extends AbstractCommand {
|
||||||
|
|
||||||
|
private List<String> commandNames = new ArrayList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void injectProperties(List<String> args, InfinispanCLI cli, KeycloakSessionFactory sessionFactory) {
|
||||||
|
for (String commandName : cli.commands.keySet()) {
|
||||||
|
commandNames.add(commandName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "help";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runCommand() {
|
||||||
|
log.info("Available commands: " + commandNames.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRunCommand(KeycloakSession session) {
|
||||||
|
// no need to implement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* 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.testsuite.util.cli;
|
||||||
|
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.UserSessionProvider;
|
||||||
|
import org.keycloak.models.UserSessionProviderFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class LoadPersistentSessionsCommand extends AbstractCommand {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "loadPersistentSessions";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRunCommand(KeycloakSession session) {
|
||||||
|
int sessionsPerSegment = getIntArg(0);
|
||||||
|
UserSessionProviderFactory sessionProviderFactory = (UserSessionProviderFactory) sessionFactory.getProviderFactory(UserSessionProvider.class);
|
||||||
|
sessionProviderFactory.loadPersistentSessions(sessionFactory, 10, sessionsPerSegment);
|
||||||
|
|
||||||
|
log.info("All persistent sessions loaded successfully");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String printUsage() {
|
||||||
|
return super.printUsage() + " <sessions-count-per-segment>";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* 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.testsuite.util.cli;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.models.ClientSessionModel;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.KeycloakSessionTask;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.models.UserSessionModel;
|
||||||
|
import org.keycloak.models.session.UserSessionPersisterProvider;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class PersistSessionsCommand extends AbstractCommand {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "persistSessions";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doRunCommand(KeycloakSession sess) {
|
||||||
|
final int count = getIntArg(0);
|
||||||
|
final List<String> userSessionIds = new LinkedList<>();
|
||||||
|
final List<String> clientSessionIds = new LinkedList<>();
|
||||||
|
|
||||||
|
// Create sessions in separate transaction first
|
||||||
|
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(KeycloakSession session) {
|
||||||
|
RealmModel realm = session.realms().getRealmByName("master");
|
||||||
|
UserModel john = session.users().getUserByUsername("admin", realm);
|
||||||
|
ClientModel testApp = realm.getClientByClientId("security-admin-console");
|
||||||
|
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
UserSessionModel userSession = session.sessions().createUserSession(realm, john, "john-doh@localhost", "127.0.0.2", "form", true, null, null);
|
||||||
|
ClientSessionModel clientSession = session.sessions().createClientSession(realm, testApp);
|
||||||
|
clientSession.setUserSession(userSession);
|
||||||
|
clientSession.setRedirectUri("http://redirect");
|
||||||
|
clientSession.setNote("foo", "bar-" + i);
|
||||||
|
userSessionIds.add(userSession.getId());
|
||||||
|
clientSessionIds.add(clientSession.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
log.info("Sessions created in infinispan storage");
|
||||||
|
|
||||||
|
// Persist them now
|
||||||
|
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(KeycloakSession session) {
|
||||||
|
RealmModel realm = session.realms().getRealmByName("master");
|
||||||
|
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
|
||||||
|
|
||||||
|
int counter = 0;
|
||||||
|
for (String userSessionId : userSessionIds) {
|
||||||
|
counter++;
|
||||||
|
UserSessionModel userSession = session.sessions().getUserSession(realm, userSessionId);
|
||||||
|
persister.createUserSession(userSession, true);
|
||||||
|
if (counter%1000 == 0) {
|
||||||
|
log.infof("%d user sessions persisted. Continue", counter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.infof("All %d user sessions persisted", counter);
|
||||||
|
|
||||||
|
counter = 0;
|
||||||
|
for (String clientSessionId : clientSessionIds) {
|
||||||
|
counter++;
|
||||||
|
ClientSessionModel clientSession = session.sessions().getClientSession(realm, clientSessionId);
|
||||||
|
persister.createClientSession(clientSession, true);
|
||||||
|
if (counter%1000 == 0) {
|
||||||
|
log.infof("%d client sessions persisted. Continue", counter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.infof("All %d client sessions persisted", counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Persist them now
|
||||||
|
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(KeycloakSession session) {
|
||||||
|
UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
|
||||||
|
log.info("Total number of sessions in persister: " + persister.getUserSessionsCount(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String printUsage() {
|
||||||
|
return super.printUsage() + " <sessions-count>";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,212 @@
|
||||||
|
/*
|
||||||
|
* 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.testsuite.util.cli;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.RoleModel;
|
||||||
|
import org.keycloak.models.UserCredentialModel;
|
||||||
|
import org.keycloak.models.UserModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class UserCommands {
|
||||||
|
|
||||||
|
public static class Create extends AbstractCommand {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "createUsers";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRunCommand(KeycloakSession session) {
|
||||||
|
String usernamePrefix = getArg(0);
|
||||||
|
String password = getArg(1);
|
||||||
|
String realmName = getArg(2);
|
||||||
|
int first = getIntArg(3);
|
||||||
|
int count = getIntArg(4);
|
||||||
|
String roleNames = getArg(5);
|
||||||
|
|
||||||
|
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||||
|
if (realm == null) {
|
||||||
|
log.errorf("Unknown realm: %s", realmName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<RoleModel> roles = findRoles(realm, roleNames);
|
||||||
|
|
||||||
|
int last = first + count;
|
||||||
|
for (int counter = first; counter < last; counter++) {
|
||||||
|
String username = usernamePrefix + counter;
|
||||||
|
UserModel user = session.users().addUser(realm, username);
|
||||||
|
user.setEnabled(true);
|
||||||
|
user.setEmail(username + "@keycloak.org");
|
||||||
|
UserCredentialModel passwordCred = UserCredentialModel.password(password);
|
||||||
|
user.updateCredential(passwordCred);
|
||||||
|
|
||||||
|
for (RoleModel role : roles) {
|
||||||
|
user.grantRole(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.infof("Users from %s to %s created", usernamePrefix + first, usernamePrefix + (last - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String printUsage() {
|
||||||
|
return super.printUsage() + " <username-prefix> <password> <realm-name> <starting-user-offset> <count> <realm-roles-list>. \nRoles list is divided by comma (client roles not yet supported)>\n" +
|
||||||
|
"Example usage: " + super.printUsage() + " test test demo 0 20 user,admin";
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<RoleModel> findRoles(RealmModel realm, String rolesList) {
|
||||||
|
Set<RoleModel> result = new HashSet<>();
|
||||||
|
|
||||||
|
String[] roles = rolesList.split(",");
|
||||||
|
for (String roleName : roles) {
|
||||||
|
roleName = roleName.trim();
|
||||||
|
RoleModel role;
|
||||||
|
if (roleName.contains("/")) {
|
||||||
|
String[] spl = roleName.split("/");
|
||||||
|
ClientModel client = realm.getClientByClientId(spl[0]);
|
||||||
|
if (client == null) {
|
||||||
|
log.errorf("Client not found: %s", spl[0]);
|
||||||
|
throw new HandledException();
|
||||||
|
}
|
||||||
|
role = client.getRole(spl[1]);
|
||||||
|
} else {
|
||||||
|
role = realm.getRole(roleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (role == null) {
|
||||||
|
log.errorf("Role not found: %s", roleName);
|
||||||
|
throw new HandledException();
|
||||||
|
}
|
||||||
|
|
||||||
|
result.add(role);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class Remove extends AbstractCommand {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "removeUsers";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRunCommand(KeycloakSession session) {
|
||||||
|
String usernamePrefix = getArg(0);
|
||||||
|
String realmName = getArg(1);
|
||||||
|
int first = getIntArg(2);
|
||||||
|
int count = getIntArg(3);
|
||||||
|
|
||||||
|
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||||
|
if (realm == null) {
|
||||||
|
log.errorf("Unknown realm: %s", realmName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int last = first + count;
|
||||||
|
for (int counter = first; counter < last; counter++) {
|
||||||
|
String username = usernamePrefix + counter;
|
||||||
|
UserModel user = session.users().getUserByUsername(username, realm);
|
||||||
|
if (user == null) {
|
||||||
|
log.errorf("User '%s' not found", username);
|
||||||
|
} else {
|
||||||
|
session.users().removeUser(realm, user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.infof("Users from %s to %s removed", usernamePrefix + first, usernamePrefix + (last - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String printUsage() {
|
||||||
|
return super.printUsage() + " <username-prefix> <realm-name> <starting-user-offset> <count> \n" +
|
||||||
|
"Example usage: " + super.printUsage() + " test demo 0 20";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class Count extends AbstractCommand {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "getUsersCount";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRunCommand(KeycloakSession session) {
|
||||||
|
String realmName = getArg(0);
|
||||||
|
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||||
|
if (realm == null) {
|
||||||
|
log.errorf("Unknown realm: %s", realmName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int usersCount = session.users().getUsersCount(realm);
|
||||||
|
log.infof("Users count in realm %s: %d", realmName, usersCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String printUsage() {
|
||||||
|
return super.printUsage() + " <realm-name>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class GetUser extends AbstractCommand {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "getUser";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRunCommand(KeycloakSession session) {
|
||||||
|
String realmName = getArg(0);
|
||||||
|
String username = getArg(1);
|
||||||
|
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||||
|
if (realm == null) {
|
||||||
|
log.errorf("Unknown realm: %s", realmName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserModel user = session.users().getUserByUsername(username, realm);
|
||||||
|
if (user == null) {
|
||||||
|
log.infof("User '%s' doesn't exist in realm '%s'", username, realmName);
|
||||||
|
} else {
|
||||||
|
log.infof("User: ID: '%s', username: '%s', mail: '%s'", user.getId(), user.getUsername(), user.getEmail());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String printUsage() {
|
||||||
|
return super.printUsage() + " <realm-name> <username>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -59,7 +59,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
||||||
|
@ -165,7 +165,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate.javax.persistence</groupId>
|
<groupId>org.hibernate.javax.persistence</groupId>
|
||||||
<artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
|
<artifactId>hibernate-jpa-2.1-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
|
|
|
@ -59,7 +59,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
||||||
|
@ -165,7 +165,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate.javax.persistence</groupId>
|
<groupId>org.hibernate.javax.persistence</groupId>
|
||||||
<artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
|
<artifactId>hibernate-jpa-2.1-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
||||||
|
@ -165,7 +165,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate.javax.persistence</groupId>
|
<groupId>org.hibernate.javax.persistence</groupId>
|
||||||
<artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
|
<artifactId>hibernate-jpa-2.1-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
|
|
|
@ -203,8 +203,7 @@
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate.javax.persistence</groupId>
|
<groupId>org.hibernate.javax.persistence</groupId>
|
||||||
<artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
|
<artifactId>hibernate-jpa-2.1-api</artifactId>
|
||||||
<version>${hibernate.javax.persistence.version}</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
||||||
|
@ -156,7 +156,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate.javax.persistence</groupId>
|
<groupId>org.hibernate.javax.persistence</groupId>
|
||||||
<artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
|
<artifactId>hibernate-jpa-2.1-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
||||||
|
@ -165,7 +165,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate.javax.persistence</groupId>
|
<groupId>org.hibernate.javax.persistence</groupId>
|
||||||
<artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
|
<artifactId>hibernate-jpa-2.1-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
|
|
|
@ -77,7 +77,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
||||||
|
@ -197,7 +197,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate.javax.persistence</groupId>
|
<groupId>org.hibernate.javax.persistence</groupId>
|
||||||
<artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
|
<artifactId>hibernate-jpa-2.1-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
||||||
|
@ -169,7 +169,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate.javax.persistence</groupId>
|
<groupId>org.hibernate.javax.persistence</groupId>
|
||||||
<artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
|
<artifactId>hibernate-jpa-2.1-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.1_spec</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
||||||
|
@ -158,7 +158,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate.javax.persistence</groupId>
|
<groupId>org.hibernate.javax.persistence</groupId>
|
||||||
<artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
|
<artifactId>hibernate-jpa-2.1-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
|
|
|
@ -70,20 +70,13 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.logging</groupId>
|
<groupId>org.jboss.logging</groupId>
|
||||||
<artifactId>jboss-logging-annotations</artifactId>
|
<artifactId>jboss-logging-annotations</artifactId>
|
||||||
<version>${jboss-logging-tools.version}</version>
|
|
||||||
<!-- This is a compile-time dependency of this project, but is not needed at compile or runtime by other
|
|
||||||
projects that depend on this project.-->
|
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.logging</groupId>
|
<groupId>org.jboss.logging</groupId>
|
||||||
<artifactId>jboss-logging-processor</artifactId>
|
<artifactId>jboss-logging-processor</artifactId>
|
||||||
<!-- This is a compile-time dependency of this project, but is not needed at compile or runtime by other
|
|
||||||
projects that depend on this project.-->
|
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
Loading…
Reference in a new issue