Compare commits

..
Author SHA1 Message Date
keycloak-bot 1fc98ad9e3 Set version to 3.2.0.Final 2017-07-05 05:31:21 +00:00
keycloak-bot 51769f2e78 Set version to 3.2.0.Final-SNAPSHOT 2017-06-30 09:28:29 +00:00
keycloak-bot b418dcafc3 Set version to 3.2.0.CR1 2017-06-30 08:01:33 +00:00
Stian Thorgersen 124ae402e2 KEYCLOAK-5091
Revert to WildFly 10 for 3.2 release

KEYCLOAK-4189 Fix cluster tests failures
2017-06-30 09:34:12 +02:00
1867 changed files with 11317 additions and 63642 deletions

No files matched your search

-6
View File
@@ -49,9 +49,3 @@ target
# Maven shade
#############
*dependency-reduced-pom.xml
# nodejs #
##########
# KEYCLOAK-5391: We will re-exclude node_modules when node_modules handling is worked out.
# For now, we keep our js libraries checked into GitHub, so we don't ignore.
#node_modules
+16 -11
View File
@@ -1,28 +1,33 @@
language: java
dist: precise
cache:
cache: false
directories:
- $HOME/.m2
before_cache:
- rm -rf $HOME/.m2/repository/org/keycloak
env:
global:
- MAVEN_SKIP_RC=true
- MAVEN_OPTS="-Xms512m -Xmx1536m"
- MAVEN_OPTS="-Xms512m -Xmx2048m"
matrix:
- TESTS=unit
- TESTS=server-group1
- TESTS=server-group2
- TESTS=server-group3
- TESTS=server-group4
- TESTS=group1
- TESTS=group2
- TESTS=group3
- TESTS=group4
- TESTS=old
- TESTS=crossdc
jdk:
- oraclejdk8
install: true
before_script:
- export MAVEN_SKIP_RC=true
script:
install:
- travis_wait 60 mvn install --no-snapshot-updates -Pdistribution -DskipTestsuite -B -V -q
script:
- ./travis-run-tests.sh $TESTS
sudo: false
Regular → Executable
+1 -5
View File
@@ -38,7 +38,7 @@ Starting Keycloak
To start Keycloak during development first build as specified above, then run:
mvn -f testsuite/utils/pom.xml exec:java -Pkeycloak-server
mvn -f testsuite/integration/pom.xml exec:java -Pkeycloak-server
To start Keycloak from the server distribution first build the distribution it as specified above, then run:
@@ -49,10 +49,6 @@ To start Keycloak from the server distribution first build the distribution it a
To stop the server press `Ctrl + C`.
Reporting security vulnerabilities
----------------------------------
If you've found a security vulnerability, please look at the [instructions on how to properly report it](http://www.keycloak.org/security.html)
Help and Documentation
----------------------
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -164,12 +164,7 @@ public class BearerTokenRequestAuthenticator {
OIDCAuthenticationError error = new OIDCAuthenticationError(reason, description);
facade.getRequest().setError(error);
facade.getResponse().addHeader("WWW-Authenticate", challenge);
if(deployment.isDelegateBearerErrorResponseSending()){
facade.getResponse().setStatus(401);
}
else {
facade.getResponse().sendError(401);
}
facade.getResponse().sendError(401);
return true;
}
};
@@ -94,8 +94,6 @@ public class KeycloakDeployment {
protected Map<String, String> redirectRewriteRules;
protected boolean delegateBearerErrorResponseSending = false;
public KeycloakDeployment() {
}
@@ -458,12 +456,6 @@ public class KeycloakDeployment {
public void setRewriteRedirectRules(Map<String, String> redirectRewriteRules) {
this.redirectRewriteRules = redirectRewriteRules;
}
public boolean isDelegateBearerErrorResponseSending() {
return delegateBearerErrorResponseSending;
}
public void setDelegateBearerErrorResponseSending(boolean delegateBearerErrorResponseSending) {
this.delegateBearerErrorResponseSending = delegateBearerErrorResponseSending;
}
}
@@ -331,7 +331,7 @@ public class OAuthRequestAuthenticator {
} catch (ServerRequest.HttpFailure failure) {
log.error("failed to turn code into token");
log.error("status from server: " + failure.getStatus());
if (failure.getError() != null) {
if (failure.getStatus() == 400 && failure.getError() != null) {
log.error(" " + failure.getError());
}
return challenge(403, OIDCAuthenticationError.Reason.CODE_TO_TOKEN_FAILURE, null);
@@ -155,9 +155,7 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext
this.refreshToken = response.getRefreshToken();
}
this.tokenString = tokenString;
if (tokenStore != null) {
tokenStore.refreshCallback(this);
}
tokenStore.refreshCallback(this);
return true;
}
@@ -89,7 +89,7 @@ class PathMatcher {
pathString = "/";
}
if (matchingUri.equals(targetUri) || pathString.equals(targetUri)) {
if (matchingUri.equals(targetUri)) {
cache.put(targetUri, entry);
return entry;
}
@@ -37,12 +37,8 @@ import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.Principal;
import java.util.HashSet;
import java.util.Map;
@@ -57,7 +53,7 @@ public abstract class AbstractKeycloakLoginModule implements LoginModule {
public static final String KEYCLOAK_CONFIG_FILE_OPTION = "keycloak-config-file";
public static final String ROLE_PRINCIPAL_CLASS_OPTION = "role-principal-class";
public static final String PROFILE_RESOURCE = "profile:";
protected Subject subject;
protected CallbackHandler callbackHandler;
protected Auth auth;
@@ -88,27 +84,14 @@ public abstract class AbstractKeycloakLoginModule implements LoginModule {
protected KeycloakDeployment resolveDeployment(String keycloakConfigFile) {
try {
InputStream is = null;
if (keycloakConfigFile.startsWith(PROFILE_RESOURCE)) {
try {
is = new URL(keycloakConfigFile).openStream();
} catch (MalformedURLException mfue) {
throw new RuntimeException(mfue);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
} else {
is = FindFile.findFile(keycloakConfigFile);
}
InputStream is = FindFile.findFile(keycloakConfigFile);
KeycloakDeployment kd = KeycloakDeploymentBuilder.build(is);
return kd;
} catch (RuntimeException e) {
getLogger().debug("Unable to find or parse file " + keycloakConfigFile + " due to " + e.getMessage(), e);
throw e;
}
}
@Override
public boolean login() throws LoginException {
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-as7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-as7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -1,13 +0,0 @@
package org.keycloak.adapters.jbossweb;
import org.apache.catalina.Container;
import org.apache.catalina.Valve;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.tomcat.AbstractAuthenticatedActionsValve;
public class AuthenticatedActionsValve extends AbstractAuthenticatedActionsValve {
public AuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
super(deploymentContext, next, container);
}
}
@@ -17,15 +17,11 @@
package org.keycloak.adapters.jbossweb;
import org.apache.catalina.Container;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Valve;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.deploy.LoginConfig;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.tomcat.AbstractAuthenticatedActionsValve;
import org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve;
import org.keycloak.adapters.tomcat.GenericPrincipalFactory;
@@ -60,6 +56,7 @@ public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorVal
super.start();
}
public void logout(Request request) {
logoutInternal(request);
}
@@ -68,9 +65,4 @@ public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorVal
protected GenericPrincipalFactory createPrincipalFactory() {
return new JBossWebPrincipalFactory();
}
@Override
protected AbstractAuthenticatedActionsValve createAuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
return new AuthenticatedActionsValve(deploymentContext, next, container);
}
}
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-as7-integration-pom</artifactId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak AS7 / JBoss EAP 6 Integration</name>
-9
View File
@@ -1,9 +0,0 @@
CLI Single Sign On
===================================
This java-based utility is meant for providing Keycloak integration to
command line applications that are either written in Java or another language. The
idea is that the Java app provided by this utility performs a login for a specific
client, parses responses, and exports an access token as an environment variable
that can be used by the command line utility you are accessing.
-10
View File
@@ -1,10 +0,0 @@
#!/bin/sh
export KC_AUTH_SERVER=http://localhost:8080/auth
export KC_REALM=master
export KC_CLIENT=cli
export KC_ACCESS_TOKEN=`java -DKEYCLOAK_AUTH_SERVER=$KC_AUTH_SERVER -DKEYCLOAK_REALM=$KC_REALM -DKEYCLOAK_CLIENT=$KC_CLIENT -jar target/keycloak-cli-sso-3.3.0.CR1-SNAPSHOT.jar login`
-9
View File
@@ -1,9 +0,0 @@
#!/bin/sh
java -DKEYCLOAK_AUTH_SERVER=$KC_AUTH_SERVER -DKEYCLOAK_REALM=$KC_REALM -DKEYCLOAK_CLIENT=$KC_CLIENT -jar target/keycloak-cli-sso-3.3.0.CR1-SNAPSHOT.jar logout
unset KC_ACCESS_TOKEN
-84
View File
@@ -1,84 +0,0 @@
<?xml version="1.0"?>
<!--
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
~ and other contributors as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-cli-sso</artifactId>
<name>Keycloak CLI SSO Framework</name>
<description/>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-installed-adapter</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.keycloak.adapters.KeycloakCliSsoMain</mainClass>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -1,45 +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.adapters;
import org.keycloak.adapters.installed.KeycloakCliSso;
import org.keycloak.adapters.installed.KeycloakInstalled;
import org.keycloak.common.util.Time;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.keycloak.util.JsonSerialization;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakCliSsoMain extends KeycloakCliSso {
public static void main(String[] args) throws Exception {
new KeycloakCliSsoMain().mainCmd(args);
}
}
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -1,266 +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.adapters.installed;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.adapters.ServerRequest;
import org.keycloak.common.util.Time;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.keycloak.util.JsonSerialization;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
*
*
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakCliSso {
public void mainCmd(String[] args) throws Exception {
if (args.length != 1) {
printHelp();
return;
}
if (args[0].equalsIgnoreCase("login")) {
login();
} else if (args[0].equalsIgnoreCase("login-manual")) {
loginManual();
} else if (args[0].equalsIgnoreCase("token")) {
token();
} else if (args[0].equalsIgnoreCase("logout")) {
logout();
} else if (args[0].equalsIgnoreCase("env")) {
System.out.println(System.getenv().toString());
} else {
printHelp();
}
}
public void printHelp() {
System.err.println("Commands:");
System.err.println(" login - login with desktop browser if available, otherwise do manual login. Output is access token.");
System.err.println(" login-manual - manual login");
System.err.println(" token - print access token if logged in");
System.err.println(" logout - logout.");
System.exit(1);
}
public AdapterConfig getConfig() {
String url = System.getProperty("KEYCLOAK_AUTH_SERVER");
if (url == null) {
System.err.println("KEYCLOAK_AUTH_SERVER property not set");
System.exit(1);
}
String realm = System.getProperty("KEYCLOAK_REALM");
if (realm == null) {
System.err.println("KEYCLOAK_REALM property not set");
System.exit(1);
}
String client = System.getProperty("KEYCLOAK_CLIENT");
if (client == null) {
System.err.println("KEYCLOAK_CLIENT property not set");
System.exit(1);
}
String secret = System.getProperty("KEYCLOAK_CLIENT_SECRET");
AdapterConfig config = new AdapterConfig();
config.setAuthServerUrl(url);
config.setRealm(realm);
config.setResource(client);
config.setSslRequired("external");
if (secret != null) {
Map<String, Object> creds = new HashMap<>();
creds.put("secret", secret);
config.setCredentials(creds);
} else {
config.setPublicClient(true);
}
return config;
}
public boolean checkToken() throws Exception {
String token = getTokenResponse();
if (token == null) return false;
if (token != null) {
Matcher m = Pattern.compile("\\{.*\\}\\z").matcher(token);
if (m.find()) {
String json = m.group(0);
try {
AccessTokenResponse tokenResponse = JsonSerialization.readValue(json, AccessTokenResponse.class);
if (Time.currentTime() < tokenResponse.getExpiresIn()) {
return true;
}
AdapterConfig config = getConfig();
KeycloakInstalled installed = new KeycloakInstalled(KeycloakDeploymentBuilder.build(config));
installed.refreshToken(tokenResponse.getRefreshToken());
processResponse(installed);
return true;
} catch (Exception e) {
System.err.println("Error processing existing token");
e.printStackTrace();
}
}
}
return false;
}
private String getTokenResponse() throws IOException {
String token = null;
File tokenFile = getTokenFilePath();
if (tokenFile.exists()) {
FileInputStream fis = new FileInputStream(tokenFile);
byte[] data = new byte[(int) tokenFile.length()];
fis.read(data);
fis.close();
token = new String(data, "UTF-8");
}
return token;
}
public void token() throws Exception {
String token = getTokenResponse();
if (token == null) {
System.err.println("There is no token for client");
System.exit(1);
} else {
Matcher m = Pattern.compile("\\{.*\\}\\z").matcher(token);
if (m.find()) {
String json = m.group(0);
try {
AccessTokenResponse tokenResponse = JsonSerialization.readValue(json, AccessTokenResponse.class);
if (Time.currentTime() < tokenResponse.getExpiresIn()) {
System.out.println(tokenResponse.getToken());
return;
} else {
System.err.println("token in response file is expired");
System.exit(1);
}
} catch (Exception e) {
System.err.println("Failure processing token response file");
e.printStackTrace();
System.exit(1);
}
} else {
System.err.println("Could not find json within token response file");
System.exit(1);
}
}
}
public void login() throws Exception {
if (checkToken()) return;
AdapterConfig config = getConfig();
KeycloakInstalled installed = new KeycloakInstalled(KeycloakDeploymentBuilder.build(config));
installed.login();
processResponse(installed);
}
public String getHome() {
String home = System.getenv("HOME");
if (home == null) {
home = System.getProperty("HOME");
if (home == null) {
home = Paths.get("").toAbsolutePath().normalize().toString();
}
}
return home;
}
public File getTokenDirectory() {
return Paths.get(getHome(), System.getProperty("basepath", ".keycloak-sso"), System.getProperty("KEYCLOAK_REALM")).toFile();
}
public File getTokenFilePath() {
return Paths.get(getHome(), System.getProperty("basepath", ".keycloak-sso"), System.getProperty("KEYCLOAK_REALM"), System.getProperty("KEYCLOAK_CLIENT") + ".json").toFile();
}
private void processResponse(KeycloakInstalled installed) throws IOException {
AccessTokenResponse tokenResponse = installed.getTokenResponse();
tokenResponse.setExpiresIn(Time.currentTime() + tokenResponse.getExpiresIn());
tokenResponse.setIdToken(null);
String output = JsonSerialization.writeValueAsString(tokenResponse);
getTokenDirectory().mkdirs();
FileOutputStream fos = new FileOutputStream(getTokenFilePath());
fos.write(output.getBytes("UTF-8"));
fos.flush();
fos.close();
System.out.println(tokenResponse.getToken());
}
public void loginManual() throws Exception {
if (checkToken()) return;
AdapterConfig config = getConfig();
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(config);
KeycloakInstalled installed = new KeycloakInstalled(deployment);
installed.loginManual();
processResponse(installed);
}
public void logout() throws Exception {
String token = getTokenResponse();
if (token != null) {
Matcher m = Pattern.compile("\\{.*\\}\\z").matcher(token);
if (m.find()) {
String json = m.group(0);
try {
AccessTokenResponse tokenResponse = JsonSerialization.readValue(json, AccessTokenResponse.class);
if (Time.currentTime() > tokenResponse.getExpiresIn()) {
System.err.println("Login is expired");
System.exit(1);
}
AdapterConfig config = getConfig();
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(config);
ServerRequest.invokeLogout(deployment, tokenResponse.getRefreshToken());
for (File fp : getTokenDirectory().listFiles()) fp.delete();
System.out.println("logout complete");
} catch (Exception e) {
System.err.println("Failure processing token response file");
e.printStackTrace();
System.exit(1);
}
} else {
System.err.println("Could not find json within token response file");
System.exit(1);
}
} else {
System.err.println("Not logged in");
System.exit(1);
}
}
}
@@ -17,7 +17,6 @@
package org.keycloak.adapters.installed;
import org.apache.commons.codec.Charsets;
import org.keycloak.OAuth2Constants;
import org.keycloak.OAuthErrorException;
import org.keycloak.adapters.KeycloakDeployment;
@@ -25,7 +24,6 @@ import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.adapters.ServerRequest;
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
import org.keycloak.common.VerificationException;
import org.keycloak.common.util.KeycloakUriBuilder;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.JWSInputException;
import org.keycloak.representations.AccessToken;
@@ -45,7 +43,6 @@ import java.net.ServerSocket;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Locale;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@@ -54,11 +51,6 @@ import java.util.concurrent.TimeUnit;
*/
public class KeycloakInstalled {
public interface HttpResponseWriter {
void success(PrintWriter pw, KeycloakInstalled ki);
void failure(PrintWriter pw, KeycloakInstalled ki);
}
private static final String KEYCLOAK_JSON = "META-INF/keycloak.json";
private KeycloakDeployment deployment;
@@ -67,18 +59,12 @@ public class KeycloakInstalled {
LOGGED_MANUAL, LOGGED_DESKTOP
}
private AccessTokenResponse tokenResponse;
private String tokenString;
private String idTokenString;
private IDToken idToken;
private AccessToken token;
private String refreshToken;
private Status status;
private Locale locale;
private HttpResponseWriter loginResponseWriter;
private HttpResponseWriter logoutResponseWriter;
public KeycloakInstalled() {
InputStream config = Thread.currentThread().getContextClassLoader().getResourceAsStream(KEYCLOAK_JSON);
@@ -89,92 +75,6 @@ public class KeycloakInstalled {
deployment = KeycloakDeploymentBuilder.build(config);
}
public KeycloakInstalled(KeycloakDeployment deployment) {
this.deployment = deployment;
}
private static HttpResponseWriter defaultLoginWriter = new HttpResponseWriter() {
@Override
public void success(PrintWriter pw, KeycloakInstalled ki) {
pw.println("HTTP/1.1 200 OK");
pw.println("Content-Type: text/html");
pw.println();
pw.println("<html><h1>Login completed.</h1><div>");
pw.println("This browser will remain logged in until you close it, logout, or the session expires.");
pw.println("</div></html>");
pw.flush();
}
@Override
public void failure(PrintWriter pw, KeycloakInstalled ki) {
pw.println("HTTP/1.1 200 OK");
pw.println("Content-Type: text/html");
pw.println();
pw.println("<html><h1>Login attempt failed.</h1><div>");
pw.println("</div></html>");
pw.flush();
}
};
private static HttpResponseWriter defaultLogoutWriter = new HttpResponseWriter() {
@Override
public void success(PrintWriter pw, KeycloakInstalled ki) {
pw.println("HTTP/1.1 200 OK");
pw.println("Content-Type: text/html");
pw.println();
pw.println("<html><h1>Logout completed.</h1><div>");
pw.println("You may close this browser tab.");
pw.println("</div></html>");
pw.flush();
}
@Override
public void failure(PrintWriter pw, KeycloakInstalled ki) {
pw.println("HTTP/1.1 200 OK");
pw.println("Content-Type: text/html");
pw.println();
pw.println("<html><h1>Logout failed.</h1><div>");
pw.println("You may close this browser tab.");
pw.println("</div></html>");
pw.flush();
}
};
public HttpResponseWriter getLoginResponseWriter() {
if (loginResponseWriter == null) {
return defaultLoginWriter;
} else {
return loginResponseWriter;
}
}
public HttpResponseWriter getLogoutResponseWriter() {
if (logoutResponseWriter == null) {
return defaultLogoutWriter;
} else {
return logoutResponseWriter;
}
}
public void setLoginResponseWriter(HttpResponseWriter loginResponseWriter) {
this.loginResponseWriter = loginResponseWriter;
}
public void setLogoutResponseWriter(HttpResponseWriter logoutResponseWriter) {
this.logoutResponseWriter = logoutResponseWriter;
}
public Locale getLocale() {
return locale;
}
public void setLocale(Locale locale) {
this.locale = locale;
}
public void login() throws IOException, ServerRequest.HttpFailure, VerificationException, InterruptedException, OAuthErrorException, URISyntaxException {
if (isDesktopSupported()) {
loginDesktop();
@@ -208,22 +108,19 @@ public class KeycloakInstalled {
}
public void loginDesktop() throws IOException, VerificationException, OAuthErrorException, URISyntaxException, ServerRequest.HttpFailure, InterruptedException {
CallbackListener callback = new CallbackListener(getLoginResponseWriter());
CallbackListener callback = new CallbackListener();
callback.start();
String redirectUri = "http://localhost:" + callback.server.getLocalPort();
String state = UUID.randomUUID().toString();
KeycloakUriBuilder builder = deployment.getAuthUrl().clone()
String authUrl = deployment.getAuthUrl().clone()
.queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE)
.queryParam(OAuth2Constants.CLIENT_ID, deployment.getResourceName())
.queryParam(OAuth2Constants.REDIRECT_URI, redirectUri)
.queryParam(OAuth2Constants.STATE, state)
.queryParam(OAuth2Constants.SCOPE, OAuth2Constants.SCOPE_OPENID);
if (locale != null) {
builder.queryParam(OAuth2Constants.UI_LOCALES_PARAM, locale.getLanguage());
}
String authUrl = builder.build().toString();
.queryParam(OAuth2Constants.SCOPE, OAuth2Constants.SCOPE_OPENID)
.build().toString();
Desktop.getDesktop().browse(new URI(authUrl));
@@ -247,7 +144,7 @@ public class KeycloakInstalled {
}
private void logoutDesktop() throws IOException, URISyntaxException, InterruptedException {
CallbackListener callback = new CallbackListener(getLogoutResponseWriter());
CallbackListener callback = new CallbackListener();
callback.start();
String redirectUri = "http://localhost:" + callback.server.getLocalPort();
@@ -270,6 +167,9 @@ public class KeycloakInstalled {
}
public void loginManual(PrintStream printer, Reader reader) throws IOException, ServerRequest.HttpFailure, VerificationException {
CallbackListener callback = new CallbackListener();
callback.start();
String redirectUri = "urn:ietf:wg:oauth:2.0:oob";
String authUrl = deployment.getAuthUrl().clone()
@@ -308,14 +208,7 @@ public class KeycloakInstalled {
parseAccessToken(tokenResponse);
}
public void refreshToken(String refreshToken) throws IOException, ServerRequest.HttpFailure, VerificationException {
AccessTokenResponse tokenResponse = ServerRequest.invokeRefresh(deployment, refreshToken);
parseAccessToken(tokenResponse);
}
private void parseAccessToken(AccessTokenResponse tokenResponse) throws VerificationException {
this.tokenResponse = tokenResponse;
tokenString = tokenResponse.getToken();
refreshToken = tokenResponse.getRefreshToken();
idTokenString = tokenResponse.getIdToken();
@@ -347,10 +240,6 @@ public class KeycloakInstalled {
return refreshToken;
}
public AccessTokenResponse getTokenResponse() {
return tokenResponse;
}
public boolean isDesktopSupported() {
return Desktop.isDesktopSupported();
}
@@ -359,8 +248,6 @@ public class KeycloakInstalled {
return deployment;
}
private void processCode(String code, String redirectUri) throws IOException, ServerRequest.HttpFailure, VerificationException {
AccessTokenResponse tokenResponse = ServerRequest.invokeAccessCodeToToken(deployment, code, redirectUri, null);
parseAccessToken(tokenResponse);
@@ -382,7 +269,6 @@ public class KeycloakInstalled {
return sb.toString();
}
public class CallbackListener extends Thread {
private ServerSocket server;
@@ -397,19 +283,14 @@ public class KeycloakInstalled {
private String state;
private Socket socket;
private HttpResponseWriter writer;
public CallbackListener(HttpResponseWriter writer) throws IOException {
this.writer = writer;
public CallbackListener() throws IOException {
server = new ServerSocket(0);
}
@Override
public void run() {
try {
socket = server.accept();
Socket socket = server.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String request = br.readLine();
@@ -433,15 +314,10 @@ public class KeycloakInstalled {
}
}
OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream());
PrintWriter pw = new PrintWriter(out);
if (error == null) {
writer.success(pw, KeycloakInstalled.this);
} else {
writer.failure(pw, KeycloakInstalled.this);
}
PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
pw.println("Please close window and return to application");
pw.flush();
socket.close();
} catch (IOException e) {
errorException = e;
@@ -452,8 +328,6 @@ public class KeycloakInstalled {
} catch (IOException e) {
}
}
}
}
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak Jetty Integration</name>
+1 -6
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -38,11 +38,6 @@
<plugin>
<groupId>com.samaxes.maven</groupId>
<artifactId>minify-maven-plugin</artifactId>
<configuration>
<jsEngine>CLOSURE</jsEngine>
<closureLanguageIn>ECMASCRIPT5</closureLanguageIn>
<closureCreateSourceMap>true</closureCreateSourceMap>
</configuration>
<executions>
<execution>
<id>min-js</id>
@@ -33,13 +33,6 @@
interval: 5
};
var scripts = document.getElementsByTagName('script');
for (var i = 0; i < scripts.length; i++) {
if ((scripts[i].src.indexOf('keycloak.js') !== -1 || scripts[i].src.indexOf('keycloak.min.js') !== -1) && scripts[i].src.indexOf('version=') !== -1) {
kc.iframeVersion = scripts[i].src.substring(scripts[i].src.indexOf('version=') + 8).split('&')[0];
}
}
kc.init = function (initOptions) {
kc.authenticated = false;
@@ -50,7 +43,7 @@
} else if (initOptions && initOptions.adapter === 'default') {
adapter = loadAdapter();
} else {
if (window.Cordova || window.cordova) {
if (window.Cordova) {
adapter = loadAdapter('cordova');
} else {
adapter = loadAdapter();
@@ -221,7 +214,7 @@
var callbackState = {
state: state,
nonce: nonce,
redirectUri: encodeURIComponent(redirectUri)
redirectUri: encodeURIComponent(redirectUri),
}
if (options && options.prompt) {
@@ -838,12 +831,7 @@
}
var src = getRealmUrl() + '/protocol/openid-connect/login-status-iframe.html';
if (kc.iframeVersion) {
src = src + '?version=' + kc.iframeVersion;
}
iframe.setAttribute('src', src );
iframe.setAttribute('title', 'keycloak-session-iframe' );
iframe.style.display = 'none';
document.body.appendChild(iframe);
@@ -948,14 +936,7 @@
if (type == 'cordova') {
loginIframe.enable = false;
var cordovaOpenWindowWrapper = function(loginUrl, target, options) {
if (window.cordova && window.cordova.InAppBrowser) {
// Use inappbrowser for IOS and Android if available
return window.cordova.InAppBrowser.open(loginUrl, target, options);
} else {
return window.open(loginUrl, target, options);
}
};
return {
login: function(options) {
var promise = createPromise();
@@ -966,7 +947,8 @@
}
var loginUrl = kc.createLoginUrl(options);
var ref = cordovaOpenWindowWrapper(loginUrl, '_blank', o);
var ref = window.open(loginUrl, '_blank', o);
var completed = false;
ref.addEventListener('loadstart', function(event) {
@@ -999,7 +981,7 @@
var promise = createPromise();
var logoutUrl = kc.createLogoutUrl(options);
var ref = cordovaOpenWindowWrapper(logoutUrl, '_blank', 'location=no,hidden=yes');
var ref = window.open(logoutUrl, '_blank', 'location=no,hidden=yes');
var error;
@@ -1032,7 +1014,7 @@
register : function() {
var registerUrl = kc.createRegisterUrl();
var ref = cordovaOpenWindowWrapper(registerUrl, '_blank', 'location=no');
var ref = window.open(registerUrl, '_blank', 'location=no');
ref.addEventListener('loadstart', function(event) {
if (event.url.indexOf('http://localhost') == 0) {
ref.close();
@@ -1042,7 +1024,7 @@
accountManagement : function() {
var accountUrl = kc.createAccountUrl();
var ref = cordovaOpenWindowWrapper(accountUrl, '_blank', 'location=no');
var ref = window.open(accountUrl, '_blank', 'location=no');
ref.addEventListener('loadstart', function(event) {
if (event.url.indexOf('http://localhost') == 0) {
ref.close();
@@ -28,7 +28,7 @@
} else if (!init) {
var req = new XMLHttpRequest();
var url = location.href.split("?")[0] + "/init";
var url = location.href + "/init";
url += "?client_id=" + encodeURIComponent(clientId);
url += "&origin=" + encodeURIComponent(origin);
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -2
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<name>Keycloak OIDC Client Adapter Modules</name>
@@ -34,7 +34,6 @@
<module>adapter-core</module>
<module>as7-eap6</module>
<module>installed</module>
<module>cli-sso</module>
<module>jaxrs-oauth-client</module>
<module>jetty</module>
<module>js</module>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -4,7 +4,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<artifactId>spring-boot-container-bundle</artifactId>
+3 -17
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -31,9 +31,7 @@
<description/>
<properties>
<spring-boot.version>1.4.0.RELEASE</spring-boot.version>
<spring.version>4.1.6.RELEASE</spring.version>
<mockito.version>1.9.5</mockito.version>
<spring-boot.version>1.3.0.RELEASE</spring-boot.version>
</properties>
<dependencies>
@@ -100,19 +98,7 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
@@ -1,24 +0,0 @@
package org.keycloak.adapters.springboot.client;
import org.springframework.boot.web.client.RestTemplateCustomizer;
import org.springframework.web.client.RestTemplate;
public class KeycloakRestTemplateCustomizer implements RestTemplateCustomizer {
private final KeycloakSecurityContextClientRequestInterceptor keycloakInterceptor;
public KeycloakRestTemplateCustomizer() {
this(new KeycloakSecurityContextClientRequestInterceptor());
}
protected KeycloakRestTemplateCustomizer(
KeycloakSecurityContextClientRequestInterceptor keycloakInterceptor
) {
this.keycloakInterceptor = keycloakInterceptor;
}
@Override
public void customize(RestTemplate restTemplate) {
restTemplate.getInterceptors().add(keycloakInterceptor);
}
}
@@ -1,55 +0,0 @@
package org.keycloak.adapters.springboot.client;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.KeycloakSecurityContext;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.io.IOException;
import java.security.Principal;
/**
* Interceptor for {@link ClientHttpRequestExecution} objects created for server to server secured
* communication using OAuth2 bearer tokens issued by Keycloak.
*
* @author <a href="mailto:jmcshan1@gmail.com">James McShane</a>
* @version $Revision: 1 $
*/
public class KeycloakSecurityContextClientRequestInterceptor implements ClientHttpRequestInterceptor {
private static final String AUTHORIZATION_HEADER = "Authorization";
/**
* Returns the {@link KeycloakSecurityContext} from the Spring {@link ServletRequestAttributes}'s {@link Principal}.
*
* The principal must support retrieval of the KeycloakSecurityContext, so at this point, only {@link KeycloakPrincipal}
* values are supported
*
* @return the current <code>KeycloakSecurityContext</code>
*/
protected KeycloakSecurityContext getKeycloakSecurityContext() {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
Principal principal = attributes.getRequest().getUserPrincipal();
if (principal == null) {
throw new IllegalStateException("Cannot set authorization header because there is no authenticated principal");
}
if (!(principal instanceof KeycloakPrincipal)) {
throw new IllegalStateException(
String.format(
"Cannot set authorization header because the principal type %s does not provide the KeycloakSecurityContext",
principal.getClass()));
}
return ((KeycloakPrincipal) principal).getKeycloakSecurityContext();
}
@Override
public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
KeycloakSecurityContext context = this.getKeycloakSecurityContext();
httpRequest.getHeaders().set(AUTHORIZATION_HEADER, "Bearer " + context.getTokenString());
return clientHttpRequestExecution.execute(httpRequest, bytes);
}
}
@@ -1,28 +0,0 @@
package org.keycloak.adapters.springboot.client;
import org.junit.Before;
import org.junit.Test;
import org.springframework.web.client.RestTemplate;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
public class KeycloakRestTemplateCustomizerTest {
private KeycloakRestTemplateCustomizer customizer;
private KeycloakSecurityContextClientRequestInterceptor interceptor =
mock(KeycloakSecurityContextClientRequestInterceptor.class);
@Before
public void setup() {
customizer = new KeycloakRestTemplateCustomizer(interceptor);
}
@Test
public void interceptorIsAddedToRequest() {
RestTemplate restTemplate = new RestTemplate();
customizer.customize(restTemplate);
assertTrue(restTemplate.getInterceptors().contains(interceptor));
}
}
@@ -1,87 +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.adapters.springboot.client;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.KeycloakSecurityContext;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.security.Principal;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.when;
/**
* Keycloak spring boot client request factory tests.
*/
public class KeycloakSecurityContextClientRequestInterceptorTest {
@Spy
private KeycloakSecurityContextClientRequestInterceptor factory;
private MockHttpServletRequest servletRequest;
@Mock
private KeycloakSecurityContext keycloakSecurityContext;
@Mock
private KeycloakPrincipal keycloakPrincipal;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
servletRequest = new MockHttpServletRequest();
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(servletRequest));
servletRequest.setUserPrincipal(keycloakPrincipal);
when(keycloakPrincipal.getKeycloakSecurityContext()).thenReturn(keycloakSecurityContext);
}
@Test
public void testGetKeycloakSecurityContext() throws Exception {
KeycloakSecurityContext context = factory.getKeycloakSecurityContext();
assertNotNull(context);
assertEquals(keycloakSecurityContext, context);
}
@Test(expected = IllegalStateException.class)
public void testGetKeycloakSecurityContextInvalidPrincipal() throws Exception {
servletRequest.setUserPrincipal(new MarkerPrincipal());
factory.getKeycloakSecurityContext();
}
@Test(expected = IllegalStateException.class)
public void testGetKeycloakSecurityContextNullAuthentication() throws Exception {
servletRequest.setUserPrincipal(null);
factory.getKeycloakSecurityContext();
}
private static class MarkerPrincipal implements Principal {
@Override
public String getName() {
return null;
}
}
}
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -17,13 +17,14 @@
package org.keycloak.adapters.springsecurity.authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
/**
* To return the forbidden code with the corresponding message.
@@ -35,14 +36,6 @@ public class KeycloakAuthenticationFailureHandler implements AuthenticationFailu
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
// Check that the response was not committed yet (this may happen when another
// part of the Keycloak adapter sends a challenge or a redirect).
if (!response.isCommitted()) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unable to authenticate using the Authorization header");
} else {
if (200 <= response.getStatus() && response.getStatus() < 300) {
throw new RuntimeException("Success response was committed while authentication failed!", exception);
}
}
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unable to authenticate using the Authorization header");
}
}
@@ -50,7 +50,7 @@ public class KeycloakAuthenticationProvider implements AuthenticationProvider {
for (String role : token.getAccount().getRoles()) {
grantedAuthorities.add(new KeycloakRole(role));
}
return new KeycloakAuthenticationToken(token.getAccount(), token.isInteractive(), mapAuthorities(grantedAuthorities));
return new KeycloakAuthenticationToken(token.getAccount(), mapAuthorities(grantedAuthorities));
}
private Collection<? extends GrantedAuthority> mapAuthorities(
@@ -94,7 +94,7 @@ public class SpringSecurityRequestAuthenticator extends RequestAuthenticator {
logger.debug("Completing bearer authentication. Bearer roles: {} ",roles);
SecurityContextHolder.getContext().setAuthentication(new KeycloakAuthenticationToken(account, false));
SecurityContextHolder.getContext().setAuthentication(new KeycloakAuthenticationToken(account));
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
}
@@ -19,9 +19,6 @@ package org.keycloak.adapters.springsecurity.facade;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.spi.KeycloakAccount;
import org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.Assert;
@@ -60,8 +57,7 @@ public class SimpleHttpFacade implements OIDCHttpFacade {
SecurityContext context = SecurityContextHolder.getContext();
if (context != null && context.getAuthentication() != null) {
KeycloakAuthenticationToken authentication = (KeycloakAuthenticationToken) context.getAuthentication();
return authentication.getAccount().getKeycloakSecurityContext();
return (KeycloakSecurityContext) context.getAuthentication().getDetails();
}
return null;
@@ -24,7 +24,6 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.keycloak.OAuth2Constants;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment;
@@ -37,7 +36,6 @@ import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticatio
import org.keycloak.adapters.springsecurity.authentication.SpringSecurityRequestAuthenticator;
import org.keycloak.adapters.springsecurity.facade.SimpleHttpFacade;
import org.keycloak.adapters.springsecurity.token.AdapterTokenStoreFactory;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.keycloak.adapters.springsecurity.token.SpringSecurityAdapterTokenStoreFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,19 +61,19 @@ import org.springframework.util.Assert;
* @version $Revision: 1 $
*/
public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter implements ApplicationContextAware {
public static final String DEFAULT_LOGIN_URL = "/sso/login";
public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String SCHEME_BEARER = "bearer ";
public static final String SCHEME_BASIC = "basic ";
/**
* Request matcher that matches requests to the {@link KeycloakAuthenticationEntryPoint#DEFAULT_LOGIN_URI default login URI}
* and any request with a <code>Authorization</code> header.
*/
public static final RequestMatcher DEFAULT_REQUEST_MATCHER =
new OrRequestMatcher(
new AntPathRequestMatcher(DEFAULT_LOGIN_URL),
new RequestHeaderRequestMatcher(AUTHORIZATION_HEADER),
new QueryParamPresenceRequestMatcher(OAuth2Constants.ACCESS_TOKEN)
);
new OrRequestMatcher(new AntPathRequestMatcher(DEFAULT_LOGIN_URL), new RequestHeaderRequestMatcher(AUTHORIZATION_HEADER));
private static final Logger log = LoggerFactory.getLogger(KeycloakAuthenticationProcessingFilter.class);
@@ -136,10 +134,6 @@ public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticati
HttpFacade facade = new SimpleHttpFacade(request, response);
KeycloakDeployment deployment = adapterDeploymentContext.resolveDeployment(facade);
// using Spring authenticationFailureHandler
deployment.setDelegateBearerErrorResponseSending(true);
AdapterTokenStore tokenStore = adapterTokenStoreFactory.createAdapterTokenStore(deployment, request);
RequestAuthenticator authenticator
= new SpringSecurityRequestAuthenticator(facade, request, deployment, tokenStore, -1);
@@ -183,10 +177,36 @@ public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticati
}
}
/**
* Returns true if the request was made with a bearer token authorization header.
*
* @param request the current <code>HttpServletRequest</code>
*
* @return <code>true</code> if the <code>request</code> was made with a bearer token authorization header;
* <code>false</code> otherwise.
*/
protected boolean isBearerTokenRequest(HttpServletRequest request) {
String authValue = request.getHeader(AUTHORIZATION_HEADER);
return authValue != null && authValue.toLowerCase().startsWith(SCHEME_BEARER);
}
/**
* Returns true if the request was made with a Basic authentication authorization header.
*
* @param request the current <code>HttpServletRequest</code>
* @return <code>true</code> if the <code>request</code> was made with a Basic authentication authorization header;
* <code>false</code> otherwise.
*/
protected boolean isBasicAuthRequest(HttpServletRequest request) {
String authValue = request.getHeader(AUTHORIZATION_HEADER);
return authValue != null && authValue.toLowerCase().startsWith(SCHEME_BASIC);
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException {
if (authResult instanceof KeycloakAuthenticationToken && ((KeycloakAuthenticationToken) authResult).isInteractive()) {
if (!(this.isBearerTokenRequest(request) || this.isBasicAuthRequest(request))) {
super.successfulAuthentication(request, response, chain, authResult);
return;
}
@@ -207,6 +227,7 @@ public class KeycloakAuthenticationProcessingFilter extends AbstractAuthenticati
} finally {
SecurityContextHolder.clearContext();
}
}
@Override
@@ -1,39 +0,0 @@
/*
* Copyright 2017 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.adapters.springsecurity.filter;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.web.util.matcher.RequestMatcher;
/**
* Spring RequestMatcher that checks for the presence of a query parameter.
*
* @author <a href="mailto:glavoie@gmail.com">Gabriel Lavoie</a>
*/
public class QueryParamPresenceRequestMatcher implements RequestMatcher {
private String param;
public QueryParamPresenceRequestMatcher(String param) {
this.param = param;
}
@Override
public boolean matches(HttpServletRequest httpServletRequest) {
return param != null && httpServletRequest.getParameter(param) != null;
}
}
@@ -38,27 +38,24 @@ import java.util.Collection;
public class KeycloakAuthenticationToken extends AbstractAuthenticationToken implements Authentication {
private Principal principal;
private boolean interactive;
/**
* Creates a new, unauthenticated Keycloak security token for the given account.
*/
public KeycloakAuthenticationToken(KeycloakAccount account, boolean interactive) {
public KeycloakAuthenticationToken(KeycloakAccount account) {
super(null);
Assert.notNull(account, "KeycloakAccount cannot be null");
Assert.notNull(account.getPrincipal(), "KeycloakAccount.getPrincipal() cannot be null");
this.principal = account.getPrincipal();
this.setDetails(account);
this.interactive = interactive;
}
public KeycloakAuthenticationToken(KeycloakAccount account, boolean interactive, Collection<? extends GrantedAuthority> authorities) {
public KeycloakAuthenticationToken(KeycloakAccount account, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
Assert.notNull(account, "KeycloakAccount cannot be null");
Assert.notNull(account.getPrincipal(), "KeycloakAccount.getPrincipal() cannot be null");
this.principal = account.getPrincipal();
this.setDetails(account);
this.interactive = interactive;
setAuthenticated(true);
}
@@ -75,8 +72,4 @@ public class KeycloakAuthenticationToken extends AbstractAuthenticationToken imp
public OidcKeycloakAccount getAccount() {
return (OidcKeycloakAccount) this.getDetails();
}
public boolean isInteractive() {
return interactive;
}
}
@@ -105,7 +105,7 @@ public class SpringSecurityTokenStore implements AdapterTokenStore {
}
logger.debug("Saving account info {}", account);
SecurityContextHolder.getContext().setAuthentication(new KeycloakAuthenticationToken(account, true));
SecurityContextHolder.getContext().setAuthentication(new KeycloakAuthenticationToken(account));
}
@Override
@@ -44,7 +44,6 @@ import static org.mockito.Mockito.mock;
public class KeycloakAuthenticationProviderTest {
private KeycloakAuthenticationProvider provider = new KeycloakAuthenticationProvider();
private KeycloakAuthenticationToken token;
private KeycloakAuthenticationToken interactiveToken;
private Set<String> roles = Sets.newSet("user", "admin");
@Before
@@ -53,18 +52,18 @@ public class KeycloakAuthenticationProviderTest {
RefreshableKeycloakSecurityContext securityContext = mock(RefreshableKeycloakSecurityContext.class);
KeycloakAccount account = new SimpleKeycloakAccount(principal, roles, securityContext);
token = new KeycloakAuthenticationToken(account, false);
interactiveToken = new KeycloakAuthenticationToken(account, true);
token = new KeycloakAuthenticationToken(account);
}
@Test
public void testAuthenticate() throws Exception {
assertAuthenticationResult(provider.authenticate(token));
}
@Test
public void testAuthenticateInteractive() throws Exception {
assertAuthenticationResult(provider.authenticate(interactiveToken));
Authentication result = provider.authenticate(token);
assertNotNull(result);
assertEquals(roles, AuthorityUtils.authorityListToSet(result.getAuthorities()));
assertTrue(result.isAuthenticated());
assertNotNull(result.getPrincipal());
assertNotNull(result.getCredentials());
assertNotNull(result.getDetails());
}
@Test
@@ -84,13 +83,4 @@ public class KeycloakAuthenticationProviderTest {
assertEquals(Sets.newSet("ROLE_USER", "ROLE_ADMIN"),
AuthorityUtils.authorityListToSet(result.getAuthorities()));
}
private void assertAuthenticationResult(Authentication result) {
assertNotNull(result);
assertEquals(roles, AuthorityUtils.authorityListToSet(result.getAuthorities()));
assertTrue(result.isAuthenticated());
assertNotNull(result.getPrincipal());
assertNotNull(result.getCredentials());
assertNotNull(result.getDetails());
}
}
@@ -1,41 +0,0 @@
package org.keycloak.adapters.springsecurity.facade;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.keycloak.adapters.spi.KeycloakAccount;
import org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.mockito.internal.util.collections.Sets;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import java.security.Principal;
import java.util.Set;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
public class SimpleHttpFacadeTest {
@Before
public void setup() {
SecurityContext springSecurityContext = SecurityContextHolder.createEmptyContext();
SecurityContextHolder.setContext(springSecurityContext);
Set<String> roles = Sets.newSet("user");
Principal principal = mock(Principal.class);
RefreshableKeycloakSecurityContext keycloakSecurityContext = mock(RefreshableKeycloakSecurityContext.class);
KeycloakAccount account = new SimpleKeycloakAccount(principal, roles, keycloakSecurityContext);
KeycloakAuthenticationToken token = new KeycloakAuthenticationToken(account, false);
springSecurityContext.setAuthentication(token);
}
@Test
public void shouldRetrieveKeycloakSecurityContext() {
SimpleHttpFacade facade = new SimpleHttpFacade(new MockHttpServletRequest(), new MockHttpServletResponse());
assertNotNull(facade.getSecurityContext());
}
}
@@ -53,6 +53,7 @@ import java.util.UUID;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -123,6 +124,34 @@ public class KeycloakAuthenticationProcessingFilterTest {
filter.afterPropertiesSet();
}
@Test
public void testIsBearerTokenRequest() throws Exception {
assertFalse(filter.isBearerTokenRequest(request));
this.setBearerAuthHeader(request);
assertTrue(filter.isBearerTokenRequest(request));
}
@Test
public void testIsBearerTokenRequestCaseInsensitive() throws Exception {
assertFalse(filter.isBearerTokenRequest(request));
this.setAuthorizationHeader(request, "bearer");
assertTrue(filter.isBearerTokenRequest(request));
}
@Test
public void testIsBasicAuthRequest() throws Exception {
assertFalse(filter.isBasicAuthRequest(request));
this.setBasicAuthHeader(request);
assertTrue(filter.isBasicAuthRequest(request));
}
@Test
public void testIsBasicAuthRequestCaseInsensitive() throws Exception {
assertFalse(filter.isBasicAuthRequest(request));
this.setAuthorizationHeader(request, "basic");
assertTrue(filter.isBasicAuthRequest(request));
}
@Test
public void testAttemptAuthenticationExpectRedirect() throws Exception {
when(keycloakDeployment.getAuthUrl()).thenReturn(KeycloakUriBuilder.fromUri("http://localhost:8080/auth"));
@@ -151,7 +180,7 @@ public class KeycloakAuthenticationProcessingFilterTest {
@Test
public void testSuccessfulAuthenticationInteractive() throws Exception {
Authentication authentication = new KeycloakAuthenticationToken(keycloakAccount, true, authorities);
Authentication authentication = new KeycloakAuthenticationToken(keycloakAccount, authorities);
filter.successfulAuthentication(request, response, chain, authentication);
verify(successHandler).onAuthenticationSuccess(eq(request), eq(response), eq(authentication));
@@ -160,7 +189,7 @@ public class KeycloakAuthenticationProcessingFilterTest {
@Test
public void testSuccessfulAuthenticationBearer() throws Exception {
Authentication authentication = new KeycloakAuthenticationToken(keycloakAccount, false, authorities);
Authentication authentication = new KeycloakAuthenticationToken(keycloakAccount, authorities);
this.setBearerAuthHeader(request);
filter.successfulAuthentication(request, response, chain, authentication);
@@ -171,7 +200,7 @@ public class KeycloakAuthenticationProcessingFilterTest {
@Test
public void testSuccessfulAuthenticationBasicAuth() throws Exception {
Authentication authentication = new KeycloakAuthenticationToken(keycloakAccount, false, authorities);
Authentication authentication = new KeycloakAuthenticationToken(keycloakAccount, authorities);
this.setBasicAuthHeader(request);
filter.successfulAuthentication(request, response, chain, authentication);
@@ -1,68 +0,0 @@
/*
* Copyright 2017 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.adapters.springsecurity.filter;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Collections;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.HttpMethod;
import org.springframework.mock.web.MockHttpServletRequest;
public class QueryParamPresenceRequestMatcherTest {
private static final String ROOT_CONTEXT_PATH = "";
private static final String VALID_PARAMETER = "access_token";
private QueryParamPresenceRequestMatcher matcher = new QueryParamPresenceRequestMatcher(VALID_PARAMETER);
private MockHttpServletRequest request;
@Before
public void setUp() throws Exception {
request = new MockHttpServletRequest();
}
@Test
public void testDoesNotMatchWithoutQueryParameter() throws Exception {
prepareRequest(HttpMethod.GET, ROOT_CONTEXT_PATH, "some/random/uri", Collections.EMPTY_MAP);
assertFalse(matcher.matches(request));
}
@Test
public void testMatchesWithValidParameter() throws Exception {
prepareRequest(HttpMethod.GET, ROOT_CONTEXT_PATH, "some/random/uri", Collections.singletonMap(VALID_PARAMETER, (Object) "123"));
assertTrue(matcher.matches(request));
}
@Test
public void testDoesNotMatchWithInvalidParameter() throws Exception {
prepareRequest(HttpMethod.GET, ROOT_CONTEXT_PATH, "some/random/uri", Collections.singletonMap("some_parameter", (Object) "123"));
assertFalse(matcher.matches(request));
}
private void prepareRequest(HttpMethod method, String contextPath, String uri, Map<String, Object> params) {
request.setMethod(method.name());
request.setContextPath(contextPath);
request.setRequestURI(contextPath + "/" + uri);
request.setParameters(params);
}
}
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak Tomcat Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -17,7 +17,11 @@
package org.keycloak.adapters.tomcat;
import org.apache.catalina.*;
import org.apache.catalina.Context;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.Manager;
import org.apache.catalina.authenticator.FormAuthenticator;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
@@ -132,7 +136,7 @@ public abstract class AbstractKeycloakAuthenticatorValve extends FormAuthenticat
}
context.getServletContext().setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext);
AbstractAuthenticatedActionsValve actions = createAuthenticatedActionsValve(deploymentContext, getNext(), getContainer());
AuthenticatedActionsValve actions = new AuthenticatedActionsValve(deploymentContext, getNext(), getContainer());
setNext(actions);
nodesRegistrationManagement = new NodesRegistrationManagement();
@@ -185,7 +189,6 @@ public abstract class AbstractKeycloakAuthenticatorValve extends FormAuthenticat
protected abstract GenericPrincipalFactory createPrincipalFactory();
protected abstract boolean forwardToErrorPageInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException;
protected abstract AbstractAuthenticatedActionsValve createAuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container);
protected boolean authenticateInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException {
CatalinaHttpFacade facade = new OIDCCatalinaHttpFacade(request, response);
@@ -31,7 +31,7 @@ import javax.servlet.ServletException;
import java.io.IOException;
/**
* Abstract base for pre-installed actions that must be authenticated
* Pre-installed actions that must be authenticated
* <p/>
* Actions include:
* <p/>
@@ -41,17 +41,18 @@ import java.io.IOException;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public abstract class AbstractAuthenticatedActionsValve extends ValveBase {
private static final Logger log = Logger.getLogger(AbstractAuthenticatedActionsValve.class);
public class AuthenticatedActionsValve extends ValveBase {
private static final Logger log = Logger.getLogger(AuthenticatedActionsValve.class);
protected AdapterDeploymentContext deploymentContext;
public AbstractAuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
public AuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
this.deploymentContext = deploymentContext;
if (next == null) throw new RuntimeException("Next valve is null!!!");
setNext(next);
setContainer(container);
}
@Override
public void invoke(Request request, Response response) throws IOException, ServletException {
log.debugv("AuthenticatedActionsValve.invoke {0}", request.getRequestURI());
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -1,12 +0,0 @@
package org.keycloak.adapters.tomcat;
import org.apache.catalina.Container;
import org.apache.catalina.Valve;
import org.keycloak.adapters.AdapterDeploymentContext;
public class AuthenticatedActionsValve extends AbstractAuthenticatedActionsValve {
public AuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
super(deploymentContext, next, container);
}
}
@@ -17,15 +17,12 @@
package org.keycloak.adapters.tomcat;
import org.apache.catalina.Container;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Valve;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.deploy.LoginConfig;
import org.apache.catalina.realm.GenericPrincipal;
import org.keycloak.adapters.AdapterDeploymentContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
@@ -54,10 +51,6 @@ public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorVal
return true;
}
@Override
protected AbstractAuthenticatedActionsValve createAuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
return new AuthenticatedActionsValve(deploymentContext, next, container);
}
@Override
public void start() throws LifecycleException {
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -1,17 +0,0 @@
package org.keycloak.adapters.tomcat;
import org.apache.catalina.Container;
import org.apache.catalina.Valve;
import org.keycloak.adapters.AdapterDeploymentContext;
public class AuthenticatedActionsValve extends AbstractAuthenticatedActionsValve {
public AuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
super(deploymentContext, next, container);
}
@Override
public boolean isAsyncSupported() {
return true;
}
}
@@ -17,14 +17,11 @@
package org.keycloak.adapters.tomcat;
import org.apache.catalina.Container;
import org.apache.catalina.Valve;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.deploy.LoginConfig;
import org.apache.catalina.realm.GenericPrincipal;
import org.keycloak.adapters.AdapterDeploymentContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
@@ -72,9 +69,4 @@ public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorVal
};
}
@Override
protected AbstractAuthenticatedActionsValve createAuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
return new AuthenticatedActionsValve(deploymentContext, next, container);
}
}
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -1,17 +0,0 @@
package org.keycloak.adapters.tomcat;
import org.apache.catalina.Container;
import org.apache.catalina.Valve;
import org.keycloak.adapters.AdapterDeploymentContext;
public class AuthenticatedActionsValve extends AbstractAuthenticatedActionsValve {
public AuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
super(deploymentContext, next, container);
}
@Override
public boolean isAsyncSupported() {
return true;
}
}
@@ -17,14 +17,11 @@
package org.keycloak.adapters.tomcat;
import org.apache.catalina.Container;
import org.apache.catalina.Valve;
import org.apache.catalina.authenticator.FormAuthenticator;
import org.apache.catalina.connector.Request;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.realm.GenericPrincipal;
import org.apache.tomcat.util.descriptor.web.LoginConfig;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.spi.HttpFacade;
@@ -105,9 +102,4 @@ public class KeycloakAuthenticatorValve extends AbstractKeycloakAuthenticatorVal
protected AdapterTokenStore getTokenStore(Request request, HttpFacade facade, KeycloakDeployment resolvedDeployment) {
return super.getTokenStore(request, facade, resolvedDeployment);
}
@Override
protected AbstractAuthenticatedActionsValve createAuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
return new AuthenticatedActionsValve(deploymentContext, next, container);
}
}
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -22,7 +22,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -50,9 +50,7 @@ import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URLDecoder;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
/**
@@ -68,7 +66,6 @@ class ElytronHttpFacade implements OIDCHttpFacade {
private ElytronAccount account;
private SecurityIdentity securityIdentity;
private boolean restored;
private final Map<String, String> headers = new HashMap<>();
public ElytronHttpFacade(HttpServerRequest request, AdapterDeploymentContext deploymentContext, CallbackHandler handler) {
this.request = request;
@@ -93,11 +90,6 @@ class ElytronHttpFacade implements OIDCHttpFacade {
void authenticationComplete() {
if (securityIdentity != null) {
HttpScope requestScope = request.getScope(Scope.EXCHANGE);
RefreshableKeycloakSecurityContext keycloakSecurityContext = account.getKeycloakSecurityContext();
requestScope.setAttachment(KeycloakSecurityContext.class.getName(), keycloakSecurityContext);
this.request.authenticationComplete(response -> {
if (!restored) {
responseConsumer.accept(response);
@@ -264,7 +256,6 @@ class ElytronHttpFacade implements OIDCHttpFacade {
@Override
public Response getResponse() {
return new Response() {
@Override
public void setStatus(final int status) {
responseConsumer = responseConsumer.andThen(response -> response.setStatusCode(status));
@@ -272,17 +263,7 @@ class ElytronHttpFacade implements OIDCHttpFacade {
@Override
public void addHeader(final String name, final String value) {
headers.put(name, value);
responseConsumer = responseConsumer.andThen(new Consumer<HttpServerResponse>() {
@Override
public void accept(HttpServerResponse response) {
String latestValue = headers.get(name);
if (latestValue.equals(value)) {
response.addResponseHeader(name, latestValue);
}
}
});
responseConsumer = responseConsumer.andThen(response -> response.addResponseHeader(name, value));
}
@Override
@@ -53,7 +53,7 @@ public class ElytronSessionTokenStore implements ElytronTokeStore {
@Override
public void checkCurrentToken() {
HttpScope session = httpFacade.getScope(Scope.SESSION);
if (session == null || !session.exists()) return;
if (!session.exists()) return;
RefreshableKeycloakSecurityContext securityContext = (RefreshableKeycloakSecurityContext) session.getAttachment(KeycloakSecurityContext.class.getName());
if (securityContext == null) return;
@@ -42,40 +42,35 @@ import java.io.InputStream;
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class KeycloakConfigurationServletListener implements ServletContextListener {
static final String ADAPTER_DEPLOYMENT_CONTEXT_ATTRIBUTE = AdapterDeploymentContext.class.getName() + ".elytron";
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext servletContext = sce.getServletContext();
String configResolverClass = servletContext.getInitParameter("keycloak.config.resolver");
KeycloakConfigResolver configResolver;
AdapterDeploymentContext deploymentContext = (AdapterDeploymentContext) servletContext.getAttribute(AdapterDeploymentContext.class.getName());
AdapterDeploymentContext deploymentContext;
if (deploymentContext == null) {
if (configResolverClass != null) {
try {
configResolver = (KeycloakConfigResolver) servletContext.getClassLoader().loadClass(configResolverClass).newInstance();
deploymentContext = new AdapterDeploymentContext(configResolver);
} catch (Exception ex) {
deploymentContext = new AdapterDeploymentContext(new KeycloakDeployment());
}
} else {
InputStream is = getConfigInputStream(servletContext);
KeycloakDeployment deployment;
if (is == null) {
deployment = new KeycloakDeployment();
} else {
deployment = KeycloakDeploymentBuilder.build(is);
}
deploymentContext = new AdapterDeploymentContext(deployment);
if (configResolverClass != null) {
try {
configResolver = (KeycloakConfigResolver) servletContext.getClassLoader().loadClass(configResolverClass).newInstance();
deploymentContext = new AdapterDeploymentContext(configResolver);
} catch (Exception ex) {
deploymentContext = new AdapterDeploymentContext(new KeycloakDeployment());
}
} else {
InputStream is = getConfigInputStream(servletContext);
KeycloakDeployment deployment;
if (is == null) {
deployment = new KeycloakDeployment();
} else {
deployment = KeycloakDeploymentBuilder.build(is);
}
deploymentContext = new AdapterDeploymentContext(deployment);
}
servletContext.setAttribute(ADAPTER_DEPLOYMENT_CONTEXT_ATTRIBUTE, deploymentContext);
servletContext.setAttribute(AdapterDeploymentContext.class.getName(), deploymentContext);
}
@Override
@@ -31,6 +31,7 @@ import org.keycloak.adapters.AuthenticatedActionsHandler;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.NodesRegistrationManagement;
import org.keycloak.adapters.PreAuthActionsHandler;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.keycloak.adapters.RequestAuthenticator;
import org.keycloak.adapters.spi.AuthChallenge;
import org.keycloak.adapters.spi.AuthOutcome;
@@ -70,7 +71,7 @@ class KeycloakHttpServerAuthenticationMechanism implements HttpServerAuthenticat
AdapterDeploymentContext deploymentContext = getDeploymentContext(request);
if (deploymentContext == null) {
LOGGER.debugf("Ignoring request for path [%s] from mechanism [%s]. No deployment context found.", request.getRequestURI(), getMechanismName());
LOGGER.debugf("Ignoring request for path [%s] from mechanism [%s]. No deployment context found.", request.getRequestURI());
request.noAuthenticationInProgress();
return;
}
@@ -126,7 +127,7 @@ class KeycloakHttpServerAuthenticationMechanism implements HttpServerAuthenticat
private AdapterDeploymentContext getDeploymentContext(HttpServerRequest request) {
if (this.deploymentContext == null) {
return (AdapterDeploymentContext) request.getScope(Scope.APPLICATION).getAttachment(KeycloakConfigurationServletListener.ADAPTER_DEPLOYMENT_CONTEXT_ATTRIBUTE);
return (AdapterDeploymentContext) request.getScope(Scope.APPLICATION).getAttachment(AdapterDeploymentContext.class.getName());
}
return this.deploymentContext;
@@ -17,7 +17,6 @@
package org.keycloak.adapters.elytron;
import java.security.Principal;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Set;
import org.keycloak.KeycloakPrincipal;
@@ -55,7 +54,7 @@ public class KeycloakSecurityRealm implements SecurityRealm {
}
@Override
public SupportLevel getCredentialAcquireSupport(Class<? extends Credential> credentialType, String algorithmName, AlgorithmParameterSpec parameterSpec) throws RealmUnavailableException {
public SupportLevel getCredentialAcquireSupport(Class<? extends Credential> credentialType, String algorithmName) throws RealmUnavailableException {
return SupportLevel.UNSUPPORTED;
}
@@ -93,7 +92,7 @@ public class KeycloakSecurityRealm implements SecurityRealm {
}
@Override
public SupportLevel getCredentialAcquireSupport(Class<? extends Credential> credentialType, String algorithmName, AlgorithmParameterSpec parameterSpec) throws RealmUnavailableException {
public SupportLevel getCredentialAcquireSupport(Class<? extends Credential> credentialType, String algorithmName) throws RealmUnavailableException {
return SupportLevel.UNSUPPORTED;
}
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak WildFly Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-parent</artifactId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -21,7 +21,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-parent</artifactId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
@@ -68,10 +68,6 @@
<artifactId>wildfly-web-common</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wildfly.security</groupId>
<artifactId>wildfly-elytron</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging-annotations</artifactId>
@@ -105,9 +101,5 @@
<artifactId>keycloak-wildfly-adapter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-wildfly-elytron-oidc-adapter</artifactId>
</dependency>
</dependencies>
</project>
@@ -1,164 +0,0 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual 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.subsystem.adapter.extension;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
import org.jboss.as.controller.SimpleResourceDefinition;
import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
import org.jboss.as.controller.operations.validation.IntRangeValidator;
import org.jboss.as.controller.operations.validation.StringLengthValidator;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Defines attributes and operations for a secure-deployment.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
abstract class AbstractAdapterConfigurationDefinition extends SimpleResourceDefinition {
protected static final SimpleAttributeDefinition REALM =
new SimpleAttributeDefinitionBuilder("realm", ModelType.STRING, true)
.setXmlName("realm")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition RESOURCE =
new SimpleAttributeDefinitionBuilder("resource", ModelType.STRING, true)
.setXmlName("resource")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition USE_RESOURCE_ROLE_MAPPINGS =
new SimpleAttributeDefinitionBuilder("use-resource-role-mappings", ModelType.BOOLEAN, true)
.setXmlName("use-resource-role-mappings")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition BEARER_ONLY =
new SimpleAttributeDefinitionBuilder("bearer-only", ModelType.BOOLEAN, true)
.setXmlName("bearer-only")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition ENABLE_BASIC_AUTH =
new SimpleAttributeDefinitionBuilder("enable-basic-auth", ModelType.BOOLEAN, true)
.setXmlName("enable-basic-auth")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition PUBLIC_CLIENT =
new SimpleAttributeDefinitionBuilder("public-client", ModelType.BOOLEAN, true)
.setXmlName("public-client")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition TURN_OFF_CHANGE_SESSION =
new SimpleAttributeDefinitionBuilder("turn-off-change-session-id-on-login", ModelType.BOOLEAN, true)
.setXmlName("turn-off-change-session-id-on-login")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition TOKEN_MINIMUM_TIME_TO_LIVE =
new SimpleAttributeDefinitionBuilder("token-minimum-time-to-live", ModelType.INT, true)
.setXmlName("token-minimum-time-to-live")
.setValidator(new IntRangeValidator(-1, true))
.setAllowExpression(true)
.build();
protected static final SimpleAttributeDefinition MIN_TIME_BETWEEN_JWKS_REQUESTS =
new SimpleAttributeDefinitionBuilder("min-time-between-jwks-requests", ModelType.INT, true)
.setXmlName("min-time-between-jwks-requests")
.setValidator(new IntRangeValidator(-1, true))
.setAllowExpression(true)
.build();
static final List<SimpleAttributeDefinition> DEPLOYMENT_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
static {
DEPLOYMENT_ONLY_ATTRIBUTES.add(REALM);
DEPLOYMENT_ONLY_ATTRIBUTES.add(RESOURCE);
DEPLOYMENT_ONLY_ATTRIBUTES.add(USE_RESOURCE_ROLE_MAPPINGS);
DEPLOYMENT_ONLY_ATTRIBUTES.add(BEARER_ONLY);
DEPLOYMENT_ONLY_ATTRIBUTES.add(ENABLE_BASIC_AUTH);
DEPLOYMENT_ONLY_ATTRIBUTES.add(PUBLIC_CLIENT);
DEPLOYMENT_ONLY_ATTRIBUTES.add(TURN_OFF_CHANGE_SESSION);
DEPLOYMENT_ONLY_ATTRIBUTES.add(TOKEN_MINIMUM_TIME_TO_LIVE);
DEPLOYMENT_ONLY_ATTRIBUTES.add(MIN_TIME_BETWEEN_JWKS_REQUESTS);
}
static final List<SimpleAttributeDefinition> ALL_ATTRIBUTES = new ArrayList();
static {
ALL_ATTRIBUTES.addAll(DEPLOYMENT_ONLY_ATTRIBUTES);
ALL_ATTRIBUTES.addAll(SharedAttributeDefinitons.ATTRIBUTES);
}
static final Map<String, SimpleAttributeDefinition> XML_ATTRIBUTES = new HashMap<String, SimpleAttributeDefinition>();
static {
for (SimpleAttributeDefinition def : ALL_ATTRIBUTES) {
XML_ATTRIBUTES.put(def.getXmlName(), def);
}
}
private static final Map<String, SimpleAttributeDefinition> DEFINITION_LOOKUP = new HashMap<String, SimpleAttributeDefinition>();
static {
for (SimpleAttributeDefinition def : ALL_ATTRIBUTES) {
DEFINITION_LOOKUP.put(def.getXmlName(), def);
}
}
private final AbstractAdapterConfigurationWriteAttributeHandler attrWriteHandler;
private final List<SimpleAttributeDefinition> attributes;
protected AbstractAdapterConfigurationDefinition(String name, List<SimpleAttributeDefinition> attributes, AbstractAdapterConfigurationAddHandler addHandler, AbstractAdapterConfigurationRemoveHandler removeHandler, AbstractAdapterConfigurationWriteAttributeHandler attrWriteHandler) {
super(PathElement.pathElement(name),
KeycloakExtension.getResourceDescriptionResolver(name),
addHandler,
removeHandler);
this.attributes = attributes;
this.attrWriteHandler = attrWriteHandler;
}
@Override
public void registerOperations(ManagementResourceRegistration resourceRegistration) {
super.registerOperations(resourceRegistration);
resourceRegistration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE);
}
@Override
public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
super.registerAttributes(resourceRegistration);
for (AttributeDefinition attrDef : this.attributes) {
resourceRegistration.registerReadWriteAttribute(attrDef, null, this.attrWriteHandler);
}
}
public static SimpleAttributeDefinition lookup(String name) {
return DEFINITION_LOOKUP.get(name);
}
}
@@ -25,9 +25,7 @@ import org.jboss.as.web.common.WarMetaData;
import org.jboss.logging.Logger;
import org.jboss.metadata.javaee.spec.ParamValueMetaData;
import org.jboss.metadata.web.jboss.JBossWebMetaData;
import org.jboss.metadata.web.spec.ListenerMetaData;
import org.jboss.metadata.web.spec.LoginConfigMetaData;
import org.keycloak.adapters.elytron.KeycloakConfigurationServletListener;
import org.keycloak.subsystem.adapter.logging.KeycloakLogger;
import java.util.ArrayList;
@@ -73,8 +71,6 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
addKeycloakAuthData(phaseContext, service);
}
addConfigurationListener(deploymentUnit);
// FYI, Undertow Extension will find deployments that have auth-method set to KEYCLOAK
// todo notsure if we need this
@@ -125,32 +121,6 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
webMetaData.setContextParams(contextParams);
}
private void addConfigurationListener(DeploymentUnit deploymentUnit) {
WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
if (warMetaData == null) {
return;
}
JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
if (webMetaData == null) {
webMetaData = new JBossWebMetaData();
warMetaData.setMergedJBossWebMetaData(webMetaData);
}
LoginConfigMetaData loginConfig = webMetaData.getLoginConfig();
if (loginConfig == null) {
return;
}
if (!loginConfig.getAuthMethod().equals("KEYCLOAK")) {
return;
}
ListenerMetaData listenerMetaData = new ListenerMetaData();
listenerMetaData.setListenerClass(KeycloakConfigurationServletListener.class.getName());
webMetaData.getListeners().add(listenerMetaData);
}
@Override
public void undeploy(DeploymentUnit du) {
@@ -23,11 +23,8 @@ import org.jboss.dmr.ModelNode;
import org.jboss.dmr.Property;
import org.jboss.metadata.web.jboss.JBossWebMetaData;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS;
@@ -53,7 +50,6 @@ public final class KeycloakAdapterConfigService {
// keycloak-secured deployments
private final Map<String, ModelNode> secureDeployments = new HashMap<String, ModelNode>();
private final Set<String> elytronEnabledDeployments = new HashSet<>();
private KeycloakAdapterConfigService() {
@@ -72,13 +68,9 @@ public final class KeycloakAdapterConfigService {
this.realms.remove(realmNameFromOp(operation));
}
public void addSecureDeployment(ModelNode operation, ModelNode model, boolean elytronEnabled) {
public void addSecureDeployment(ModelNode operation, ModelNode model) {
ModelNode deployment = model.clone();
String name = deploymentNameFromOp(operation);
this.secureDeployments.put(name, deployment);
if (elytronEnabled) {
elytronEnabledDeployments.add(name);
}
this.secureDeployments.put(deploymentNameFromOp(operation), deployment);
}
public void updateSecureDeployment(ModelNode operation, String attrName, ModelNode resolvedValue) {
@@ -87,9 +79,7 @@ public final class KeycloakAdapterConfigService {
}
public void removeSecureDeployment(ModelNode operation) {
String name = deploymentNameFromOp(operation);
this.secureDeployments.remove(name);
elytronEnabledDeployments.remove(name);
this.secureDeployments.remove(deploymentNameFromOp(operation));
}
public void addCredential(ModelNode operation, ModelNode model) {
@@ -197,19 +187,7 @@ public final class KeycloakAdapterConfigService {
}
private String deploymentNameFromOp(ModelNode operation) {
String deploymentName = valueFromOpAddress(SecureDeploymentDefinition.TAG_NAME, operation);
if (deploymentName == null) {
deploymentName = valueFromOpAddress(KeycloakHttpServerAuthenticationMechanismFactoryDefinition.TAG_NAME, operation);
}
if (deploymentName == null) {
deploymentName = valueFromOpAddress(SecureServerDefinition.TAG_NAME, operation);
}
if (deploymentName == null) throw new RuntimeException("Can't find deployment name in address " + operation);
return deploymentName;
return valueFromOpAddress(SecureDeploymentDefinition.TAG_NAME, operation);
}
private String credentialNameFromOp(ModelNode operation) {
@@ -221,7 +199,9 @@ public final class KeycloakAdapterConfigService {
}
private String valueFromOpAddress(String addrElement, ModelNode operation) {
return getValueOfAddrElement(operation.get(ADDRESS), addrElement);
String deploymentName = getValueOfAddrElement(operation.get(ADDRESS), addrElement);
if (deploymentName == null) throw new RuntimeException("Can't find '" + addrElement + "' in address " + operation.toString());
return deploymentName;
}
private String getValueOfAddrElement(ModelNode address, String elementName) {
@@ -261,22 +241,8 @@ public final class KeycloakAdapterConfigService {
return json.toJSONString(true);
}
public String getJSON(String deploymentName) {
ModelNode deployment = this.secureDeployments.get(deploymentName);
String realmName = deployment.get(RealmDefinition.TAG_NAME).asString();
ModelNode realm = this.realms.get(realmName);
ModelNode json = new ModelNode();
json.get(RealmDefinition.TAG_NAME).set(realmName);
// Realm values set first. Some can be overridden by deployment values.
if (realm != null) setJSONValues(json, realm);
setJSONValues(json, deployment);
return json.toJSONString(true);
}
private void setJSONValues(ModelNode json, ModelNode values) {
for (Property prop : new ArrayList<>(values.asPropertyList())) {
for (Property prop : values.asPropertyList()) {
String name = prop.getName();
ModelNode value = prop.getValue();
if (value.isDefined()) {
@@ -292,10 +258,6 @@ public final class KeycloakAdapterConfigService {
return this.secureDeployments.containsKey(deploymentName);
}
public boolean isElytronEnabled(DeploymentUnit deploymentUnit) {
return elytronEnabledDeployments.contains(preferredDeploymentName(deploymentUnit));
}
private ModelNode getSecureDeployment(DeploymentUnit deploymentUnit) {
String deploymentName = preferredDeploymentName(deploymentUnit);
return this.secureDeployments.containsKey(deploymentName)
@@ -29,14 +29,13 @@ import org.jboss.modules.ModuleLoader;
*/
public class KeycloakDependencyProcessorWildFly extends KeycloakDependencyProcessor {
private static final ModuleIdentifier KEYCLOAK_ELYTRON_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-wildfly-elytron-oidc-adapter");
private static final ModuleIdentifier KEYCLOAK_WILDFLY_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-wildfly-adapter");
private static final ModuleIdentifier KEYCLOAK_UNDERTOW_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-undertow-adapter");
@Override
protected void addPlatformSpecificModules(ModuleSpecification moduleSpecification, ModuleLoader moduleLoader) {
// ModuleDependency(ModuleLoader moduleLoader, ModuleIdentifier identifier, boolean optional, boolean export, boolean importServices, boolean userSpecified)
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_WILDFLY_ADAPTER, false, false, true, false));
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_UNDERTOW_ADAPTER, false, false, false, false));
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_ELYTRON_ADAPTER, true, false, false, false));
}
}
@@ -47,9 +47,8 @@ public class KeycloakExtension implements Extension {
private static final ResourceDefinition KEYCLOAK_SUBSYSTEM_RESOURCE = new KeycloakSubsystemDefinition();
static final RealmDefinition REALM_DEFINITION = new RealmDefinition();
static final SecureDeploymentDefinition SECURE_DEPLOYMENT_DEFINITION = new SecureDeploymentDefinition();
static final SecureServerDefinition SECURE_SERVER_DEFINITION = new SecureServerDefinition();
static final CredentialDefinition CREDENTIAL_DEFINITION = new CredentialDefinition();
static final RedirecRewritetRuleDefinition REDIRECT_RULE_DEFINITON = new RedirecRewritetRuleDefinition();
static final RedirecRewritetRuleDefinition REDIRECT_RULE_DEFINITON = new RedirecRewritetRuleDefinition();
public static StandardResourceDescriptionResolver getResourceDescriptionResolver(final String... keyPrefix) {
StringBuilder prefix = new StringBuilder(SUBSYSTEM_NAME);
@@ -81,10 +80,6 @@ public class KeycloakExtension implements Extension {
secureDeploymentRegistration.registerSubModel(CREDENTIAL_DEFINITION);
secureDeploymentRegistration.registerSubModel(REDIRECT_RULE_DEFINITON);
ManagementResourceRegistration secureServerRegistration = registration.registerSubModel(SECURE_SERVER_DEFINITION);
secureServerRegistration.registerSubModel(CREDENTIAL_DEFINITION);
secureServerRegistration.registerSubModel(REDIRECT_RULE_DEFINITON);
subsystem.registerXMLElementWriter(PARSER);
}
}
@@ -1,67 +0,0 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual 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.subsystem.adapter.extension;
import org.jboss.msc.service.Service;
import org.jboss.msc.service.StartContext;
import org.jboss.msc.service.StartException;
import org.jboss.msc.service.StopContext;
import org.jboss.msc.value.InjectedValue;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.adapters.elytron.KeycloakHttpServerAuthenticationMechanismFactory;
import org.wildfly.security.auth.server.SecurityDomain;
import org.wildfly.security.http.HttpServerAuthenticationMechanismFactory;
import org.wildfly.security.http.util.SetMechanismInformationMechanismFactory;
import java.io.ByteArrayInputStream;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class KeycloakHttpAuthenticationFactoryService implements Service<HttpServerAuthenticationMechanismFactory> {
private final String factoryName;
private HttpServerAuthenticationMechanismFactory httpAuthenticationFactory;
public KeycloakHttpAuthenticationFactoryService(String factoryName) {
this.factoryName = factoryName;
}
@Override
public void start(StartContext context) throws StartException {
KeycloakAdapterConfigService adapterConfigService = KeycloakAdapterConfigService.getInstance();
String config = adapterConfigService.getJSON(this.factoryName);
this.httpAuthenticationFactory = new KeycloakHttpServerAuthenticationMechanismFactory(createDeploymentContext(config.getBytes()));
}
@Override
public void stop(StopContext context) {
this.httpAuthenticationFactory = null;
}
@Override
public HttpServerAuthenticationMechanismFactory getValue() throws IllegalStateException, IllegalArgumentException {
return new SetMechanismInformationMechanismFactory(this.httpAuthenticationFactory);
}
private AdapterDeploymentContext createDeploymentContext(byte[] config) {
return new AdapterDeploymentContext(KeycloakDeploymentBuilder.build(new ByteArrayInputStream(config)));
}
}
@@ -1,117 +0,0 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual 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.subsystem.adapter.extension;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
import static org.keycloak.subsystem.adapter.extension.KeycloakHttpServerAuthenticationMechanismFactoryDefinition.KeycloakHttpServerAuthenticationMechanismFactoryAddHandler.HTTP_SERVER_AUTHENTICATION_CAPABILITY;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.SimpleResourceDefinition;
import org.jboss.as.controller.capability.RuntimeCapability;
import org.jboss.dmr.ModelNode;
import org.jboss.msc.service.ServiceController;
import org.jboss.msc.service.ServiceName;
import org.wildfly.security.http.HttpServerAuthenticationMechanismFactory;
/**
* A {@link SimpleResourceDefinition} that can be used to configure a {@link org.keycloak.adapters.elytron.KeycloakHttpServerAuthenticationMechanismFactory}
* and expose it as a capability for other subsystems.
*
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
class KeycloakHttpServerAuthenticationMechanismFactoryDefinition extends AbstractAdapterConfigurationDefinition {
static final String TAG_NAME = "http-server-mechanism-factory";
KeycloakHttpServerAuthenticationMechanismFactoryDefinition() {
this(TAG_NAME);
}
KeycloakHttpServerAuthenticationMechanismFactoryDefinition(String tagName) {
super(tagName, ALL_ATTRIBUTES, new KeycloakHttpServerAuthenticationMechanismFactoryAddHandler(), new KeycloakHttpServerAuthenticationMechanismFactoryRemoveHandler(), new KeycloakHttpServerAuthenticationMechanismFactoryWriteHandler());
}
/**
* A {@link AbstractAdapterConfigurationAddHandler} that exposes a {@link KeycloakHttpServerAuthenticationMechanismFactoryDefinition}
* as a capability through the installation of a {@link KeycloakHttpAuthenticationFactoryService}.
*
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
static final class KeycloakHttpServerAuthenticationMechanismFactoryAddHandler extends AbstractAdapterConfigurationAddHandler {
static final String HTTP_SERVER_AUTHENTICATION_CAPABILITY = "org.wildfly.security.http-server-mechanism-factory";
static final RuntimeCapability<Void> HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY = RuntimeCapability
.Builder.of(HTTP_SERVER_AUTHENTICATION_CAPABILITY, true, HttpServerAuthenticationMechanismFactory.class)
.build();
KeycloakHttpServerAuthenticationMechanismFactoryAddHandler() {
super(HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY, ALL_ATTRIBUTES);
}
@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
super.performRuntime(context, operation, model);
installCapability(context, operation);
}
static void installCapability(OperationContext context, ModelNode operation) {
PathAddress pathAddress = PathAddress.pathAddress(operation.get(OP_ADDR));
String factoryName = pathAddress.getLastElement().getValue();
ServiceName serviceName = context.getCapabilityServiceName(HTTP_SERVER_AUTHENTICATION_CAPABILITY, factoryName, HttpServerAuthenticationMechanismFactory.class);
KeycloakHttpAuthenticationFactoryService service = new KeycloakHttpAuthenticationFactoryService(factoryName);
context.getServiceTarget().addService(serviceName, service).setInitialMode(ServiceController.Mode.ACTIVE).install();
}
}
/**
* A {@link AbstractAdapterConfigurationRemoveHandler} that handles the removal of {@link KeycloakHttpServerAuthenticationMechanismFactoryDefinition}.
*
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
static final class KeycloakHttpServerAuthenticationMechanismFactoryRemoveHandler extends AbstractAdapterConfigurationRemoveHandler {
@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
super.performRuntime(context, operation, model);
PathAddress pathAddress = PathAddress.pathAddress(operation.get(OP_ADDR));
String factoryName = pathAddress.getLastElement().getValue();
ServiceName serviceName = context.getCapabilityServiceName(HTTP_SERVER_AUTHENTICATION_CAPABILITY, factoryName, HttpServerAuthenticationMechanismFactory.class);
context.removeService(serviceName);
}
@Override
protected void recoverServices(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
super.recoverServices(context, operation, model);
KeycloakHttpServerAuthenticationMechanismFactoryAddHandler.installCapability(context, operation);
}
}
/**
* A {@link AbstractAdapterConfigurationWriteAttributeHandler} that updates attributes on a {@link KeycloakHttpServerAuthenticationMechanismFactoryDefinition}.
*
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
static final class KeycloakHttpServerAuthenticationMechanismFactoryWriteHandler extends AbstractAdapterConfigurationWriteAttributeHandler {
KeycloakHttpServerAuthenticationMechanismFactoryWriteHandler() {
super(ALL_ATTRIBUTES);
}
}
}
@@ -62,9 +62,6 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
else if (reader.getLocalName().equals(SecureDeploymentDefinition.TAG_NAME)) {
readDeployment(reader, list);
}
else if (reader.getLocalName().equals(SecureServerDefinition.TAG_NAME)) {
readSecureServer(reader, list);
}
}
}
@@ -92,35 +89,27 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
}
private void readDeployment(XMLExtendedStreamReader reader, List<ModelNode> resourcesToAdd) throws XMLStreamException {
readSecureResource(KeycloakExtension.SECURE_DEPLOYMENT_DEFINITION.TAG_NAME, KeycloakExtension.SECURE_DEPLOYMENT_DEFINITION, reader, resourcesToAdd);
}
private void readSecureServer(XMLExtendedStreamReader reader, List<ModelNode> resourcesToAdd) throws XMLStreamException {
readSecureResource(KeycloakExtension.SECURE_SERVER_DEFINITION.TAG_NAME, KeycloakExtension.SECURE_SERVER_DEFINITION, reader, resourcesToAdd);
}
private void readSecureResource(String tagName, AbstractAdapterConfigurationDefinition resource, XMLExtendedStreamReader reader, List<ModelNode> resourcesToAdd) throws XMLStreamException {
String name = readNameAttribute(reader);
ModelNode addSecureDeployment = new ModelNode();
addSecureDeployment.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
PathAddress addr = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, KeycloakExtension.SUBSYSTEM_NAME),
PathElement.pathElement(tagName, name));
PathElement.pathElement(SecureDeploymentDefinition.TAG_NAME, name));
addSecureDeployment.get(ModelDescriptionConstants.OP_ADDR).set(addr.toModelNode());
List<ModelNode> credentialsToAdd = new ArrayList<ModelNode>();
List<ModelNode> redirectRulesToAdd = new ArrayList<ModelNode>();
while (reader.hasNext() && nextTag(reader) != END_ELEMENT) {
String localName = reader.getLocalName();
if (localName.equals(CredentialDefinition.TAG_NAME)) {
String tagName = reader.getLocalName();
if (tagName.equals(CredentialDefinition.TAG_NAME)) {
readCredential(reader, addr, credentialsToAdd);
continue;
}
if (localName.equals(RedirecRewritetRuleDefinition.TAG_NAME)) {
if (tagName.equals(RedirecRewritetRuleDefinition.TAG_NAME)) {
readRewriteRule(reader, addr, redirectRulesToAdd);
continue;
}
SimpleAttributeDefinition def = resource.lookup(localName);
if (def == null) throw new XMLStreamException("Unknown secure-deployment tag " + localName);
SimpleAttributeDefinition def = SecureDeploymentDefinition.lookup(tagName);
if (def == null) throw new XMLStreamException("Unknown secure-deployment tag " + tagName);
def.parseAndSetParameter(reader.getElementText(), addSecureDeployment, reader);
}
@@ -247,7 +236,6 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
context.startSubsystemElement(KeycloakExtension.NAMESPACE, false);
writeRealms(writer, context);
writeSecureDeployments(writer, context);
writeSecureServers(writer, context);
writer.writeEndElement();
}
@@ -268,22 +256,14 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
}
private void writeSecureDeployments(XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException {
writeSecureResource(SecureDeploymentDefinition.TAG_NAME, SecureDeploymentDefinition.ALL_ATTRIBUTES, writer, context);
}
private void writeSecureServers(XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException {
writeSecureResource(SecureServerDefinition.TAG_NAME, SecureServerDefinition.ALL_ATTRIBUTES, writer, context);
}
private void writeSecureResource(String tagName, List<SimpleAttributeDefinition> attributes, XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException {
if (!context.getModelNode().get(tagName).isDefined()) {
if (!context.getModelNode().get(SecureDeploymentDefinition.TAG_NAME).isDefined()) {
return;
}
for (Property deployment : context.getModelNode().get(tagName).asPropertyList()) {
writer.writeStartElement(tagName);
for (Property deployment : context.getModelNode().get(SecureDeploymentDefinition.TAG_NAME).asPropertyList()) {
writer.writeStartElement(SecureDeploymentDefinition.TAG_NAME);
writer.writeAttribute("name", deployment.getName());
ModelNode deploymentElements = deployment.getValue();
for (AttributeDefinition element : attributes) {
for (AttributeDefinition element : SecureDeploymentDefinition.ALL_ATTRIBUTES) {
element.marshallAsElement(deploymentElements, writer);
}
@@ -291,7 +271,7 @@ class KeycloakSubsystemParser implements XMLStreamConstants, XMLElementReader<Li
if (credentials.isDefined()) {
writeCredentials(writer, credentials);
}
ModelNode redirectRewriteRule = deploymentElements.get(RedirecRewritetRuleDefinition.TAG_NAME);
if (redirectRewriteRule.isDefined()) {
writeRedirectRules(writer, redirectRewriteRule);
@@ -17,32 +17,41 @@
package org.keycloak.subsystem.adapter.extension;
import java.util.List;
import org.jboss.as.controller.AbstractAddStepHandler;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.as.controller.capability.RuntimeCapability;
import org.jboss.dmr.ModelNode;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
/**
* Add a deployment to a realm.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
abstract class AbstractAdapterConfigurationAddHandler extends AbstractAddStepHandler {
public final class SecureDeploymentAddHandler extends AbstractAddStepHandler {
private final boolean elytronEnabled;
public static SecureDeploymentAddHandler INSTANCE = new SecureDeploymentAddHandler();
AbstractAdapterConfigurationAddHandler(RuntimeCapability<Void> runtimeCapability, List<SimpleAttributeDefinition> attributes) {
super(runtimeCapability, attributes);
elytronEnabled = runtimeCapability != null;
private SecureDeploymentAddHandler() {}
@Override
protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException {
// TODO: localize exception. get id number
if (!operation.get(OP).asString().equals(ADD)) {
throw new OperationFailedException("Unexpected operation for add secure deployment. operation=" + operation.toString());
}
for (AttributeDefinition attr : SecureDeploymentDefinition.ALL_ATTRIBUTES) {
attr.validateAndSet(operation, model);
}
}
@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
KeycloakAdapterConfigService ckService = KeycloakAdapterConfigService.getInstance();
ckService.addSecureDeployment(operation, context.resolveExpressions(model), elytronEnabled);
ckService.addSecureDeployment(operation, context.resolveExpressions(model));
}
}
@@ -16,88 +16,138 @@
*/
package org.keycloak.subsystem.adapter.extension;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.capability.RuntimeCapability;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
import org.jboss.as.controller.SimpleResourceDefinition;
import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
import org.jboss.as.controller.operations.validation.IntRangeValidator;
import org.jboss.as.controller.operations.validation.StringLengthValidator;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.dmr.ModelNode;
import org.jboss.msc.service.ServiceController;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.service.ServiceTarget;
import org.wildfly.security.http.HttpServerAuthenticationMechanismFactory;
import org.jboss.dmr.ModelType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Defines attributes and operations for a secure-deployment.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
final class SecureDeploymentDefinition extends AbstractAdapterConfigurationDefinition {
public class SecureDeploymentDefinition extends SimpleResourceDefinition {
static final String TAG_NAME = "secure-deployment";
public static final String TAG_NAME = "secure-deployment";
protected static final SimpleAttributeDefinition REALM =
new SimpleAttributeDefinitionBuilder("realm", ModelType.STRING, true)
.setXmlName("realm")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition RESOURCE =
new SimpleAttributeDefinitionBuilder("resource", ModelType.STRING, true)
.setXmlName("resource")
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
protected static final SimpleAttributeDefinition USE_RESOURCE_ROLE_MAPPINGS =
new SimpleAttributeDefinitionBuilder("use-resource-role-mappings", ModelType.BOOLEAN, true)
.setXmlName("use-resource-role-mappings")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition BEARER_ONLY =
new SimpleAttributeDefinitionBuilder("bearer-only", ModelType.BOOLEAN, true)
.setXmlName("bearer-only")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition ENABLE_BASIC_AUTH =
new SimpleAttributeDefinitionBuilder("enable-basic-auth", ModelType.BOOLEAN, true)
.setXmlName("enable-basic-auth")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition PUBLIC_CLIENT =
new SimpleAttributeDefinitionBuilder("public-client", ModelType.BOOLEAN, true)
.setXmlName("public-client")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition TURN_OFF_CHANGE_SESSION =
new SimpleAttributeDefinitionBuilder("turn-off-change-session-id-on-login", ModelType.BOOLEAN, true)
.setXmlName("turn-off-change-session-id-on-login")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition TOKEN_MINIMUM_TIME_TO_LIVE =
new SimpleAttributeDefinitionBuilder("token-minimum-time-to-live", ModelType.INT, true)
.setXmlName("token-minimum-time-to-live")
.setValidator(new IntRangeValidator(-1, true))
.setAllowExpression(true)
.build();
protected static final SimpleAttributeDefinition MIN_TIME_BETWEEN_JWKS_REQUESTS =
new SimpleAttributeDefinitionBuilder("min-time-between-jwks-requests", ModelType.INT, true)
.setXmlName("min-time-between-jwks-requests")
.setValidator(new IntRangeValidator(-1, true))
.setAllowExpression(true)
.build();
protected static final List<SimpleAttributeDefinition> DEPLOYMENT_ONLY_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
static {
DEPLOYMENT_ONLY_ATTRIBUTES.add(REALM);
DEPLOYMENT_ONLY_ATTRIBUTES.add(RESOURCE);
DEPLOYMENT_ONLY_ATTRIBUTES.add(USE_RESOURCE_ROLE_MAPPINGS);
DEPLOYMENT_ONLY_ATTRIBUTES.add(BEARER_ONLY);
DEPLOYMENT_ONLY_ATTRIBUTES.add(ENABLE_BASIC_AUTH);
DEPLOYMENT_ONLY_ATTRIBUTES.add(PUBLIC_CLIENT);
DEPLOYMENT_ONLY_ATTRIBUTES.add(TURN_OFF_CHANGE_SESSION);
DEPLOYMENT_ONLY_ATTRIBUTES.add(TOKEN_MINIMUM_TIME_TO_LIVE);
DEPLOYMENT_ONLY_ATTRIBUTES.add(MIN_TIME_BETWEEN_JWKS_REQUESTS);
}
protected static final List<SimpleAttributeDefinition> ALL_ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
static {
ALL_ATTRIBUTES.addAll(DEPLOYMENT_ONLY_ATTRIBUTES);
ALL_ATTRIBUTES.addAll(SharedAttributeDefinitons.ATTRIBUTES);
}
private static final Map<String, SimpleAttributeDefinition> DEFINITION_LOOKUP = new HashMap<String, SimpleAttributeDefinition>();
static {
for (SimpleAttributeDefinition def : ALL_ATTRIBUTES) {
DEFINITION_LOOKUP.put(def.getXmlName(), def);
}
}
private static SecureDeploymentWriteAttributeHandler attrHandler = new SecureDeploymentWriteAttributeHandler(ALL_ATTRIBUTES);
public SecureDeploymentDefinition() {
super(TAG_NAME, ALL_ATTRIBUTES, new SecureDeploymentAddHandler(), new SecureDeploymentRemoveHandler(), new SecureDeploymentWriteAttributeHandler());
super(PathElement.pathElement(TAG_NAME),
KeycloakExtension.getResourceDescriptionResolver(TAG_NAME),
SecureDeploymentAddHandler.INSTANCE,
SecureDeploymentRemoveHandler.INSTANCE);
}
/**
* Add a deployment to a realm.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
static final class SecureDeploymentAddHandler extends AbstractAdapterConfigurationAddHandler {
@Override
public void registerOperations(ManagementResourceRegistration resourceRegistration) {
super.registerOperations(resourceRegistration);
resourceRegistration.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE);
}
static final String HTTP_SERVER_AUTHENTICATION_CAPABILITY = "org.wildfly.security.http-server-mechanism-factory";
static RuntimeCapability<Void> HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY;
static {
try {
HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY = RuntimeCapability
.Builder.of(HTTP_SERVER_AUTHENTICATION_CAPABILITY, true, HttpServerAuthenticationMechanismFactory.class)
.build();
} catch (NoClassDefFoundError ncfe) {
// ignore, Elytron not present thus no capability will be published by this resource definition
}
}
SecureDeploymentAddHandler() {
super(HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY, ALL_ATTRIBUTES);
}
@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
super.performRuntime(context, operation, model);
if (HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY != null) {
installCapability(context, operation);
}
}
static void installCapability(OperationContext context, ModelNode operation) {
PathAddress pathAddress = PathAddress.pathAddress(operation.get(OP_ADDR));
String factoryName = pathAddress.getLastElement().getValue();
ServiceName serviceName = context.getCapabilityServiceName(HTTP_SERVER_AUTHENTICATION_CAPABILITY, factoryName, HttpServerAuthenticationMechanismFactory.class);
KeycloakHttpAuthenticationFactoryService service = new KeycloakHttpAuthenticationFactoryService(factoryName);
ServiceTarget serviceTarget = context.getServiceTarget();
serviceTarget.addService(serviceName, service).setInitialMode(ServiceController.Mode.ACTIVE).install();
@Override
public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
super.registerAttributes(resourceRegistration);
for (AttributeDefinition attrDef : ALL_ATTRIBUTES) {
resourceRegistration.registerReadWriteAttribute(attrDef, null, attrHandler);
}
}
/**
* Remove a secure-deployment from a realm.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
static final class SecureDeploymentRemoveHandler extends AbstractAdapterConfigurationRemoveHandler {}
/**
* Update an attribute on a secure-deployment.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
static final class SecureDeploymentWriteAttributeHandler extends AbstractAdapterConfigurationWriteAttributeHandler {
SecureDeploymentWriteAttributeHandler() {
super(ALL_ATTRIBUTES);
}
public static SimpleAttributeDefinition lookup(String name) {
return DEFINITION_LOOKUP.get(name);
}
}
@@ -27,7 +27,11 @@ import org.jboss.dmr.ModelNode;
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
abstract class AbstractAdapterConfigurationRemoveHandler extends AbstractRemoveStepHandler {
public final class SecureDeploymentRemoveHandler extends AbstractRemoveStepHandler {
public static SecureDeploymentRemoveHandler INSTANCE = new SecureDeploymentRemoveHandler();
private SecureDeploymentRemoveHandler() {}
@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
@@ -31,10 +31,14 @@ import java.util.List;
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
abstract class AbstractAdapterConfigurationWriteAttributeHandler extends AbstractWriteAttributeHandler<KeycloakAdapterConfigService> {
public class SecureDeploymentWriteAttributeHandler extends AbstractWriteAttributeHandler<KeycloakAdapterConfigService> {
AbstractAdapterConfigurationWriteAttributeHandler(List<SimpleAttributeDefinition> definitions) {
super(definitions.toArray(new AttributeDefinition[definitions.size()]));
public SecureDeploymentWriteAttributeHandler(List<SimpleAttributeDefinition> definitions) {
this(definitions.toArray(new AttributeDefinition[definitions.size()]));
}
public SecureDeploymentWriteAttributeHandler(AttributeDefinition... definitions) {
super(definitions);
}
@Override
@@ -1,258 +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.subsystem.adapter.extension;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
import static org.keycloak.subsystem.adapter.extension.KeycloakHttpServerAuthenticationMechanismFactoryDefinition.KeycloakHttpServerAuthenticationMechanismFactoryAddHandler.HTTP_SERVER_AUTHENTICATION_CAPABILITY;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Path;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import io.undertow.io.IoCallback;
import io.undertow.io.Sender;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.handlers.resource.Resource;
import io.undertow.server.handlers.resource.ResourceChangeListener;
import io.undertow.server.handlers.resource.ResourceManager;
import io.undertow.util.ETag;
import io.undertow.util.MimeMappings;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.capability.RuntimeCapability;
import org.jboss.as.server.mgmt.domain.ExtensibleHttpManagement;
import org.jboss.dmr.ModelNode;
import org.jboss.msc.service.Service;
import org.jboss.msc.service.ServiceController.Mode;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.service.ServiceTarget;
import org.jboss.msc.service.StartContext;
import org.jboss.msc.service.StartException;
import org.jboss.msc.service.StopContext;
import org.jboss.msc.value.InjectedValue;
import org.wildfly.security.http.HttpServerAuthenticationMechanismFactory;
/**
* Defines attributes and operations for a secure-deployment.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2013 Red Hat Inc.
*/
final class SecureServerDefinition extends AbstractAdapterConfigurationDefinition {
public static final String TAG_NAME = "secure-server";
SecureServerDefinition() {
super(TAG_NAME, ALL_ATTRIBUTES, new SecureServerAddHandler(), new SecureServerRemoveHandler(), new SecureServerWriteHandler());
}
/**
* A {@link AbstractAdapterConfigurationAddHandler} that exposes a {@link SecureServerDefinition}
* as a capability through the installation of a {@link KeycloakHttpAuthenticationFactoryService}.
*
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
static final class SecureServerAddHandler extends AbstractAdapterConfigurationAddHandler {
static final String HTTP_SERVER_AUTHENTICATION_CAPABILITY = "org.wildfly.security.http-server-mechanism-factory";
static final String HTTP_MANAGEMENT_HTTP_EXTENSIBLE_CAPABILITY = "org.wildfly.management.http.extensible";
static RuntimeCapability<Void> HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY;
static {
try {
HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY = RuntimeCapability
.Builder.of(HTTP_SERVER_AUTHENTICATION_CAPABILITY, true, HttpServerAuthenticationMechanismFactory.class)
.build();
} catch (NoClassDefFoundError ncfe) {
// ignore, Elytron not present thus no capability will be published by this resource definition
}
}
SecureServerAddHandler() {
super(HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY, ALL_ATTRIBUTES);
}
@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
super.performRuntime(context, operation, model);
if (HTTP_SERVER_AUTHENTICATION_RUNTIME_CAPABILITY != null) {
installCapability(context, operation);
}
}
static void installCapability(OperationContext context, ModelNode operation) throws OperationFailedException {
PathAddress pathAddress = PathAddress.pathAddress(operation.get(OP_ADDR));
String factoryName = pathAddress.getLastElement().getValue();
ServiceName serviceName = context.getCapabilityServiceName(HTTP_SERVER_AUTHENTICATION_CAPABILITY, factoryName, HttpServerAuthenticationMechanismFactory.class);
boolean publicClient = SecureServerDefinition.PUBLIC_CLIENT.resolveModelAttribute(context, operation).asBoolean(false);
if (!publicClient) {
throw new OperationFailedException("Only public clients are allowed to have their configuration exposed through the management interface");
}
KeycloakHttpAuthenticationFactoryService service = new KeycloakHttpAuthenticationFactoryService(factoryName);
ServiceTarget serviceTarget = context.getServiceTarget();
InjectedValue<ExtensibleHttpManagement> injectedValue = new InjectedValue<>();
serviceTarget.addService(serviceName.append("http-management-context"), createHttpManagementConfigContextService(factoryName, injectedValue))
.addDependency(context.getCapabilityServiceName(HTTP_MANAGEMENT_HTTP_EXTENSIBLE_CAPABILITY, ExtensibleHttpManagement.class), ExtensibleHttpManagement.class, injectedValue).setInitialMode(Mode.ACTIVE).install();
serviceTarget.addService(serviceName, service).setInitialMode(Mode.ACTIVE).install();
}
}
/**
* A {@link AbstractAdapterConfigurationRemoveHandler} that handles the removal of {@link SecureServerDefinition}.
*
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
static final class SecureServerRemoveHandler extends AbstractAdapterConfigurationRemoveHandler {
@Override
protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
super.performRuntime(context, operation, model);
PathAddress pathAddress = PathAddress.pathAddress(operation.get(OP_ADDR));
String factoryName = pathAddress.getLastElement().getValue();
ServiceName serviceName = context.getCapabilityServiceName(HTTP_SERVER_AUTHENTICATION_CAPABILITY, factoryName, HttpServerAuthenticationMechanismFactory.class);
context.removeService(serviceName);
}
@Override
protected void recoverServices(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
super.recoverServices(context, operation, model);
SecureServerDefinition.SecureServerAddHandler.installCapability(context, operation);
}
}
/**
* A {@link AbstractAdapterConfigurationWriteAttributeHandler} that updates attributes on a {@link SecureServerDefinition}.
*
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
static final class SecureServerWriteHandler extends AbstractAdapterConfigurationWriteAttributeHandler {
SecureServerWriteHandler() {
super(ALL_ATTRIBUTES);
}
}
private static Service<Void> createHttpManagementConfigContextService(final String factoryName, final InjectedValue<ExtensibleHttpManagement> httpConfigContext) {
final String contextName = "/keycloak/adapter/" + factoryName + "/";
return new Service<Void>() {
public void start(StartContext startContext) throws StartException {
ExtensibleHttpManagement extensibleHttpManagement = (ExtensibleHttpManagement)httpConfigContext.getValue();
extensibleHttpManagement.addStaticContext(contextName, new ResourceManager() {
public Resource getResource(final String path) throws IOException {
KeycloakAdapterConfigService adapterConfigService = KeycloakAdapterConfigService.getInstance();
final String config = adapterConfigService.getJSON(factoryName);
if (config == null) {
return null;
}
return new Resource() {
public String getPath() {
return null;
}
public Date getLastModified() {
return null;
}
public String getLastModifiedString() {
return null;
}
public ETag getETag() {
return null;
}
public String getName() {
return null;
}
public boolean isDirectory() {
return false;
}
public List<Resource> list() {
return Collections.emptyList();
}
public String getContentType(MimeMappings mimeMappings) {
return "application/json";
}
public void serve(Sender sender, HttpServerExchange exchange, IoCallback completionCallback) {
sender.send(config);
}
public Long getContentLength() {
return Long.valueOf((long)config.length());
}
public String getCacheKey() {
return null;
}
public File getFile() {
return null;
}
public Path getFilePath() {
return null;
}
public File getResourceManagerRoot() {
return null;
}
public Path getResourceManagerRootPath() {
return null;
}
public URL getUrl() {
return null;
}
};
}
public boolean isResourceChangeListenerSupported() {
return false;
}
public void registerResourceChangeListener(ResourceChangeListener listener) {
}
public void removeResourceChangeListener(ResourceChangeListener listener) {
}
public void close() throws IOException {
}
});
}
public void stop(StopContext stopContext) {
((ExtensibleHttpManagement)httpConfigContext.getValue()).removeContext(contextName);
}
public Void getValue() throws IllegalStateException, IllegalArgumentException {
return null;
}
};
}
}
@@ -20,8 +20,6 @@ keycloak.subsystem.add=Operation Adds Keycloak adapter subsystem
keycloak.subsystem.remove=Operation removes Keycloak adapter subsystem
keycloak.subsystem.realm=A Keycloak realm.
keycloak.subsystem.secure-deployment=A deployment secured by Keycloak.
keycloak.subsystem.secure-server=A configuration exposed to the server.
keycloak.subsystem.http-server-mechanism-factory=A http-server-mechanism-factory exposed to the server.
keycloak.realm=A Keycloak realm.
keycloak.realm.add=Add a realm definition to the subsystem.
@@ -92,48 +90,7 @@ keycloak.secure-deployment.token-minimum-time-to-live=The adapter will refresh t
keycloak.secure-deployment.min-time-between-jwks-requests=If adapter recognize token signed by unknown public key, it will try to download new public key from keycloak server. However it won't try to download if already tried it in less than 'min-time-between-jwks-requests' seconds
keycloak.secure-deployment.ignore-oauth-query-parameter=disable query parameter parsing for access_token
keycloak.secure-server=A deployment secured by Keycloak
keycloak.secure-server.add=Add a deployment to be secured by Keycloak
keycloak.secure-server.realm=Keycloak realm
keycloak.secure-server.remove=Remove a deployment to be secured by Keycloak
keycloak.secure-server.realm-public-key=Public key of the realm
keycloak.secure-server.auth-server-url=Base URL of the Realm Auth Server
keycloak.secure-server.disable-trust-manager=Adapter will not use a trust manager when making adapter HTTPS requests
keycloak.secure-server.ssl-required=Specify if SSL is required (valid values are all, external and none)
keycloak.secure-server.allow-any-hostname=SSL Setting
keycloak.secure-server.truststore=Truststore used for adapter client HTTPS requests
keycloak.secure-server.truststore-password=Password of the Truststore
keycloak.secure-server.connection-pool-size=Connection pool size for the client used by the adapter
keycloak.secure-server.resource=Application name
keycloak.secure-server.use-resource-role-mappings=Use resource level permissions from token
keycloak.secure-server.credentials=Adapter credentials
keycloak.secure-server.redirect-rewrite-rule=Apply a rewrite rule for the redirect URI
keycloak.secure-server.bearer-only=Bearer Token Auth only
keycloak.secure-server.enable-basic-auth=Enable Basic Authentication
keycloak.secure-server.public-client=Public client
keycloak.secure-server.enable-cors=Enable Keycloak CORS support
keycloak.secure-server.autodetect-bearer-only=autodetect bearer-only requests
keycloak.secure-server.client-keystore=n/a
keycloak.secure-server.client-keystore-password=n/a
keycloak.secure-server.client-key-password=n/a
keycloak.secure-server.cors-max-age=CORS max-age header
keycloak.secure-server.cors-allowed-headers=CORS allowed headers
keycloak.secure-server.cors-allowed-methods=CORS allowed methods
keycloak.secure-server.cors-exposed-headers=CORS exposed headers
keycloak.secure-server.expose-token=Enable secure URL that exposes access token
keycloak.secure-server.auth-server-url-for-backend-requests=URL to use to make background calls to auth server
keycloak.secure-server.always-refresh-token=Refresh token on every single web request
keycloak.secure-server.register-node-at-startup=Cluster setting
keycloak.secure-server.register-node-period=how often to re-register node
keycloak.secure-server.token-store=cookie or session storage for auth session data
keycloak.secure-server.principal-attribute=token attribute to use to set Principal name
keycloak.secure-server.turn-off-change-session-id-on-login=The session id is changed by default on a successful login. Change this to true if you want to turn this off
keycloak.secure-server.token-minimum-time-to-live=The adapter will refresh the token if the current token is expired OR will expire in 'token-minimum-time-to-live' seconds or less
keycloak.secure-server.min-time-between-jwks-requests=If adapter recognize token signed by unknown public key, it will try to download new public key from keycloak server. However it won't try to download if already tried it in less than 'min-time-between-jwks-requests' seconds
keycloak.secure-server.ignore-oauth-query-parameter=disable query parameter parsing for access_token
keycloak.secure-deployment.credential=Credential value
keycloak.secure-server.credential=Credential value
keycloak.credential=Credential
keycloak.credential.value=Credential value
@@ -38,7 +38,6 @@
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="realm" maxOccurs="unbounded" minOccurs="0" type="realm-type"/>
<xs:element name="secure-deployment" maxOccurs="unbounded" minOccurs="0" type="secure-deployment-type"/>
<xs:element name="secure-server" maxOccurs="unbounded" minOccurs="0" type="secure-deployment-type"/>
</xs:choice>
</xs:complexType>
@@ -85,7 +84,7 @@
<xs:element name="allow-any-hostname" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="use-resource-role-mappings" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="cors-max-age" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:element name="auth-server-url" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="auth-server-url" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="realm" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="disable-trust-manager" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="cors-allowed-methods" type="xs:string" minOccurs="0" maxOccurs="1"/>
@@ -100,9 +99,9 @@
<xs:element name="connection-pool-size" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:element name="expose-token" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
<xs:element name="ssl-required" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="realm-public-key" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="credential" type="credential-type" minOccurs="0" maxOccurs="1"/>
<xs:element name="redirect-rewrite-rule" type="redirect-rewrite-rule-type" minOccurs="0" maxOccurs="1"/>
<xs:element name="realm-public-key" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="credential" type="credential-type" minOccurs="1" maxOccurs="1"/>
<xs:element name="redirect-rewrite-rule" type="redirect-rewrite-rule-type" minOccurs="1" maxOccurs="1"/>
<xs:element name="auth-server-url-for-backend-requests" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="always-refresh-token" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
<xs:element name="register-node-at-startup" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
@@ -73,7 +73,7 @@ public class SubsystemParsingTestCase extends AbstractSubsystemBaseTest {
ModelNode deployment = new ModelNode();
deployment.get("realm").set("demo");
deployment.get("resource").set("customer-portal");
service.addSecureDeployment(deploymentOp, deployment, false);
service.addSecureDeployment(deploymentOp, deployment);
addCredential(addr, service, "secret", "secret1");
addCredential(addr, service, "jwt.client-keystore-file", "/tmp/foo.jks");
@@ -40,10 +40,6 @@
<token-store>session</token-store>
<principal-attribute>sub</principal-attribute>
</realm>
<realm name="jboss-infra">
<realm-public-key>MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqKoq+a9MgXepmsPJDmo45qswuChW9pWjanX68oIBuI4hGvhQxFHryCow230A+sr7tFdMQMt8f1l/ysmV/fYAuW29WaoY4kI4Ou1yYPuwywKSsxT6PooTs83hKyZ1h4LZMj5DkLGDDDyVRHob2WmPaYg9RGVRw3iGGsD/p+Yb+L/gnBYQnZZ7lYqmN7h36p5CkzzlgXQA1Ha8sQxL+rJNH8+sZm0vBrKsoII3Of7TqHGsm1RwFV3XCuGJ7S61AbjJMXL5DQgJl9Z5scvxGAyoRLKC294UgMnQdzyBTMPw2GybxkRKmiK2KjQKmcopmrJp/Bt6fBR6ZkGSs9qUlxGHgwIDAQAB</realm-public-key>
<auth-server-url>http://localhost:8180/auth</auth-server-url>
</realm>
<secure-deployment name="web-console">
<realm>master</realm>
<resource>web-console</resource>
@@ -73,16 +69,4 @@
</credential>
<redirect-rewrite-rule name="^/wsmaster/api/(.*)$">/api/$1/</redirect-rewrite-rule>
</secure-deployment>
<secure-deployment name="wildfly-management">
<realm>jboss-infra</realm>
<resource>wildfly-management</resource>
<bearer-only>true</bearer-only>
<ssl-required>EXTERNAL</ssl-required>
<principal-attribute>preferred_username</principal-attribute>
</secure-deployment>
<secure-server name="wildfly-console">
<realm>jboss-infra</realm>
<resource>wildfly-console</resource>
<public-client>true</public-client>
</secure-server>
</subsystem>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>3.4.0.Final</version>
<version>3.2.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<name>Keycloak Adapters</name>
Loaded 100 of 1867 files, more files were not shown because too many files have changed in this diff. Show more