refactor adapters

This commit is contained in:
Bill Burke 2014-03-06 21:13:55 -05:00
parent 0fd0240be7
commit a653e5a406
43 changed files with 674 additions and 927 deletions

View file

@ -15,7 +15,6 @@ public class AbstractOAuthClient {
public static final String OAUTH_TOKEN_REQUEST_STATE = "OAuth_Token_Request_State";
protected String clientId;
protected Map<String, String> credentials;
protected KeyStore truststore;
protected String authUrl;
protected String codeUrl;
protected String refreshUrl;
@ -46,20 +45,10 @@ public class AbstractOAuthClient {
this.credentials = credentials;
}
public KeyStore getTruststore() {
return truststore;
}
public void setTruststore(KeyStore truststore) {
this.truststore = truststore;
}
public String getAuthUrl() {
return authUrl;
}
public void setAuthUrl(String authUrl) {
this.authUrl = authUrl;
}

View file

@ -1,6 +1,5 @@
package org.keycloak;
import org.keycloak.adapters.ResourceMetadata;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.IDToken;
@ -15,17 +14,15 @@ public class KeycloakSecurityContext implements Serializable {
protected AccessToken token;
protected IDToken idToken;
protected String idTokenString;
protected transient ResourceMetadata metadata;
public KeycloakSecurityContext() {
}
public KeycloakSecurityContext(String tokenString, AccessToken token, String idTokenString, IDToken idToken, ResourceMetadata metadata) {
public KeycloakSecurityContext(String tokenString, AccessToken token, String idTokenString, IDToken idToken) {
this.tokenString = tokenString;
this.token = token;
this.idToken = idToken;
this.idTokenString = idTokenString;
this.metadata = metadata;
}
public AccessToken getToken() {
@ -36,14 +33,6 @@ public class KeycloakSecurityContext implements Serializable {
return tokenString;
}
public ResourceMetadata getMetadata() {
return metadata;
}
public void setMetadata(ResourceMetadata metadata) {
this.metadata = metadata;
}
public IDToken getIdToken() {
return idToken;
}

View file

@ -1,90 +0,0 @@
package org.keycloak.adapters;
import java.security.KeyStore;
import java.security.PublicKey;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ResourceMetadata {
protected String realm;
protected String resourceName;
protected KeyStore clientKeystore;
protected String clientKeyPassword;
protected KeyStore truststore;
protected PublicKey realmKey;
protected String scope;
public String getResourceName() {
return resourceName;
}
public String getRealm() {
return realm;
}
/**
* keystore that contains service's private key and certificate.
* Used when making invocations on remote HTTPS endpoints that require client-cert authentication
*
* @return
*/
public KeyStore getClientKeystore() {
return clientKeystore;
}
public String getClientKeyPassword() {
return clientKeyPassword;
}
public void setClientKeyPassword(String clientKeyPassword) {
this.clientKeyPassword = clientKeyPassword;
}
/**
* Truststore to use if this service makes client invocations on remote HTTPS endpoints.
*
* @return
*/
public KeyStore getTruststore() {
return truststore;
}
/**
* Public key of the realm. Used to verify access tokens
*
* @return
*/
public PublicKey getRealmKey() {
return realmKey;
}
public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}
public void setRealm(String realm) {
this.realm = realm;
}
public void setClientKeystore(KeyStore clientKeystore) {
this.clientKeystore = clientKeystore;
}
public void setTruststore(KeyStore truststore) {
this.truststore = truststore;
}
public void setRealmKey(PublicKey realmKey) {
this.realmKey = realmKey;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
}

View file

@ -0,0 +1,21 @@
package org.keycloak.util;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeystoreUtil {
public static KeyStore loadKeyStore(String filename, String password) throws Exception {
KeyStore trustStore = KeyStore.getInstance(KeyStore
.getDefaultType());
File truststoreFile = new File(filename);
FileInputStream trustStream = new FileInputStream(truststoreFile);
trustStore.load(trustStream, password.toCharArray());
trustStream.close();
return trustStore;
}
}

View file

@ -10,7 +10,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.keycloak.example.demo</groupId>
<artifactId>customer-portal-cli-example</artifactId>
<packaging>war</packaging>
<packaging>jar</packaging>
<name>Customer Portal CLI</name>
<description/>
@ -62,7 +62,10 @@
<plugin>
<groupId>org.jboss.as.plugins</groupId>
<artifactId>jboss-as-maven-plugin</artifactId>
<version>7.4.Final</version>
<version>7.1.1.Final</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>

View file

@ -46,8 +46,7 @@ public class CustomerDatabaseClient {
KeycloakSecurityContext session = (KeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
HttpClient client = new HttpClientBuilder()
.trustStore(session.getMetadata().getTruststore())
.hostnameVerification(HttpClientBuilder.HostnameVerificationPolicy.ANY).build();
.disableTrustManager().build();
try {
HttpGet get = new HttpGet("http://localhost:8080/database/customers");
get.addHeader("Authorization", "Bearer " + session.getTokenString());

View file

@ -37,8 +37,7 @@ public class ProductDatabaseClient
public static List<String> getProducts(HttpServletRequest req) throws Failure {
KeycloakSecurityContext session = (KeycloakSecurityContext)req.getAttribute(KeycloakSecurityContext.class.getName());
HttpClient client = new HttpClientBuilder()
.trustStore(session.getMetadata().getTruststore())
.hostnameVerification(HttpClientBuilder.HostnameVerificationPolicy.ANY).build();
.disableTrustManager().build();
try {
HttpGet get = new HttpGet("http://localhost:8080/database/products");
get.addHeader("Authorization", "Bearer " + session.getTokenString());

View file

@ -12,7 +12,7 @@ import javax.servlet.annotation.WebListener;
import org.jboss.logging.Logger;
import org.keycloak.servlet.ServletOAuthClient;
import org.keycloak.servlet.ServletOAuthClientConfigLoader;
import org.keycloak.servlet.ServletOAuthClientBuilder;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -40,12 +40,7 @@ public class AppContextListener implements ServletContextListener {
throw new RuntimeException(e);
}
}
ServletOAuthClientConfigLoader loader = new ServletOAuthClientConfigLoader(is);
loader.initOAuthClientConfiguration(true);
loader.configureServletOAuthClient(oauthClient);
oauthClient.start();
ServletOAuthClientBuilder.build(is, oauthClient);
logger.info("OAuth client configured and started");
}

View file

@ -1,7 +1,7 @@
package org.keycloak.example.oauth;
import org.keycloak.servlet.ServletOAuthClient;
import org.keycloak.servlet.ServletOAuthClientConfigLoader;
import org.keycloak.servlet.ServletOAuthClientBuilder;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
@ -23,16 +23,6 @@ public class Bootstrap implements ServletContextListener {
private ServletOAuthClient client;
private static KeyStore loadKeyStore(String filename, String password) throws Exception {
KeyStore trustStore = KeyStore.getInstance(KeyStore
.getDefaultType());
File truststoreFile = new File(filename);
FileInputStream trustStream = new FileInputStream(truststoreFile);
trustStore.load(trustStream, password.toCharArray());
trustStream.close();
return trustStore;
}
@Override
public void contextInitialized(ServletContextEvent sce) {
client = new ServletOAuthClient();
@ -62,8 +52,6 @@ public class Bootstrap implements ServletContextListener {
}
}
ServletOAuthClientConfigLoader loader = new ServletOAuthClientConfigLoader(is);
loader.initOAuthClientConfiguration(true);
loader.configureServletOAuthClient(client);
client = ServletOAuthClientBuilder.build(is);
}
}

View file

@ -15,6 +15,9 @@ import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.keycloak.util.EnvUtil;
import org.keycloak.util.KeystoreUtil;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
@ -271,4 +274,41 @@ public class HttpClientBuilder {
}
}
public HttpClient build(AdapterConfig adapterConfig) {
String truststorePath = adapterConfig.getTruststore();
if (truststorePath != null) {
truststorePath = EnvUtil.replace(truststorePath);
String truststorePassword = adapterConfig.getTruststorePassword();
try {
this.truststore = KeystoreUtil.loadKeyStore(truststorePath, truststorePassword);
} catch (Exception e) {
throw new RuntimeException("Failed to load truststore", e);
}
}
String clientKeystore = adapterConfig.getClientKeystore();
if (clientKeystore != null) {
clientKeystore = EnvUtil.replace(clientKeystore);
String clientKeystorePassword = adapterConfig.getClientKeystorePassword();
try {
KeyStore clientCertKeystore = KeystoreUtil.loadKeyStore(clientKeystore, clientKeystorePassword);
keyStore(clientCertKeystore, clientKeystorePassword);
} catch (Exception e) {
throw new RuntimeException("Failed to load keystore", e);
}
}
int size = 10;
if (adapterConfig.getConnectionPoolSize() > 0)
size = adapterConfig.getConnectionPoolSize();
HttpClientBuilder.HostnameVerificationPolicy policy = HttpClientBuilder.HostnameVerificationPolicy.WILDCARD;
if (adapterConfig.isAllowAnyHostname())
policy = HttpClientBuilder.HostnameVerificationPolicy.ANY;
connectionPoolSize(size);
hostnameVerification(policy);
if (adapterConfig.isDisableTrustManager()) {
disableTrustManager();
} else {
trustStore(truststore);
}
return build();
}
}

View file

@ -0,0 +1,197 @@
package org.keycloak.adapters;
import org.apache.http.client.HttpClient;
import org.keycloak.util.KeycloakUriBuilder;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakDeployment {
protected String realm;
protected PublicKey realmKey;
protected KeycloakUriBuilder authUrl;
protected String codeUrl;
protected String refreshUrl;
protected String resourceName;
protected boolean bearerOnly;
protected boolean publicClient;
protected Map<String, String> resourceCredentials = new HashMap<String, String>();
protected HttpClient client;
protected String scope;
protected boolean sslRequired = true;
protected String stateCookieName = "OAuth_Token_Request_State";
protected boolean useResourceRoleMappings;
protected boolean cors;
protected int corsMaxAge = -1;
protected String corsAllowedHeaders;
protected String corsAllowedMethods;
protected boolean exposeToken;
protected volatile int notBefore;
public String getResourceName() {
return resourceName;
}
public String getRealm() {
return realm;
}
public void setRealm(String realm) {
this.realm = realm;
}
public PublicKey getRealmKey() {
return realmKey;
}
public void setRealmKey(PublicKey realmKey) {
this.realmKey = realmKey;
}
public KeycloakUriBuilder getAuthUrl() {
return authUrl;
}
public void setAuthUrl(KeycloakUriBuilder authUrl) {
this.authUrl = authUrl;
}
public String getCodeUrl() {
return codeUrl;
}
public void setCodeUrl(String codeUrl) {
this.codeUrl = codeUrl;
}
public String getRefreshUrl() {
return refreshUrl;
}
public void setRefreshUrl(String refreshUrl) {
this.refreshUrl = refreshUrl;
}
public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}
public boolean isBearerOnly() {
return bearerOnly;
}
public void setBearerOnly(boolean bearerOnly) {
this.bearerOnly = bearerOnly;
}
public boolean isPublicClient() {
return publicClient;
}
public void setPublicClient(boolean publicClient) {
this.publicClient = publicClient;
}
public Map<String, String> getResourceCredentials() {
return resourceCredentials;
}
public void setResourceCredentials(Map<String, String> resourceCredentials) {
this.resourceCredentials = resourceCredentials;
}
public HttpClient getClient() {
return client;
}
public void setClient(HttpClient client) {
this.client = client;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public boolean isSslRequired() {
return sslRequired;
}
public void setSslRequired(boolean sslRequired) {
this.sslRequired = sslRequired;
}
public String getStateCookieName() {
return stateCookieName;
}
public void setStateCookieName(String stateCookieName) {
this.stateCookieName = stateCookieName;
}
public boolean isUseResourceRoleMappings() {
return useResourceRoleMappings;
}
public void setUseResourceRoleMappings(boolean useResourceRoleMappings) {
this.useResourceRoleMappings = useResourceRoleMappings;
}
public boolean isCors() {
return cors;
}
public void setCors(boolean cors) {
this.cors = cors;
}
public int getCorsMaxAge() {
return corsMaxAge;
}
public void setCorsMaxAge(int corsMaxAge) {
this.corsMaxAge = corsMaxAge;
}
public String getCorsAllowedHeaders() {
return corsAllowedHeaders;
}
public void setCorsAllowedHeaders(String corsAllowedHeaders) {
this.corsAllowedHeaders = corsAllowedHeaders;
}
public String getCorsAllowedMethods() {
return corsAllowedMethods;
}
public void setCorsAllowedMethods(String corsAllowedMethods) {
this.corsAllowedMethods = corsAllowedMethods;
}
public boolean isExposeToken() {
return exposeToken;
}
public void setExposeToken(boolean exposeToken) {
this.exposeToken = exposeToken;
}
public int getNotBefore() {
return notBefore;
}
public void setNotBefore(int notBefore) {
this.notBefore = notBefore;
}
}

View file

@ -0,0 +1,95 @@
package org.keycloak.adapters;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.keycloak.ServiceUrlConstants;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.keycloak.util.EnvUtil;
import org.keycloak.util.KeycloakUriBuilder;
import org.keycloak.util.KeystoreUtil;
import org.keycloak.util.PemUtils;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PublicKey;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class KeycloakDeploymentBuilder {
protected KeycloakDeployment deployment = new KeycloakDeployment();
protected KeycloakDeploymentBuilder() {}
protected KeycloakDeployment internalBuild(AdapterConfig adapterConfig) {
if (adapterConfig.getRealm() == null) throw new RuntimeException("Must set 'realm' in config");
deployment.setRealm(adapterConfig.getRealm());
String resource = adapterConfig.getResource();
if (resource == null) throw new RuntimeException("Must set 'resource' in config");
deployment.setResourceName(resource);
String realmKeyPem = adapterConfig.getRealmKey();
if (realmKeyPem == null) {
throw new IllegalArgumentException("You must set the realm-public-key");
}
PublicKey realmKey = null;
try {
realmKey = PemUtils.decodePublicKey(realmKeyPem);
} catch (Exception e) {
throw new RuntimeException(e);
}
deployment.setRealmKey(realmKey);
deployment.setSslRequired(!adapterConfig.isSslNotRequired());
deployment.setResourceCredentials(adapterConfig.getCredentials());
deployment.setPublicClient(adapterConfig.isPublicClient());
if (adapterConfig.isBearerOnly()) {
deployment.setBearerOnly(true);
return deployment;
}
deployment.setClient(new HttpClientBuilder().build(adapterConfig));
if (adapterConfig.getAuthServerUrl() == null) {
throw new RuntimeException("You must specify auth-url");
}
KeycloakUriBuilder serverBuilder = KeycloakUriBuilder.fromUri(adapterConfig.getAuthServerUrl());
String authUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_LOGIN_PATH).build(adapterConfig.getRealm()).toString();
String tokenUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_ACCESS_CODE_PATH).build(adapterConfig.getRealm()).toString();
String refreshUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_REFRESH_PATH).build(adapterConfig.getRealm()).toString();
deployment.setAuthUrl(KeycloakUriBuilder.fromUri(authUrl).queryParam("client_id", deployment.getResourceName()));
deployment.setCodeUrl(tokenUrl);
deployment.setRefreshUrl(refreshUrl);
return deployment;
}
public static KeycloakDeployment build(InputStream is) {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
AdapterConfig adapterConfig = null;
try {
adapterConfig = mapper.readValue(is, AdapterConfig.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
return new KeycloakDeploymentBuilder().internalBuild(adapterConfig);
}
public static KeycloakDeployment build(AdapterConfig adapterConfig) {
return new KeycloakDeploymentBuilder().internalBuild(adapterConfig);
}
}

View file

@ -3,7 +3,6 @@ package org.keycloak.adapters;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.RSATokenVerifier;
import org.keycloak.VerificationException;
import org.keycloak.adapters.config.RealmConfiguration;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.AccessTokenResponse;
import org.jboss.logging.Logger;
@ -19,15 +18,15 @@ public class RefreshableKeycloakSession extends KeycloakSecurityContext {
protected static Logger log = Logger.getLogger(RefreshableKeycloakSession.class);
protected transient RealmConfiguration realmConfiguration;
protected transient KeycloakDeployment deployment;
protected String refreshToken;
public RefreshableKeycloakSession() {
}
public RefreshableKeycloakSession(String tokenString, AccessToken token, String idTokenString, IDToken idToken, ResourceMetadata metadata, RealmConfiguration realmConfiguration, String refreshToken) {
super(tokenString, token, idTokenString, idToken, metadata);
this.realmConfiguration = realmConfiguration;
public RefreshableKeycloakSession(KeycloakDeployment deployment, String tokenString, AccessToken token, String idTokenString, IDToken idToken, String refreshToken) {
super(tokenString, token, idTokenString, idToken);
this.deployment = deployment;
this.refreshToken = refreshToken;
}
@ -44,22 +43,22 @@ public class RefreshableKeycloakSession extends KeycloakSecurityContext {
}
public boolean isActive() {
return this.token.isActive() && this.token.getIssuedAt() > realmConfiguration.getNotBefore();
return this.token.isActive() && this.token.getIssuedAt() > deployment.getNotBefore();
}
public void setRealmConfiguration(RealmConfiguration realmConfiguration) {
this.realmConfiguration = realmConfiguration;
public void setDeployment(KeycloakDeployment deployment) {
this.deployment = deployment;
}
public void refreshExpiredToken() {
log.info("checking whether to refresh.");
if (isActive()) return;
if (this.realmConfiguration == null || refreshToken == null) return; // Might be serialized in HttpSession?
if (this.deployment == null || refreshToken == null) return; // Might be serialized in HttpSession?
log.info("Doing refresh");
AccessTokenResponse response = null;
try {
response = ServerRequest.invokeRefresh(realmConfiguration, refreshToken);
response = ServerRequest.invokeRefresh(deployment, refreshToken);
} catch (IOException e) {
log.error("Refresh token failure", e);
return;
@ -71,13 +70,13 @@ public class RefreshableKeycloakSession extends KeycloakSecurityContext {
String tokenString = response.getToken();
AccessToken token = null;
try {
token = RSATokenVerifier.verifyToken(tokenString, realmConfiguration.getMetadata().getRealmKey(), realmConfiguration.getMetadata().getRealm());
token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealm());
log.info("Token Verification succeeded!");
} catch (VerificationException e) {
log.error("failed verification of token");
}
if (response.getNotBeforePolicy() > realmConfiguration.getNotBefore()) {
realmConfiguration.setNotBefore(response.getNotBeforePolicy());
if (response.getNotBeforePolicy() > deployment.getNotBefore()) {
deployment.setNotBefore(response.getNotBeforePolicy());
}
this.token = token;

View file

@ -7,9 +7,7 @@ import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.keycloak.adapters.config.RealmConfiguration;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.util.BasicAuthHelper;
import org.keycloak.util.JsonSerialization;
@ -47,13 +45,13 @@ public class ServerRequest {
}
}
public static AccessTokenResponse invokeAccessCodeToToken(RealmConfiguration config, String code, String redirectUri) throws HttpFailure, IOException {
String codeUrl = config.getCodeUrl();
String client_id = config.getMetadata().getResourceName();
Map<String, String> credentials = config.getResourceCredentials();
HttpClient client = config.getClient();
public static AccessTokenResponse invokeAccessCodeToToken(KeycloakDeployment deployment, String code, String redirectUri) throws HttpFailure, IOException {
String codeUrl = deployment.getCodeUrl();
String client_id = deployment.getResourceName();
Map<String, String> credentials = deployment.getResourceCredentials();
HttpClient client = deployment.getClient();
return invokeAccessCodeToToken(client, config.isPublicClient(), code, codeUrl, redirectUri, client_id, credentials);
return invokeAccessCodeToToken(client, deployment.isPublicClient(), code, codeUrl, redirectUri, client_id, credentials);
}
public static AccessTokenResponse invokeAccessCodeToToken(HttpClient client, boolean publicClient, String code, String codeUrl, String redirectUri, String client_id, Map<String, String> credentials) throws IOException, HttpFailure {
@ -108,12 +106,12 @@ public class ServerRequest {
}
}
public static AccessTokenResponse invokeRefresh(RealmConfiguration config, String refreshToken) throws IOException, HttpFailure {
String refreshUrl = config.getRefreshUrl();
String client_id = config.getMetadata().getResourceName();
Map<String, String> credentials = config.getResourceCredentials();
HttpClient client = config.getClient();
return invokeRefresh(client, config.isPublicClient(), refreshToken, refreshUrl, client_id, credentials);
public static AccessTokenResponse invokeRefresh(KeycloakDeployment deployment, String refreshToken) throws IOException, HttpFailure {
String refreshUrl = deployment.getRefreshUrl();
String client_id = deployment.getResourceName();
Map<String, String> credentials = deployment.getResourceCredentials();
HttpClient client = deployment.getClient();
return invokeRefresh(client, deployment.isPublicClient(), refreshToken, refreshUrl, client_id, credentials);
}

View file

@ -1,123 +0,0 @@
package org.keycloak.adapters.config;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.keycloak.util.EnvUtil;
import org.keycloak.util.PemUtils;
import org.keycloak.adapters.ResourceMetadata;
import org.keycloak.representations.adapters.config.AdapterConfig;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PublicKey;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class AdapterConfigLoader {
protected AdapterConfig adapterConfig;
protected ResourceMetadata resourceMetadata;
protected KeyStore clientCertKeystore;
protected KeyStore truststore;
public static KeyStore loadKeyStore(String filename, String password) throws Exception {
KeyStore trustStore = KeyStore.getInstance(KeyStore
.getDefaultType());
File truststoreFile = new File(filename);
FileInputStream trustStream = new FileInputStream(truststoreFile);
trustStore.load(trustStream, password.toCharArray());
trustStream.close();
return trustStore;
}
public void init() {
initTruststore();
initClientKeystore();
String realm = adapterConfig.getRealm();
if (realm == null) throw new RuntimeException("Must set 'realm' in config");
String resource = adapterConfig.getResource();
if (resource == null) throw new RuntimeException("Must set 'resource' in config");
String realmKeyPem = adapterConfig.getRealmKey();
if (realmKeyPem == null) {
throw new IllegalArgumentException("You must set the realm-public-key");
}
PublicKey realmKey = null;
try {
realmKey = PemUtils.decodePublicKey(realmKeyPem);
} catch (Exception e) {
throw new RuntimeException(e);
}
resourceMetadata = new ResourceMetadata();
resourceMetadata.setRealm(realm);
resourceMetadata.setResourceName(resource);
resourceMetadata.setRealmKey(realmKey);
resourceMetadata.setClientKeystore(clientCertKeystore);
String clientKeyPassword = adapterConfig.getClientKeyPassword();
resourceMetadata.setClientKeyPassword(clientKeyPassword);
resourceMetadata.setTruststore(this.truststore);
}
public AdapterConfig getAdapterConfig() {
return adapterConfig;
}
public ResourceMetadata getResourceMetadata() {
return resourceMetadata;
}
public KeyStore getClientCertKeystore() {
return clientCertKeystore;
}
public KeyStore getTruststore() {
return truststore;
}
protected void loadConfig(InputStream is) {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
adapterConfig = null;
try {
adapterConfig = mapper.readValue(is, AdapterConfig.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
protected void initTruststore() {
String truststorePath = adapterConfig.getTruststore();
if (truststorePath != null) {
truststorePath = EnvUtil.replace(truststorePath);
String truststorePassword = adapterConfig.getTruststorePassword();
try {
this.truststore = loadKeyStore(truststorePath, truststorePassword);
} catch (Exception e) {
throw new RuntimeException("Failed to load truststore", e);
}
}
}
protected void initClientKeystore() {
String clientKeystore = adapterConfig.getClientKeystore();
if (clientKeystore != null) {
clientKeystore = EnvUtil.replace(clientKeystore);
String clientKeystorePassword = adapterConfig.getClientKeystorePassword();
clientCertKeystore = null;
try {
clientCertKeystore = loadKeyStore(clientKeystore, clientKeystorePassword);
} catch (Exception e) {
throw new RuntimeException("Failed to load keystore", e);
}
}
}
}

View file

@ -1,45 +0,0 @@
package org.keycloak.adapters.config;
import java.io.InputStream;
import org.keycloak.AbstractOAuthClient;
import org.keycloak.ServiceUrlConstants;
import org.keycloak.util.KeycloakUriBuilder;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public abstract class OAuthClientConfigLoader extends RealmConfigurationLoader {
public OAuthClientConfigLoader() {
}
public OAuthClientConfigLoader(InputStream is) {
super(is);
}
/**
* For now, configure just things supported by AbstractOAuthClient
*/
public void initOAuthClientConfiguration() {
initTruststore();
initClientKeystore();
}
public void configureOAuthClient(AbstractOAuthClient oauthClient) {
oauthClient.setClientId(adapterConfig.getResource());
oauthClient.setPublicClient(adapterConfig.isPublicClient());
oauthClient.setCredentials(adapterConfig.getCredentials());
if (adapterConfig.getAuthServerUrl() == null) {
throw new RuntimeException("You must specify auth-url");
}
KeycloakUriBuilder serverBuilder = KeycloakUriBuilder.fromUri(adapterConfig.getAuthServerUrl());
String authUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_LOGIN_PATH).build(adapterConfig.getRealm()).toString();
String tokenUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_ACCESS_CODE_PATH).build(adapterConfig.getRealm()).toString();
String refreshUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_REFRESH_PATH).build(adapterConfig.getRealm()).toString();
oauthClient.setAuthUrl(authUrl);
oauthClient.setCodeUrl(tokenUrl);
oauthClient.setRefreshUrl(refreshUrl);
oauthClient.setTruststore(truststore);
}
}

View file

@ -1,109 +0,0 @@
package org.keycloak.adapters.config;
import org.apache.http.client.HttpClient;
import org.keycloak.adapters.ResourceMetadata;
import org.keycloak.util.KeycloakUriBuilder;
import java.util.HashMap;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class RealmConfiguration {
protected ResourceMetadata metadata;
protected HttpClient client;
protected KeycloakUriBuilder authUrl;
protected String codeUrl;
protected String refreshUrl;
protected boolean publicClient;
protected Map<String, String> resourceCredentials = new HashMap<String, String>();
protected boolean sslRequired = true;
protected String stateCookieName = "OAuth_Token_Request_State";
protected volatile int notBefore;
public RealmConfiguration() {
}
public ResourceMetadata getMetadata() {
return metadata;
}
public void setMetadata(ResourceMetadata metadata) {
this.metadata = metadata;
}
public boolean isSslRequired() {
return sslRequired;
}
public void setSslRequired(boolean sslRequired) {
this.sslRequired = sslRequired;
}
public String getStateCookieName() {
return stateCookieName;
}
public void setStateCookieName(String stateCookieName) {
this.stateCookieName = stateCookieName;
}
public HttpClient getClient() {
return client;
}
public void setClient(HttpClient client) {
this.client = client;
}
public KeycloakUriBuilder getAuthUrl() {
return authUrl;
}
public void setAuthUrl(KeycloakUriBuilder authUrl) {
this.authUrl = authUrl;
}
public String getCodeUrl() {
return codeUrl;
}
public void setCodeUrl(String codeUrl) {
this.codeUrl = codeUrl;
}
public String getRefreshUrl() {
return refreshUrl;
}
public void setRefreshUrl(String refreshUrl) {
this.refreshUrl = refreshUrl;
}
public Map<String, String> getResourceCredentials() {
return resourceCredentials;
}
public void setResourceCredentials(Map<String, String> resourceCredentials) {
this.resourceCredentials = resourceCredentials;
}
public int getNotBefore() {
return notBefore;
}
public void setNotBefore(int notBefore) {
this.notBefore = notBefore;
}
public boolean isPublicClient() {
return publicClient;
}
public void setPublicClient(boolean publicClient) {
this.publicClient = publicClient;
}
}

View file

@ -1,82 +0,0 @@
package org.keycloak.adapters.config;
import org.apache.http.client.HttpClient;
import org.keycloak.ServiceUrlConstants;
import org.keycloak.adapters.HttpClientBuilder;
import org.keycloak.util.KeycloakUriBuilder;
import java.io.InputStream;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class RealmConfigurationLoader extends AdapterConfigLoader {
protected HttpClient client;
protected RealmConfiguration realmConfiguration;
public RealmConfigurationLoader() {
}
public RealmConfigurationLoader(InputStream is) {
loadConfig(is);
}
public void init(boolean setupClient) {
init();
initRealmConfiguration(setupClient);
}
protected void initRealmConfiguration(boolean setupClient) {
realmConfiguration = new RealmConfiguration();
realmConfiguration.setMetadata(resourceMetadata);
realmConfiguration.setSslRequired(!adapterConfig.isSslNotRequired());
realmConfiguration.setResourceCredentials(adapterConfig.getCredentials());
realmConfiguration.setPublicClient(adapterConfig.isPublicClient());
if (!setupClient || adapterConfig.isBearerOnly()) return;
initClient();
if (adapterConfig.getAuthServerUrl() == null) {
throw new RuntimeException("You must specify auth-url");
}
KeycloakUriBuilder serverBuilder = KeycloakUriBuilder.fromUri(adapterConfig.getAuthServerUrl());
String authUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_LOGIN_PATH).build(adapterConfig.getRealm()).toString();
String tokenUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_ACCESS_CODE_PATH).build(adapterConfig.getRealm()).toString();
String refreshUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_REFRESH_PATH).build(adapterConfig.getRealm()).toString();
HttpClient client = getClient();
realmConfiguration.setClient(client);
realmConfiguration.setAuthUrl(KeycloakUriBuilder.fromUri(authUrl).queryParam("client_id", resourceMetadata.getResourceName()));
realmConfiguration.setCodeUrl(tokenUrl);
realmConfiguration.setRefreshUrl(refreshUrl);
}
protected void initClient() {
int size = 10;
if (adapterConfig.getConnectionPoolSize() > 0)
size = adapterConfig.getConnectionPoolSize();
HttpClientBuilder.HostnameVerificationPolicy policy = HttpClientBuilder.HostnameVerificationPolicy.WILDCARD;
if (adapterConfig.isAllowAnyHostname())
policy = HttpClientBuilder.HostnameVerificationPolicy.ANY;
HttpClientBuilder builder = new HttpClientBuilder()
.connectionPoolSize(size)
.hostnameVerification(policy)
.keyStore(clientCertKeystore, adapterConfig.getClientKeyPassword());
if (adapterConfig.isDisableTrustManager()) {
builder.disableTrustManager();
} else {
builder.trustStore(truststore);
}
client = builder.build();
}
public HttpClient getClient() {
return client;
}
public RealmConfiguration getRealmConfiguration() {
return realmConfiguration;
}
}

View file

@ -68,8 +68,8 @@ public class SecureDeploymentDefinition extends SimpleResourceDefinition {
.setDefaultValue(new ModelNode(false))
.build();
protected static final SimpleAttributeDefinition PUBLIC_CLIENT =
new SimpleAttributeDefinitionBuilder("bearer-only", ModelType.BOOLEAN, true)
.setXmlName("bearer-only")
new SimpleAttributeDefinitionBuilder("public-client", ModelType.BOOLEAN, true)
.setXmlName("public-client")
.setAllowExpression(true)
.setDefaultValue(new ModelNode(false))
.build();

View file

@ -9,6 +9,7 @@ import org.apache.catalina.valves.ValveBase;
import org.jboss.logging.Logger;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.AdapterConstants;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.adapters.config.AdapterConfig;
@ -31,10 +32,10 @@ import java.util.Set;
*/
public class AuthenticatedActionsValve extends ValveBase {
private static final Logger log = Logger.getLogger(AuthenticatedActionsValve.class);
protected AdapterConfig config;
protected KeycloakDeployment deployment;
public AuthenticatedActionsValve(AdapterConfig config, Valve next, Container container, ObjectName controller) {
this.config = config;
public AuthenticatedActionsValve(KeycloakDeployment deployment, Valve next, Container container, ObjectName controller) {
this.deployment = deployment;
if (next == null) throw new RuntimeException("WTF is next null?!");
setNext(next);
setContainer(container);
@ -81,11 +82,11 @@ public class AuthenticatedActionsValve extends ValveBase {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return true;
}
if (!config.isExposeToken()) {
if (!deployment.isExposeToken()) {
response.setStatus(HttpServletResponse.SC_OK);
return true;
}
if (!config.isCors() && request.getHeader("Origin") != null) {
if (!deployment.isCors() && request.getHeader("Origin") != null) {
response.setStatus(HttpServletResponse.SC_OK);
return true;
}
@ -93,7 +94,7 @@ public class AuthenticatedActionsValve extends ValveBase {
}
protected boolean corsRequest(Request request, Response response, KeycloakSecurityContext session) throws IOException {
if (!config.isCors()) return false;
if (!deployment.isCors()) return false;
log.debugv("CORS enabled + request.getRequestURI()");
String origin = request.getHeader("Origin");
log.debugv("Origin: {0} uri: {1}", origin, request.getRequestURI());

View file

@ -5,7 +5,7 @@ import org.jboss.logging.Logger;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.RSATokenVerifier;
import org.keycloak.adapters.ResourceMetadata;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.VerificationException;
import org.keycloak.representations.AccessToken;
@ -22,24 +22,16 @@ import java.util.Set;
* @version $Revision: 1 $
*/
public class CatalinaBearerTokenAuthenticator {
protected ResourceMetadata resourceMetadata;
protected boolean challenge;
protected Logger log = Logger.getLogger(CatalinaBearerTokenAuthenticator.class);
protected String tokenString;
protected AccessToken token;
private Principal principal;
protected boolean useResourceRoleMappings;
protected int notBefore;
protected Principal principal;
protected KeycloakDeployment deployment;
public CatalinaBearerTokenAuthenticator(ResourceMetadata resourceMetadata, int notBefore, boolean challenge, boolean useResourceRoleMappings) {
this.resourceMetadata = resourceMetadata;
public CatalinaBearerTokenAuthenticator(KeycloakDeployment deployment, boolean challenge) {
this.deployment = deployment;
this.challenge = challenge;
this.useResourceRoleMappings = useResourceRoleMappings;
this.notBefore = notBefore;
}
public ResourceMetadata getResourceMetadata() {
return resourceMetadata;
}
public String getTokenString() {
@ -73,23 +65,23 @@ public class CatalinaBearerTokenAuthenticator {
tokenString = split[1];
try {
token = RSATokenVerifier.verifyToken(tokenString, resourceMetadata.getRealmKey(), resourceMetadata.getRealm());
token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealm());
} catch (VerificationException e) {
log.error("Failed to verify token", e);
challengeResponse(response, "invalid_token", e.getMessage());
}
if (token.getIssuedAt() < notBefore) {
if (token.getIssuedAt() < deployment.getNotBefore()) {
log.error("Stale token");
challengeResponse(response, "invalid_token", "Stale token");
}
boolean verifyCaller = false;
Set<String> roles = new HashSet<String>();
if (useResourceRoleMappings) {
AccessToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName());
if (deployment.isUseResourceRoleMappings()) {
AccessToken.Access access = token.getResourceAccess(deployment.getResourceName());
if (access != null) roles = access.getRoles();
verifyCaller = token.isVerifyCaller(resourceMetadata.getResourceName());
verifyCaller = token.isVerifyCaller(deployment.getResourceName());
} else {
verifyCaller = token.isVerifyCaller();
AccessToken.Access access = token.getRealmAccess();
@ -114,7 +106,7 @@ public class CatalinaBearerTokenAuthenticator {
principal = new CatalinaSecurityContextHelper().createPrincipal(request.getContext().getRealm(), skeletonKeyPrincipal, roles);
request.setUserPrincipal(principal);
request.setAuthType("KEYCLOAK");
KeycloakSecurityContext skSession = new KeycloakSecurityContext(tokenString, token, null, null, resourceMetadata);
KeycloakSecurityContext skSession = new KeycloakSecurityContext(tokenString, token, null, null);
request.setAttribute(KeycloakSecurityContext.class.getName(), skSession);
return true;
@ -123,7 +115,7 @@ public class CatalinaBearerTokenAuthenticator {
protected void challengeResponse(HttpServletResponse response, String error, String description) throws LoginException {
StringBuilder header = new StringBuilder("Bearer realm=\"");
header.append(resourceMetadata.getRealm()).append("\"");
header.append(deployment.getRealm()).append("\"");
if (error != null) {
header.append(", error=\"").append(error).append("\"");
}

View file

@ -3,6 +3,7 @@ package org.keycloak.adapters.as7;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.jboss.logging.Logger;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.representations.adapters.config.AdapterConfig;
import javax.servlet.http.HttpServletResponse;
@ -13,10 +14,10 @@ import javax.servlet.http.HttpServletResponse;
*/
public class CorsPreflightChecker {
private static final Logger log = Logger.getLogger(CorsPreflightChecker.class);
protected AdapterConfig config;
protected KeycloakDeployment deployment;
public CorsPreflightChecker(AdapterConfig config) {
this.config = config;
public CorsPreflightChecker(KeycloakDeployment deployment) {
this.deployment = deployment;
}
public boolean checkCorsPreflight(Request request, Response response) {
@ -37,20 +38,20 @@ public class CorsPreflightChecker {
response.setHeader("Access-Control-Allow-Credentials", "true");
String requestMethods = request.getHeader("Access-Control-Request-Method");
if (requestMethods != null) {
if (config.getCorsAllowedMethods() != null) {
requestMethods = config.getCorsAllowedMethods();
if (deployment.getCorsAllowedMethods() != null) {
requestMethods = deployment.getCorsAllowedMethods();
}
response.setHeader("Access-Control-Allow-Methods", requestMethods);
}
String allowHeaders = request.getHeader("Access-Control-Request-Headers");
if (allowHeaders != null) {
if (config.getCorsAllowedHeaders() != null) {
allowHeaders = config.getCorsAllowedHeaders();
if (deployment.getCorsAllowedHeaders() != null) {
allowHeaders = deployment.getCorsAllowedHeaders();
}
response.setHeader("Access-Control-Allow-Headers", allowHeaders);
}
if (config.getCorsMaxAge() > -1) {
response.setHeader("Access-Control-Max-Age", Integer.toString(config.getCorsMaxAge()));
if (deployment.getCorsMaxAge() > -1) {
response.setHeader("Access-Control-Max-Age", Integer.toString(deployment.getCorsMaxAge()));
}
return true;
}

View file

@ -1,5 +1,6 @@
package org.keycloak.adapters.as7;
import org.apache.catalina.Context;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleException;
@ -16,9 +17,9 @@ import org.jboss.logging.Logger;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.adapters.AdapterConstants;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.adapters.RefreshableKeycloakSession;
import org.keycloak.adapters.ResourceMetadata;
import org.keycloak.adapters.as7.config.CatalinaAdapterConfigLoader;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.adapters.action.AdminAction;
import org.keycloak.representations.adapters.action.PushNotBeforeAction;
@ -26,9 +27,6 @@ import org.keycloak.representations.adapters.action.SessionStats;
import org.keycloak.representations.adapters.action.SessionStatsAction;
import org.keycloak.representations.adapters.action.UserStats;
import org.keycloak.representations.adapters.action.UserStatsAction;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.keycloak.adapters.config.RealmConfiguration;
import org.keycloak.adapters.config.RealmConfigurationLoader;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.crypto.RSAProvider;
import org.keycloak.representations.adapters.action.LogoutAction;
@ -36,10 +34,15 @@ import org.keycloak.util.JsonSerialization;
import org.keycloak.util.StreamUtil;
import javax.security.auth.login.LoginException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@ -55,11 +58,9 @@ import java.util.Set;
* @version $Revision: 1 $
*/
public class KeycloakAuthenticatorValve extends FormAuthenticator implements LifecycleListener {
protected RealmConfiguration realmConfiguration;
private static final Logger log = Logger.getLogger(KeycloakAuthenticatorValve.class);
protected UserSessionManagement userSessionManagement = new UserSessionManagement();
protected AdapterConfig adapterConfig;
protected ResourceMetadata resourceMetadata;
protected KeycloakDeployment deployment;
@Override
@ -75,21 +76,44 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
if (event.getType() == Lifecycle.AFTER_START_EVENT) init();
}
protected void init() {
RealmConfigurationLoader configLoader = new CatalinaAdapterConfigLoader(context);
configLoader.init(true);
resourceMetadata = configLoader.getResourceMetadata();
adapterConfig = configLoader.getAdapterConfig();
private static InputStream getJSONFromServletContext(ServletContext servletContext) {
String json = servletContext.getInitParameter(AdapterConstants.AUTH_DATA_PARAM_NAME);
if (json == null) {
return null;
}
log.info("**** using " + AdapterConstants.AUTH_DATA_PARAM_NAME);
log.info(json);
return new ByteArrayInputStream(json.getBytes());
}
private static InputStream getConfigInputStream(Context context) {
InputStream is = getJSONFromServletContext(context.getServletContext());
if (is == null) {
String path = context.getServletContext().getInitParameter("keycloak.config.file");
if (path == null) {
log.info("**** using /WEB-INF/keycloak.json");
is = context.getServletContext().getResourceAsStream("/WEB-INF/keycloak.json");
} else {
try {
is = new FileInputStream(path);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
}
return is;
}
realmConfiguration = configLoader.getRealmConfiguration();
AuthenticatedActionsValve actions = new AuthenticatedActionsValve(adapterConfig, getNext(), getContainer(), getController());
protected void init() {
this.deployment = KeycloakDeploymentBuilder.build(getConfigInputStream(context));
AuthenticatedActionsValve actions = new AuthenticatedActionsValve(deployment, getNext(), getContainer(), getController());
setNext(actions);
}
@Override
public void invoke(Request request, Response response) throws IOException, ServletException {
try {
if (adapterConfig.isCors() && new CorsPreflightChecker(adapterConfig).checkCorsPreflight(request, response)) {
if (deployment.isCors() && new CorsPreflightChecker(deployment).checkCorsPreflight(request, response)) {
return;
}
String requestURI = request.getDecodedRequestURI();
@ -148,7 +172,7 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
}
// initiate or continue oauth2 protocol
if (!adapterConfig.isBearerOnly()) oauth(request, response);
if (!deployment.isBearerOnly()) oauth(request, response);
} catch (LoginException e) {
}
return false;
@ -165,7 +189,7 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
JWSInput input = new JWSInput(token);
boolean verified = false;
try {
verified = RSAProvider.verify(input, realmConfiguration.getMetadata().getRealmKey());
verified = RSAProvider.verify(input, deployment.getRealmKey());
} catch (Exception ignore) {
}
if (!verified) {
@ -188,7 +212,7 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Expired token");
return false;
}
if (!resourceMetadata.getResourceName().equals(action.getResource())) {
if (!deployment.getResourceName().equals(action.getResource())) {
log.warn("Resource name does not match");
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Resource name does not match");
return false;
@ -203,7 +227,7 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
if (!validateAction(response, action)) {
return;
}
realmConfiguration.setNotBefore(action.getNotBefore());
deployment.setNotBefore(action.getNotBefore());
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}
@ -280,8 +304,8 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
}
protected boolean bearer(boolean challenge, Request request, HttpServletResponse response) throws LoginException, IOException {
boolean useResourceRoleMappings = adapterConfig.isUseResourceRoleMappings();
CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, realmConfiguration.getNotBefore(), challenge, useResourceRoleMappings);
boolean useResourceRoleMappings = deployment.isUseResourceRoleMappings();
CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(deployment, challenge);
if (bearer.login(request, response)) {
return true;
}
@ -298,8 +322,7 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
RefreshableKeycloakSession session = (RefreshableKeycloakSession)request.getSessionInternal().getNote(KeycloakSecurityContext.class.getName());
if (session == null) return;
// just in case session got serialized
session.setRealmConfiguration(realmConfiguration);
session.setMetadata(resourceMetadata);
session.setDeployment(deployment);
if (session.isActive()) return;
// FYI: A refresh requires same scope, so same roles will be set. Otherwise, refresh will fail and token will
@ -335,7 +358,7 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
* This method always set the HTTP response, so do not continue after invoking
*/
protected void oauth(Request request, HttpServletResponse response) throws IOException {
ServletOAuthLogin oauth = new ServletOAuthLogin(realmConfiguration, request, response, request.getConnector().getRedirectPort());
ServletOAuthLogin oauth = new ServletOAuthLogin(deployment, request, response, request.getConnector().getRedirectPort());
String code = oauth.getCode();
if (code == null) {
String error = oauth.getError();
@ -352,8 +375,8 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
AccessToken token = oauth.getToken();
Set<String> roles = new HashSet<String>();
if (adapterConfig.isUseResourceRoleMappings()) {
AccessToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName());
if (deployment.isUseResourceRoleMappings()) {
AccessToken.Access access = token.getResourceAccess(deployment.getResourceName());
if (access != null) roles.addAll(access.getRoles());
} else {
AccessToken.Access access = token.getRealmAccess();
@ -364,7 +387,7 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
Session session = request.getSessionInternal(true);
session.setPrincipal(principal);
session.setAuthType("OAUTH");
KeycloakSecurityContext skSession = new RefreshableKeycloakSession(oauth.getTokenString(), oauth.getToken(), oauth.getIdTokenString(), oauth.getIdToken(), resourceMetadata, realmConfiguration, oauth.getRefreshToken());
KeycloakSecurityContext skSession = new RefreshableKeycloakSession(deployment, oauth.getTokenString(), oauth.getToken(), oauth.getIdTokenString(), oauth.getIdToken(), oauth.getRefreshToken());
session.setNote(KeycloakSecurityContext.class.getName(), skSession);
String username = token.getSubject();

View file

@ -3,8 +3,8 @@ package org.keycloak.adapters.as7;
import org.jboss.logging.Logger;
import org.keycloak.RSATokenVerifier;
import org.keycloak.VerificationException;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.ServerRequest;
import org.keycloak.adapters.config.RealmConfiguration;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.AccessTokenResponse;
@ -27,7 +27,7 @@ public class ServletOAuthLogin {
protected HttpServletRequest request;
protected HttpServletResponse response;
protected boolean codePresent;
protected RealmConfiguration realmInfo;
protected KeycloakDeployment deployment;
protected int redirectPort;
protected String tokenString;
protected String idTokenString;
@ -35,10 +35,10 @@ public class ServletOAuthLogin {
protected AccessToken token;
protected String refreshToken;
public ServletOAuthLogin(RealmConfiguration realmInfo, HttpServletRequest request, HttpServletResponse response, int redirectPort) {
public ServletOAuthLogin(KeycloakDeployment deployment, HttpServletRequest request, HttpServletResponse response, int redirectPort) {
this.request = request;
this.response = response;
this.realmInfo = realmInfo;
this.deployment = deployment;
this.redirectPort = redirectPort;
}
@ -62,10 +62,6 @@ public class ServletOAuthLogin {
return idToken;
}
public RealmConfiguration getRealmInfo() {
return realmInfo;
}
protected String getDefaultCookiePath() {
String path = request.getContextPath();
if ("".equals(path) || path == null) path = "/";
@ -145,7 +141,7 @@ public class ServletOAuthLogin {
protected String getRedirectUri(String state) {
String url = getRequestUrl();
if (!isRequestSecure() && realmInfo.isSslRequired()) {
if (!isRequestSecure() && deployment.isSslRequired()) {
int port = redirectPort;
if (port < 0) {
// disabled?
@ -155,13 +151,13 @@ public class ServletOAuthLogin {
if (port != 443) secureUrl.port(port);
url = secureUrl.build().toString();
}
KeycloakUriBuilder uriBuilder = realmInfo.getAuthUrl().clone()
.queryParam("client_id", realmInfo.getMetadata().getResourceName())
KeycloakUriBuilder uriBuilder = deployment.getAuthUrl().clone()
.queryParam("client_id", deployment.getResourceName())
.queryParam("redirect_uri", url)
.queryParam("state", state)
.queryParam("login", "true");
if (realmInfo.getMetadata().getScope() != null) {
uriBuilder.queryParam("scope", realmInfo.getMetadata().getScope());
if (deployment.getScope() != null) {
uriBuilder.queryParam("scope", deployment.getScope());
}
return uriBuilder.build().toString();
}
@ -179,12 +175,12 @@ public class ServletOAuthLogin {
sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
setCookie(realmInfo.getStateCookieName(), state, null, getDefaultCookiePath(), realmInfo.isSslRequired());
setCookie(deployment.getStateCookieName(), state, null, getDefaultCookiePath(), deployment.isSslRequired());
sendRedirect(redirect);
}
public boolean checkStateCookie() {
Cookie stateCookie = getCookie(realmInfo.getStateCookieName());
Cookie stateCookie = getCookie(deployment.getStateCookieName());
if (stateCookie == null) {
sendError(HttpServletResponse.SC_BAD_REQUEST);
@ -193,12 +189,12 @@ public class ServletOAuthLogin {
}
// reset the cookie
log.debug("** reseting application state cookie");
Cookie reset = new Cookie(realmInfo.getStateCookieName(), "");
Cookie reset = new Cookie(deployment.getStateCookieName(), "");
reset.setPath(getDefaultCookiePath());
reset.setMaxAge(0);
response.addCookie(reset);
String stateCookieValue = getCookieValue(realmInfo.getStateCookieName());
String stateCookieValue = getCookieValue(deployment.getStateCookieName());
// its ok to call request.getParameter() because this should be a redirect
String state = request.getParameter("state");
if (state == null) {
@ -231,7 +227,7 @@ public class ServletOAuthLogin {
*/
public boolean resolveCode(String code) {
// abort if not HTTPS
if (realmInfo.isSslRequired() && !isRequestSecure()) {
if (deployment.isSslRequired() && !isRequestSecure()) {
log.error("SSL is required");
sendError(HttpServletResponse.SC_FORBIDDEN);
return false;
@ -242,7 +238,7 @@ public class ServletOAuthLogin {
String redirectUri = stripOauthParametersFromRedirect();
AccessTokenResponse tokenResponse = null;
try {
tokenResponse = ServerRequest.invokeAccessCodeToToken(realmInfo, code, redirectUri);
tokenResponse = ServerRequest.invokeAccessCodeToToken(deployment, code, redirectUri);
} catch (ServerRequest.HttpFailure failure) {
log.error("failed to turn code into token");
log.error("status from server: " + failure.getStatus());
@ -260,7 +256,7 @@ public class ServletOAuthLogin {
tokenString = tokenResponse.getToken();
idTokenString = tokenResponse.getIdToken();
try {
token = RSATokenVerifier.verifyToken(tokenString, realmInfo.getMetadata().getRealmKey(), realmInfo.getMetadata().getRealm());
token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealm());
if (idTokenString != null) {
JWSInput input = new JWSInput(idTokenString);
try {
@ -275,10 +271,10 @@ public class ServletOAuthLogin {
sendError(HttpServletResponse.SC_FORBIDDEN);
return false;
}
if (tokenResponse.getNotBeforePolicy() > realmInfo.getNotBefore()) {
realmInfo.setNotBefore(tokenResponse.getNotBeforePolicy());
if (tokenResponse.getNotBeforePolicy() > deployment.getNotBefore()) {
deployment.setNotBefore(tokenResponse.getNotBeforePolicy());
}
if (token.getIssuedAt() < realmInfo.getNotBefore()) {
if (token.getIssuedAt() < deployment.getNotBefore()) {
log.error("Stale token");
sendError(HttpServletResponse.SC_FORBIDDEN);
return false;

View file

@ -1,47 +0,0 @@
package org.keycloak.adapters.as7.config;
import org.apache.catalina.Context;
import org.jboss.logging.Logger;
import org.keycloak.adapters.AdapterConstants;
import org.keycloak.adapters.config.RealmConfigurationLoader;
import javax.servlet.ServletContext;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
public class CatalinaAdapterConfigLoader extends RealmConfigurationLoader {
private static final Logger log = Logger.getLogger(CatalinaAdapterConfigLoader.class);
private InputStream getJSONFromServletContext(ServletContext servletContext) {
String json = servletContext.getInitParameter(AdapterConstants.AUTH_DATA_PARAM_NAME);
if (json == null) {
return null;
}
log.info("**** using " + AdapterConstants.AUTH_DATA_PARAM_NAME);
log.info(json);
return new ByteArrayInputStream(json.getBytes());
}
public CatalinaAdapterConfigLoader(Context context) {
log.info("******* Loading adapter config.");
InputStream is = getJSONFromServletContext(context.getServletContext());
if (is == null) {
String path = context.getServletContext().getInitParameter("keycloak.config.file");
if (path == null) {
log.info("**** using /WEB-INF/keycloak.json");
is = context.getServletContext().getResourceAsStream("/WEB-INF/keycloak.json");
} else {
try {
is = new FileInputStream(path);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
}
if (is == null) throw new RuntimeException("Could not find keycloak config.");
loadConfig(is);
}
}

View file

@ -5,7 +5,6 @@ import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.RSATokenVerifier;
import org.keycloak.adapters.ResourceMetadata;
import org.keycloak.VerificationException;
import org.keycloak.representations.AccessToken;
@ -19,6 +18,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import java.io.IOException;
import java.security.Principal;
import java.security.PublicKey;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -26,16 +26,20 @@ import java.security.Principal;
*/
@Priority(Priorities.AUTHENTICATION)
public class JaxrsBearerTokenFilter implements ContainerRequestFilter {
protected ResourceMetadata resourceMetadata;
private static Logger log = Logger.getLogger(JaxrsBearerTokenFilter.class);
protected String realm;
protected PublicKey realmPublicKey;
protected String resourceName;
public JaxrsBearerTokenFilter(ResourceMetadata resourceMetadata) {
this.resourceMetadata = resourceMetadata;
public JaxrsBearerTokenFilter(String realm, PublicKey realmPublicKey, String resourceName) {
this.realm = realm;
this.realmPublicKey = realmPublicKey;
this.resourceName = resourceName;
}
protected void challengeResponse(ContainerRequestContext request, String error, String description) {
StringBuilder header = new StringBuilder("Bearer realm=\"");
header.append(resourceMetadata.getRealm()).append("\"");
header.append(realm).append("\"");
if (error != null) {
header.append(", error=\"").append(error).append("\"");
}
@ -66,16 +70,16 @@ public class JaxrsBearerTokenFilter implements ContainerRequestFilter {
try {
AccessToken token = RSATokenVerifier.verifyToken(tokenString, resourceMetadata.getRealmKey(), resourceMetadata.getRealm());
KeycloakSecurityContext skSession = new KeycloakSecurityContext(tokenString, token, null, null, resourceMetadata);
AccessToken token = RSATokenVerifier.verifyToken(tokenString, realmPublicKey, realm);
KeycloakSecurityContext skSession = new KeycloakSecurityContext(tokenString, token, null, null);
ResteasyProviderFactory.pushContext(KeycloakSecurityContext.class, skSession);
String callerPrincipal = securityContext.getUserPrincipal() != null ? securityContext.getUserPrincipal().getName() : null;
final KeycloakPrincipal principal = new KeycloakPrincipal(token.getSubject(), callerPrincipal);
final boolean isSecure = securityContext.isSecure();
final AccessToken.Access access;
if (resourceMetadata.getResourceName() != null) {
access = token.getResourceAccess(resourceMetadata.getResourceName());
if (resourceName != null) {
access = token.getResourceAccess(resourceName);
} else {
access = token.getRealmAccess();
}

View file

@ -33,22 +33,10 @@ public class JaxrsOAuthClient extends AbstractOAuthClient {
protected Client client;
/**
* Creates a Client for obtaining access token from code
*/
public void start() {
if (client == null) {
client = new ResteasyClientBuilder().trustStore(truststore)
.hostnameVerification(ResteasyClientBuilder.HostnameVerificationPolicy.ANY)
.connectionPoolSize(10)
.build();
}
}
/**
* closes cllient
* closes client
*/
public void stop() {
client.close();
if (client != null) client.close();
}
public Client getClient() {
return client;

View file

@ -36,14 +36,6 @@
<version>${keycloak.apache.httpcomponents.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
</dependency>
<dependency>
<groupId>net.iharder</groupId>
<artifactId>base64</artifactId>

View file

@ -22,20 +22,11 @@ import java.net.URI;
public class ServletOAuthClient extends AbstractOAuthClient {
protected HttpClient client;
/**
* Creates a Client for obtaining access token from code
*/
public void start() {
if (client == null) {
client = new HttpClientBuilder().trustStore(truststore)
.hostnameVerification(HttpClientBuilder.HostnameVerificationPolicy.ANY)
.connectionPoolSize(10)
.build();
}
}
/**
* closes cllient
* closes client
*/
public void stop() {
client.getConnectionManager().shutdown();

View file

@ -0,0 +1,60 @@
package org.keycloak.servlet;
import org.apache.http.client.HttpClient;
import org.keycloak.ServiceUrlConstants;
import org.keycloak.adapters.HttpClientBuilder;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.keycloak.util.JsonSerialization;
import org.keycloak.util.KeycloakUriBuilder;
import java.io.IOException;
import java.io.InputStream;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ServletOAuthClientBuilder {
public static ServletOAuthClient build(InputStream is) {
AdapterConfig adapterConfig = getAdapterConfig(is);
return build(adapterConfig);
}
private static AdapterConfig getAdapterConfig(InputStream is) {
try {
return JsonSerialization.readValue(is, AdapterConfig.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static ServletOAuthClient build(AdapterConfig adapterConfig) {
ServletOAuthClient oauthClient = new ServletOAuthClient();
build(adapterConfig, oauthClient);
return oauthClient;
}
public static void build(InputStream is, ServletOAuthClient oauthClient) {
build(getAdapterConfig(is), oauthClient);
}
public static void build(AdapterConfig adapterConfig, ServletOAuthClient oauthClient) {
HttpClient client = new HttpClientBuilder().build(adapterConfig);
oauthClient.setClient(client);
oauthClient.setClientId(adapterConfig.getResource());
oauthClient.setPublicClient(adapterConfig.isPublicClient());
oauthClient.setCredentials(adapterConfig.getCredentials());
if (adapterConfig.getAuthServerUrl() == null) {
throw new RuntimeException("You must specify auth-url");
}
KeycloakUriBuilder serverBuilder = KeycloakUriBuilder.fromUri(adapterConfig.getAuthServerUrl());
String authUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_LOGIN_PATH).build(adapterConfig.getRealm()).toString();
String tokenUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_ACCESS_CODE_PATH).build(adapterConfig.getRealm()).toString();
String refreshUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_REFRESH_PATH).build(adapterConfig.getRealm()).toString();
oauthClient.setAuthUrl(authUrl);
oauthClient.setCodeUrl(tokenUrl);
oauthClient.setRefreshUrl(refreshUrl);
}
}

View file

@ -1,36 +0,0 @@
package org.keycloak.servlet;
import java.io.InputStream;
import org.keycloak.adapters.config.OAuthClientConfigLoader;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ServletOAuthClientConfigLoader extends OAuthClientConfigLoader {
public ServletOAuthClientConfigLoader() {
}
public ServletOAuthClientConfigLoader(InputStream is) {
super(is);
}
/**
* For now, configure just things supported by ServletOAuthClient
* @param setupClient
*/
public void initOAuthClientConfiguration(boolean setupClient) {
initOAuthClientConfiguration();
if (setupClient) {
initClient();
}
}
public void configureServletOAuthClient(ServletOAuthClient oauthClient) {
configureOAuthClient(oauthClient);
if (client != null) {
oauthClient.setClient(client);
}
}
}

View file

@ -7,6 +7,7 @@ import io.undertow.util.Headers;
import io.undertow.util.StatusCodes;
import org.jboss.logging.Logger;
import org.keycloak.adapters.AdapterConstants;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.adapters.config.AdapterConfig;
@ -27,25 +28,25 @@ import java.util.Set;
*/
public class AuthenticatedActionsHandler implements HttpHandler {
private static final Logger log = Logger.getLogger(AuthenticatedActionsHandler.class);
protected AdapterConfig adapterConfig;
protected KeycloakDeployment deployment;
protected HttpHandler next;
public static class Wrapper implements HandlerWrapper {
protected AdapterConfig config;
protected KeycloakDeployment deployment;
public Wrapper(AdapterConfig config) {
this.config = config;
public Wrapper(KeycloakDeployment deployment) {
this.deployment = deployment;
}
@Override
public HttpHandler wrap(HttpHandler handler) {
return new AuthenticatedActionsHandler(config, handler);
return new AuthenticatedActionsHandler(deployment, handler);
}
}
protected AuthenticatedActionsHandler(AdapterConfig config, HttpHandler next) {
this.adapterConfig = config;
protected AuthenticatedActionsHandler(KeycloakDeployment deployment, HttpHandler next) {
this.deployment = deployment;
this.next = next;
}
@ -82,13 +83,13 @@ public class AuthenticatedActionsHandler implements HttpHandler {
exchange.endExchange();
return true;
}
if (!adapterConfig.isExposeToken()) {
if (!deployment.isExposeToken()) {
exchange.setResponseCode(StatusCodes.OK);
exchange.endExchange();
return true;
}
// Don't allow a CORS request if we're not validating CORS requests.
if (!adapterConfig.isCors() && exchange.getRequestHeaders().getFirst(Headers.ORIGIN) != null) {
if (!deployment.isCors() && exchange.getRequestHeaders().getFirst(Headers.ORIGIN) != null) {
exchange.setResponseCode(StatusCodes.OK);
exchange.endExchange();
return true;
@ -97,7 +98,7 @@ public class AuthenticatedActionsHandler implements HttpHandler {
}
protected boolean corsRequest(HttpServerExchange exchange, KeycloakUndertowAccount account) throws IOException {
if (!adapterConfig.isCors()) return false;
if (!deployment.isCors()) return false;
log.debugv("CORS enabled + request.getRequestURI()");
String origin = exchange.getRequestHeaders().getFirst("Origin");
log.debugv("Origin: {0} uri: {1}", origin, exchange.getRequestURI());

View file

@ -5,14 +5,12 @@ import io.undertow.security.api.SecurityContext;
import io.undertow.server.HttpServerExchange;
import org.jboss.logging.Logger;
import org.keycloak.RSATokenVerifier;
import org.keycloak.adapters.ResourceMetadata;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.VerificationException;
import org.keycloak.representations.AccessToken;
import javax.security.cert.X509Certificate;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static io.undertow.util.Headers.AUTHORIZATION;
import static io.undertow.util.Headers.WWW_AUTHENTICATE;
@ -23,29 +21,21 @@ import static io.undertow.util.StatusCodes.UNAUTHORIZED;
* @version $Revision: 1 $
*/
public class BearerTokenAuthenticator {
protected ResourceMetadata resourceMetadata;
protected Logger log = Logger.getLogger(BearerTokenAuthenticator.class);
protected String tokenString;
protected AccessToken token;
protected boolean useResourceRoleMappings;
protected String surrogate;
protected KeycloakChallenge challenge;
protected int notBefore;
protected KeycloakDeployment deployment;
public BearerTokenAuthenticator(ResourceMetadata resourceMetadata, int notBefore, boolean useResourceRoleMappings) {
this.resourceMetadata = resourceMetadata;
this.useResourceRoleMappings = useResourceRoleMappings;
this.notBefore = notBefore;
public BearerTokenAuthenticator(KeycloakDeployment deployment) {
this.deployment = deployment;
}
public KeycloakChallenge getChallenge() {
return challenge;
}
public ResourceMetadata getResourceMetadata() {
return resourceMetadata;
}
public String getTokenString() {
return tokenString;
}
@ -79,20 +69,20 @@ public class BearerTokenAuthenticator {
}
try {
token = RSATokenVerifier.verifyToken(tokenString, resourceMetadata.getRealmKey(), resourceMetadata.getRealm());
token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealm());
} catch (VerificationException e) {
log.error("Failed to verify token", e);
challenge = challengeResponse(exchange, "invalid_token", e.getMessage());
return AuthenticationMechanism.AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
}
if (token.getIssuedAt() < notBefore) {
if (token.getIssuedAt() < deployment.getNotBefore()) {
log.error("Stale token");
challenge = challengeResponse(exchange, "invalid_token", "Stale token");
return AuthenticationMechanism.AuthenticationMechanismOutcome.NOT_AUTHENTICATED;
}
boolean verifyCaller = false;
if (useResourceRoleMappings) {
verifyCaller = token.isVerifyCaller(resourceMetadata.getResourceName());
if (deployment.isUseResourceRoleMappings()) {
verifyCaller = token.isVerifyCaller(deployment.getResourceName());
} else {
verifyCaller = token.isVerifyCaller();
}
@ -135,7 +125,7 @@ public class BearerTokenAuthenticator {
protected KeycloakChallenge challengeResponse(HttpServerExchange exchange, String error, String description) {
StringBuilder header = new StringBuilder("Bearer realm=\"");
header.append(resourceMetadata.getRealm()).append("\"");
header.append(deployment.getRealm()).append("\"");
if (error != null) {
header.append(", error=\"").append(error).append("\"");
}

View file

@ -7,10 +7,8 @@ import io.undertow.util.AttachmentKey;
import io.undertow.util.Headers;
import org.jboss.logging.Logger;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.RefreshableKeycloakSession;
import org.keycloak.adapters.ResourceMetadata;
import org.keycloak.adapters.config.RealmConfiguration;
import org.keycloak.representations.adapters.config.AdapterConfig;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -21,23 +19,17 @@ public class KeycloakAuthenticationMechanism implements AuthenticationMechanism
public static final AttachmentKey<KeycloakChallenge> KEYCLOAK_CHALLENGE_ATTACHMENT_KEY = AttachmentKey.create(KeycloakChallenge.class);
protected ResourceMetadata resourceMetadata;
protected AdapterConfig adapterConfig;
protected RealmConfiguration realmConfig;
protected KeycloakDeployment deployment;
protected int sslRedirectPort;
public KeycloakAuthenticationMechanism(AdapterConfig config, RealmConfiguration realmConfig, int sslRedirectPort) {
this.resourceMetadata = realmConfig.getMetadata();
this.adapterConfig = config;
this.realmConfig = realmConfig;
public KeycloakAuthenticationMechanism(KeycloakDeployment deployment, int sslRedirectPort) {
this.deployment = deployment;
this.sslRedirectPort = sslRedirectPort;
}
public KeycloakAuthenticationMechanism(AdapterConfig adapterConfig, RealmConfiguration realmConfig) {
this.resourceMetadata = realmConfig.getMetadata();
this.adapterConfig = adapterConfig;
this.realmConfig = realmConfig;
}
public KeycloakAuthenticationMechanism(KeycloakDeployment deployment) {
this.deployment = deployment;
}
@Override
public AuthenticationMechanismOutcome authenticate(HttpServerExchange exchange, SecurityContext securityContext) {
@ -50,7 +42,7 @@ public class KeycloakAuthenticationMechanism implements AuthenticationMechanism
} else if (outcome == AuthenticationMechanismOutcome.AUTHENTICATED) {
completeAuthentication(exchange, securityContext, bearer);
return AuthenticationMechanismOutcome.AUTHENTICATED;
} else if (adapterConfig.isBearerOnly()) {
} else if (deployment.isBearerOnly()) {
exchange.putAttachment(KEYCLOAK_CHALLENGE_ATTACHMENT_KEY, bearer.getChallenge());
return AuthenticationMechanismOutcome.NOT_ATTEMPTED;
}
@ -88,17 +80,17 @@ public class KeycloakAuthenticationMechanism implements AuthenticationMechanism
}
protected OAuthAuthenticator createOAuthAuthenticator(HttpServerExchange exchange) {
return new OAuthAuthenticator(exchange, realmConfig, sslRedirectPort);
return new OAuthAuthenticator(exchange, deployment, sslRedirectPort);
}
protected BearerTokenAuthenticator createBearerTokenAuthenticator() {
return new BearerTokenAuthenticator(resourceMetadata, realmConfig.getNotBefore(), adapterConfig.isUseResourceRoleMappings());
return new BearerTokenAuthenticator(deployment);
}
protected void completeAuthentication(HttpServerExchange exchange, SecurityContext securityContext, OAuthAuthenticator oauth) {
final KeycloakPrincipal principal = new KeycloakPrincipal(oauth.getToken().getSubject(), null);
RefreshableKeycloakSession session = new RefreshableKeycloakSession(oauth.getTokenString(), oauth.getToken(), oauth.getIdTokenString(), oauth.getIdToken(), resourceMetadata, realmConfig, oauth.getRefreshToken());
KeycloakUndertowAccount account = new KeycloakUndertowAccount(principal, session, adapterConfig, resourceMetadata);
RefreshableKeycloakSession session = new RefreshableKeycloakSession(deployment, oauth.getTokenString(), oauth.getToken(), oauth.getIdTokenString(), oauth.getIdToken(), oauth.getRefreshToken());
KeycloakUndertowAccount account = new KeycloakUndertowAccount(principal, session, deployment);
// We cache account ourselves instead of using the Cache session handler of Undertow because
// Undertow will return a 403 from an invalid account when calling IdentityManager.verify(Account) and
@ -118,8 +110,8 @@ public class KeycloakAuthenticationMechanism implements AuthenticationMechanism
protected void completeAuthentication(HttpServerExchange exchange, SecurityContext securityContext, BearerTokenAuthenticator bearer) {
final KeycloakPrincipal principal = new KeycloakPrincipal(bearer.getToken().getSubject(), bearer.getSurrogate());
RefreshableKeycloakSession session = new RefreshableKeycloakSession(bearer.getTokenString(), bearer.getToken(), null, null, resourceMetadata, realmConfig, null);
KeycloakUndertowAccount account = new KeycloakUndertowAccount(principal, session, adapterConfig, resourceMetadata);
RefreshableKeycloakSession session = new RefreshableKeycloakSession(deployment, bearer.getTokenString(), bearer.getToken(), null, null, null);
KeycloakUndertowAccount account = new KeycloakUndertowAccount(principal, session, deployment);
securityContext.authenticationComplete(account, "KEYCLOAK", false);
propagateKeycloakContext(exchange, account);
}

View file

@ -1,44 +0,0 @@
package org.keycloak.adapters.undertow;
import io.undertow.security.idm.Account;
import io.undertow.security.idm.Credential;
import io.undertow.security.idm.IdentityManager;
import org.jboss.logging.Logger;
import org.keycloak.adapters.config.RealmConfiguration;
import org.keycloak.representations.adapters.config.AdapterConfig;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
class KeycloakIdentityManager implements IdentityManager {
protected static Logger log = Logger.getLogger(KeycloakIdentityManager.class);
protected AdapterConfig adapterConfig;
protected RealmConfiguration realmConfiguration;
KeycloakIdentityManager(AdapterConfig adapterConfig, RealmConfiguration realmConfiguration) {
this.adapterConfig = adapterConfig;
this.realmConfiguration = realmConfiguration;
}
@Override
public Account verify(Account account) {
log.info("Verifying account in IdentityManager");
KeycloakUndertowAccount keycloakAccount = (KeycloakUndertowAccount)account;
if (!keycloakAccount.isActive(realmConfiguration, adapterConfig)) {
log.info("account.isActive() returned false, returning null");
return null;
}
return account;
}
@Override
public Account verify(String id, Credential credential) {
throw new IllegalStateException("Unsupported verify method");
}
@Override
public Account verify(Credential credential) {
throw new IllegalStateException("Unsupported verify method");
}
}

View file

@ -14,9 +14,8 @@ import io.undertow.servlet.api.ServletSessionConfig;
import java.io.ByteArrayInputStream;
import org.jboss.logging.Logger;
import org.keycloak.adapters.AdapterConstants;
import org.keycloak.adapters.config.RealmConfiguration;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.keycloak.adapters.config.RealmConfigurationLoader;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import javax.servlet.ServletContext;
import java.io.InputStream;
@ -63,24 +62,20 @@ public class KeycloakServletExtension implements ServletExtension {
is = servletContext.getResourceAsStream("/WEB-INF/keycloak.json");
}
if (is == null) throw new RuntimeException("Unable to find realm config in /WEB-INF/keycloak.json or in keycloak subsystem.");
RealmConfigurationLoader loader = new RealmConfigurationLoader(is);
loader.init(true);
AdapterConfig keycloakConfig = loader.getAdapterConfig();
RealmConfiguration realmConfiguration = loader.getRealmConfiguration();
PreflightCorsHandler.Wrapper preflight = new PreflightCorsHandler.Wrapper(keycloakConfig);
UserSessionManagement userSessionManagement = new UserSessionManagement(realmConfiguration);
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(is);
PreflightCorsHandler.Wrapper preflight = new PreflightCorsHandler.Wrapper(deployment);
UserSessionManagement userSessionManagement = new UserSessionManagement(deployment);
ServletKeycloakAuthenticationMechanism auth = null;
auth = new ServletKeycloakAuthenticationMechanism(
userSessionManagement,
keycloakConfig,
realmConfiguration,
deployment,
deploymentInfo.getConfidentialPortManager());
AuthenticatedActionsHandler.Wrapper actions = new AuthenticatedActionsHandler.Wrapper(keycloakConfig);
AuthenticatedActionsHandler.Wrapper actions = new AuthenticatedActionsHandler.Wrapper(deployment);
// setup handlers
deploymentInfo.addInitialHandlerChainWrapper(preflight); // cors preflight
deploymentInfo.addOuterHandlerChainWrapper(new ServletAdminActionsHandler.Wrapper(realmConfiguration, loader.getResourceMetadata(), userSessionManagement));
deploymentInfo.addOuterHandlerChainWrapper(new ServletAdminActionsHandler.Wrapper(deployment, userSessionManagement));
final ServletKeycloakAuthenticationMechanism theAuth = auth;
deploymentInfo.addAuthenticationMechanism("KEYCLOAK", new AuthenticationMechanismFactory() {
@Override

View file

@ -3,11 +3,9 @@ package org.keycloak.adapters.undertow;
import io.undertow.security.idm.Account;
import org.jboss.logging.Logger;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.RefreshableKeycloakSession;
import org.keycloak.adapters.ResourceMetadata;
import org.keycloak.adapters.config.RealmConfiguration;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.adapters.config.AdapterConfig;
import java.io.Serializable;
import java.security.Principal;
@ -24,16 +22,16 @@ public class KeycloakUndertowAccount implements Account, Serializable {
protected KeycloakPrincipal principal;
protected Set<String> accountRoles;
public KeycloakUndertowAccount(KeycloakPrincipal principal, RefreshableKeycloakSession session, AdapterConfig config, ResourceMetadata metadata) {
public KeycloakUndertowAccount(KeycloakPrincipal principal, RefreshableKeycloakSession session, KeycloakDeployment deployment) {
this.principal = principal;
this.session = session;
setRoles(session.getToken(), config, metadata);
setRoles(session.getToken(), deployment);
}
protected void setRoles(AccessToken accessToken, AdapterConfig adapterConfig, ResourceMetadata resourceMetadata) {
protected void setRoles(AccessToken accessToken, KeycloakDeployment deployment) {
Set<String> roles = null;
if (adapterConfig.isUseResourceRoleMappings()) {
AccessToken.Access access = accessToken.getResourceAccess(resourceMetadata.getResourceName());
if (deployment.isUseResourceRoleMappings()) {
AccessToken.Access access = accessToken.getResourceAccess(deployment.getResourceName());
if (access != null) roles = access.getRoles();
} else {
AccessToken.Access access = accessToken.getRealmAccess();
@ -65,11 +63,10 @@ public class KeycloakUndertowAccount implements Account, Serializable {
return session;
}
public boolean isActive(RealmConfiguration realmConfiguration, AdapterConfig config) {
public boolean isActive(KeycloakDeployment deployment) {
// this object may have been serialized, so we need to reset realm config/metadata
session.setRealmConfiguration(realmConfiguration);
session.setMetadata(realmConfiguration.getMetadata());
log.info("realmConfig notBefore: " + realmConfiguration.getNotBefore());
session.setDeployment(deployment);
log.info("realmConfig notBefore: " + deployment.getNotBefore());
if (session.isActive()) {
log.info("session is active");
return true;
@ -84,7 +81,7 @@ public class KeycloakUndertowAccount implements Account, Serializable {
}
log.info("refresh succeeded");
setRoles(session.getToken(), config, realmConfiguration.getMetadata());
setRoles(session.getToken(), deployment);
return true;
}

View file

@ -9,8 +9,8 @@ import io.undertow.util.Headers;
import io.undertow.util.StatusCodes;
import org.jboss.logging.Logger;
import org.keycloak.RSATokenVerifier;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.ServerRequest;
import org.keycloak.adapters.config.RealmConfiguration;
import org.keycloak.VerificationException;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.representations.AccessToken;
@ -30,7 +30,7 @@ import java.util.concurrent.atomic.AtomicLong;
*/
public class OAuthAuthenticator {
private static final Logger log = Logger.getLogger(OAuthAuthenticator.class);
protected RealmConfiguration realmInfo;
protected KeycloakDeployment deployment;
protected int sslRedirectPort;
protected String tokenString;
protected String idTokenString;
@ -41,9 +41,9 @@ public class OAuthAuthenticator {
protected String refreshToken;
protected String strippedOauthParametersRequestUri;
public OAuthAuthenticator(HttpServerExchange exchange, RealmConfiguration realmInfo, int sslRedirectPort) {
public OAuthAuthenticator(HttpServerExchange exchange, KeycloakDeployment deployment, int sslRedirectPort) {
this.exchange = exchange;
this.realmInfo = realmInfo;
this.deployment = deployment;
this.sslRedirectPort = sslRedirectPort;
}
@ -129,7 +129,7 @@ public class OAuthAuthenticator {
protected String getRedirectUri(String state) {
String url = getRequestUrl();
log.infof("sending redirect uri: %s", url);
if (!isRequestSecure() && realmInfo.isSslRequired()) {
if (!isRequestSecure() && deployment.isSslRequired()) {
int port = sslRedirectPort();
if (port < 0) {
// disabled?
@ -139,8 +139,8 @@ public class OAuthAuthenticator {
if (port != 443) secureUrl.port(port);
url = secureUrl.build().toString();
}
return realmInfo.getAuthUrl().clone()
.queryParam("client_id", realmInfo.getMetadata().getResourceName())
return deployment.getAuthUrl().clone()
.queryParam("client_id", deployment.getResourceName())
.queryParam("redirect_uri", url)
.queryParam("state", state)
.queryParam("login", "true")
@ -166,9 +166,9 @@ public class OAuthAuthenticator {
if (redirect == null) {
return new AuthenticationMechanism.ChallengeResult(true, StatusCodes.FORBIDDEN);
}
CookieImpl cookie = new CookieImpl(realmInfo.getStateCookieName(), state);
CookieImpl cookie = new CookieImpl(deployment.getStateCookieName(), state);
//cookie.setPath(getDefaultCookiePath()); todo I don't think we need to set state cookie path as it will be the same redirect
cookie.setSecure(realmInfo.isSslRequired());
cookie.setSecure(deployment.isSslRequired());
exchange.setResponseCookie(cookie);
exchange.getResponseHeaders().put(Headers.LOCATION, redirect);
return new AuthenticationMechanism.ChallengeResult(true, StatusCodes.FOUND);
@ -177,7 +177,7 @@ public class OAuthAuthenticator {
}
protected KeycloakChallenge checkStateCookie() {
Cookie stateCookie = getCookie(realmInfo.getStateCookieName());
Cookie stateCookie = getCookie(deployment.getStateCookieName());
if (stateCookie == null) {
log.warn("No state cookie");
@ -185,12 +185,12 @@ public class OAuthAuthenticator {
}
// reset the cookie
log.info("** reseting application state cookie");
Cookie reset = new CookieImpl(realmInfo.getStateCookieName(), "");
Cookie reset = new CookieImpl(deployment.getStateCookieName(), "");
reset.setPath(stateCookie.getPath());
reset.setMaxAge(0);
exchange.setResponseCookie(reset);
String stateCookieValue = getCookieValue(realmInfo.getStateCookieName());
String stateCookieValue = getCookieValue(deployment.getStateCookieName());
String state = getQueryParamValue("state");
if (state == null) {
@ -256,7 +256,7 @@ public class OAuthAuthenticator {
*/
protected KeycloakChallenge resolveCode(String code) {
// abort if not HTTPS
if (realmInfo.isSslRequired() && !isRequestSecure()) {
if (deployment.isSslRequired() && !isRequestSecure()) {
log.error("SSL is required");
return challenge(StatusCodes.FORBIDDEN);
}
@ -268,7 +268,7 @@ public class OAuthAuthenticator {
AccessTokenResponse tokenResponse = null;
strippedOauthParametersRequestUri = stripOauthParametersFromRedirect();
try {
tokenResponse = ServerRequest.invokeAccessCodeToToken(realmInfo, code, strippedOauthParametersRequestUri);
tokenResponse = ServerRequest.invokeAccessCodeToToken(deployment, code, strippedOauthParametersRequestUri);
} catch (ServerRequest.HttpFailure failure) {
log.error("failed to turn code into token");
log.error("status from server: " + failure.getStatus());
@ -286,7 +286,7 @@ public class OAuthAuthenticator {
refreshToken = tokenResponse.getRefreshToken();
idTokenString = tokenResponse.getIdToken();
try {
token = RSATokenVerifier.verifyToken(tokenString, realmInfo.getMetadata().getRealmKey(), realmInfo.getMetadata().getRealm());
token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealm());
if (idTokenString != null) {
JWSInput input = new JWSInput(idTokenString);
try {
@ -300,10 +300,10 @@ public class OAuthAuthenticator {
log.error("failed verification of token");
return challenge(StatusCodes.FORBIDDEN);
}
if (tokenResponse.getNotBeforePolicy() > realmInfo.getNotBefore()) {
realmInfo.setNotBefore(tokenResponse.getNotBeforePolicy());
if (tokenResponse.getNotBeforePolicy() > deployment.getNotBefore()) {
deployment.setNotBefore(tokenResponse.getNotBeforePolicy());
}
if (token.getIssuedAt() < realmInfo.getNotBefore()) {
if (token.getIssuedAt() < deployment.getNotBefore()) {
log.error("Stale token");
return challenge(StatusCodes.FORBIDDEN);
}

View file

@ -6,6 +6,7 @@ import io.undertow.server.HttpServerExchange;
import io.undertow.util.HttpString;
import io.undertow.util.StatusCodes;
import org.jboss.logging.Logger;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.representations.adapters.config.AdapterConfig;
/**
@ -14,7 +15,7 @@ import org.keycloak.representations.adapters.config.AdapterConfig;
*/
public class PreflightCorsHandler implements HttpHandler {
private static final Logger log = Logger.getLogger(PreflightCorsHandler.class);
protected AdapterConfig adapterConfig;
protected KeycloakDeployment deployment;
protected HttpHandler next;
public static final HttpString ACCESS_CONTROL_ALLOW_ORIGIN = new HttpString("Access-Control-Allow-Origin");
@ -24,20 +25,20 @@ public class PreflightCorsHandler implements HttpHandler {
public static final HttpString ACCESS_CONTROL_MAX_AGE = new HttpString("Access-Control-Max-Age");
public static class Wrapper implements HandlerWrapper {
protected AdapterConfig config;
protected KeycloakDeployment deployment;
public Wrapper(AdapterConfig config) {
this.config = config;
public Wrapper(KeycloakDeployment deployment) {
this.deployment = deployment;
}
@Override
public HttpHandler wrap(HttpHandler handler) {
return new PreflightCorsHandler(config, handler);
return new PreflightCorsHandler(deployment, handler);
}
}
protected PreflightCorsHandler(AdapterConfig config, HttpHandler next) {
this.adapterConfig = config;
protected PreflightCorsHandler(KeycloakDeployment deployment, HttpHandler next) {
this.deployment = deployment;
this.next = next;
}
@ -61,20 +62,20 @@ public class PreflightCorsHandler implements HttpHandler {
exchange.getResponseHeaders().put(ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
String requestMethods = exchange.getRequestHeaders().getFirst("Access-Control-Request-Method");
if (requestMethods != null) {
if (adapterConfig.getCorsAllowedMethods() != null) {
requestMethods = adapterConfig.getCorsAllowedMethods();
if (deployment.getCorsAllowedMethods() != null) {
requestMethods = deployment.getCorsAllowedMethods();
}
exchange.getResponseHeaders().put(ACCESS_CONTROL_ALLOW_METHODS, requestMethods);
}
String allowHeaders = exchange.getRequestHeaders().getFirst("Access-Control-Request-Headers");
if (allowHeaders != null) {
if (adapterConfig.getCorsAllowedHeaders() != null) {
allowHeaders = adapterConfig.getCorsAllowedHeaders();
if (deployment.getCorsAllowedHeaders() != null) {
allowHeaders = deployment.getCorsAllowedHeaders();
}
exchange.getResponseHeaders().put(ACCESS_CONTROL_ALLOW_HEADERS, allowHeaders);
}
if (adapterConfig.getCorsMaxAge() > -1) {
exchange.getResponseHeaders().put(ACCESS_CONTROL_MAX_AGE, Integer.toString(adapterConfig.getCorsMaxAge()));
if (deployment.getCorsMaxAge() > -1) {
exchange.getResponseHeaders().put(ACCESS_CONTROL_MAX_AGE, Integer.toString(deployment.getCorsMaxAge()));
}
exchange.endExchange();
}

View file

@ -8,8 +8,7 @@ import io.undertow.servlet.handlers.ServletRequestContext;
import io.undertow.util.StatusCodes;
import org.jboss.logging.Logger;
import org.keycloak.adapters.AdapterConstants;
import org.keycloak.adapters.ResourceMetadata;
import org.keycloak.adapters.config.RealmConfiguration;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.crypto.RSAProvider;
import org.keycloak.representations.adapters.action.AdminAction;
@ -25,8 +24,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
@ -38,35 +35,30 @@ public class ServletAdminActionsHandler implements HttpHandler {
private static final Logger log = Logger.getLogger(ServletAdminActionsHandler.class);
protected HttpHandler next;
protected UserSessionManagement userSessionManagement;
protected RealmConfiguration realmConfig;
protected ResourceMetadata resourceMetadata;
protected KeycloakDeployment deployment;
public static class Wrapper implements HandlerWrapper {
protected RealmConfiguration realmConfig;
protected ResourceMetadata resourceMetadata;
protected KeycloakDeployment deployment;
protected UserSessionManagement userSessionManagement;
public Wrapper(RealmConfiguration realmConfig, ResourceMetadata resourceMetadata, UserSessionManagement userSessionManagement) {
this.realmConfig = realmConfig;
this.resourceMetadata = resourceMetadata;
public Wrapper(KeycloakDeployment deployment, UserSessionManagement userSessionManagement) {
this.deployment = deployment;
this.userSessionManagement = userSessionManagement;
}
@Override
public HttpHandler wrap(HttpHandler handler) {
return new ServletAdminActionsHandler(realmConfig, resourceMetadata, userSessionManagement, handler);
return new ServletAdminActionsHandler(deployment, userSessionManagement, handler);
}
}
protected ServletAdminActionsHandler(RealmConfiguration realmConfig,
ResourceMetadata resourceMetadata,
protected ServletAdminActionsHandler(KeycloakDeployment deployment,
UserSessionManagement userSessionManagement,
HttpHandler next) {
this.next = next;
this.resourceMetadata = resourceMetadata;
this.deployment = deployment;
this.userSessionManagement = userSessionManagement;
this.realmConfig = realmConfig;
}
@ -110,7 +102,7 @@ public class ServletAdminActionsHandler implements HttpHandler {
}
PushNotBeforeAction action = JsonSerialization.readValue(token.getContent(), PushNotBeforeAction.class);
if (!validateAction(response, action)) return;
realmConfig.setNotBefore(action.getNotBefore());
deployment.setNotBefore(action.getNotBefore());
return;
}
@ -125,7 +117,7 @@ public class ServletAdminActionsHandler implements HttpHandler {
JWSInput input = new JWSInput(token);
boolean verified = false;
try {
verified = RSAProvider.verify(input, realmConfig.getMetadata().getRealmKey());
verified = RSAProvider.verify(input, deployment.getRealmKey());
} catch (Exception ignore) {
}
if (!verified) {
@ -148,7 +140,7 @@ public class ServletAdminActionsHandler implements HttpHandler {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Expired token");
return false;
}
if (!resourceMetadata.getResourceName().equals(action.getResource())) {
if (!deployment.getResourceName().equals(action.getResource())) {
log.warn("Resource name does not match");
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Resource name does not match");
return false;

View file

@ -4,8 +4,7 @@ import io.undertow.server.HttpServerExchange;
import io.undertow.servlet.api.ConfidentialPortManager;
import io.undertow.servlet.handlers.ServletRequestContext;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.config.RealmConfiguration;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.keycloak.adapters.KeycloakDeployment;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@ -18,15 +17,15 @@ public class ServletKeycloakAuthenticationMechanism extends KeycloakAuthenticati
protected ConfidentialPortManager portManager;
protected UserSessionManagement userSessionManagement;
public ServletKeycloakAuthenticationMechanism(UserSessionManagement userSessionManagement, AdapterConfig config, RealmConfiguration realmConfig, ConfidentialPortManager portManager) {
super(config, realmConfig);
public ServletKeycloakAuthenticationMechanism(UserSessionManagement userSessionManagement, KeycloakDeployment deployment, ConfidentialPortManager portManager) {
super(deployment);
this.portManager = portManager;
this.userSessionManagement = userSessionManagement;
}
@Override
protected OAuthAuthenticator createOAuthAuthenticator(HttpServerExchange exchange) {
return new ServletOAuthAuthenticator(exchange, realmConfig, portManager);
return new ServletOAuthAuthenticator(exchange, deployment, portManager);
}
@Override
@ -43,7 +42,7 @@ public class ServletKeycloakAuthenticationMechanism extends KeycloakAuthenticati
log.info("Account was not in session, returning null");
return null;
}
if (account.isActive(realmConfig, adapterConfig)) return account;
if (account.isActive(deployment)) return account;
log.info("Account was not active, returning null");
session.setAttribute(KeycloakUndertowAccount.class.getName(), null);
return null;

View file

@ -2,7 +2,7 @@ package org.keycloak.adapters.undertow;
import io.undertow.server.HttpServerExchange;
import io.undertow.servlet.api.ConfidentialPortManager;
import org.keycloak.adapters.config.RealmConfiguration;
import org.keycloak.adapters.KeycloakDeployment;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -11,8 +11,8 @@ import org.keycloak.adapters.config.RealmConfiguration;
public class ServletOAuthAuthenticator extends OAuthAuthenticator {
protected ConfidentialPortManager portManager;
public ServletOAuthAuthenticator(HttpServerExchange exchange, RealmConfiguration realmInfo, ConfidentialPortManager portManager) {
super(exchange, realmInfo, -1);
public ServletOAuthAuthenticator(HttpServerExchange exchange, KeycloakDeployment deployment, ConfidentialPortManager portManager) {
super(exchange, deployment, -1);
this.portManager = portManager;
}

View file

@ -8,7 +8,7 @@ import io.undertow.server.session.SessionManager;
import io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler;
import io.undertow.util.StatusCodes;
import org.jboss.logging.Logger;
import org.keycloak.adapters.config.RealmConfiguration;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.representations.adapters.action.LogoutAction;
import org.keycloak.util.JsonSerialization;
@ -33,10 +33,10 @@ public class UserSessionManagement implements SessionListener {
private static final String AUTH_SESSION_NAME = CachedAuthenticatedSessionHandler.class.getName() + ".AuthenticatedSession";
protected ConcurrentHashMap<String, UserSessions> userSessionMap = new ConcurrentHashMap<String, UserSessions>();
protected RealmConfiguration realmInfo;
protected KeycloakDeployment deployment;
public UserSessionManagement(RealmConfiguration realmInfo) {
this.realmInfo = realmInfo;
public UserSessionManagement(KeycloakDeployment deployment) {
this.deployment = deployment;
}
public static class UserSessions {
@ -52,10 +52,6 @@ public class UserSessionManagement implements SessionListener {
}
}
public int getNumUserLogins() {
return userSessionMap.size();
}
public int getActiveSessions() {
int active = 0;
synchronized (userSessionMap) {
@ -93,7 +89,7 @@ public class UserSessionManagement implements SessionListener {
response.sendError(StatusCodes.BAD_REQUEST, "Expired token");
return;
}
if (!realmInfo.getMetadata().getResourceName().equals(action.getResource())) {
if (!deployment.getResourceName().equals(action.getResource())) {
log.warn("Resource name does not match");
response.sendError(StatusCodes.BAD_REQUEST, "Resource name does not match");
return;