Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2b572c7e3 | ||
|
|
2edf212fcb | ||
|
|
b2a9f5afcb | ||
|
|
8dd16ceeba | ||
|
|
4544e26e3e | ||
|
|
b3a16be7b9 | ||
|
|
4186900da0 |
No files matched your search
-10
@@ -22,16 +22,6 @@ jdk:
|
||||
|
||||
install: true
|
||||
|
||||
before_install:
|
||||
- "export PHANTOMJS_VERSION=2.1.1"
|
||||
- "phantomjs --version"
|
||||
- "export PATH=$PWD/travis_phantomjs/phantomjs-$PHANTOMJS_VERSION-linux-x86_64/bin:$PATH"
|
||||
- "phantomjs --version"
|
||||
- "if [ $(phantomjs --version) != '$PHANTOMJS_VERSION' ]; then rm -rf $PWD/travis_phantomjs; mkdir -p $PWD/travis_phantomjs; fi"
|
||||
- "if [ $(phantomjs --version) != '$PHANTOMJS_VERSION' ]; then wget https://github.com/Medium/phantomjs/releases/download/v$PHANTOMJS_VERSION/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2 -O $PWD/travis_phantomjs/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2; fi"
|
||||
- "if [ $(phantomjs --version) != '$PHANTOMJS_VERSION' ]; then tar -xvf $PWD/travis_phantomjs/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2 -C $PWD/travis_phantomjs; fi"
|
||||
- "phantomjs --version"
|
||||
|
||||
script:
|
||||
- ./travis-run-tests.sh $TESTS
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
-20
@@ -206,16 +206,6 @@ public class AdapterDeploymentContext {
|
||||
public void setBearerOnly(boolean bearerOnly) {
|
||||
delegate.setBearerOnly(bearerOnly);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutodetectBearerOnly() {
|
||||
return delegate.isAutodetectBearerOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAutodetectBearerOnly(boolean autodetectBearerOnly) {
|
||||
delegate.setAutodetectBearerOnly(autodetectBearerOnly);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnableBasicAuth() {
|
||||
@@ -287,16 +277,6 @@ public class AdapterDeploymentContext {
|
||||
delegate.setSslRequired(sslRequired);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getConfidentialPort() {
|
||||
return delegate.getConfidentialPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConfidentialPort(int confidentialPort) {
|
||||
delegate.setConfidentialPort(confidentialPort);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenStore getTokenStore() {
|
||||
return delegate.getTokenStore();
|
||||
|
||||
+5
-6
@@ -71,10 +71,9 @@ public class BasicAuthRequestAuthenticator extends BearerTokenRequestAuthenticat
|
||||
AccessTokenResponse atr=null;
|
||||
try {
|
||||
String userpw=new String(Base64.decode(tokenString));
|
||||
int seperatorIndex = userpw.indexOf(":");
|
||||
String user = userpw.substring(0, seperatorIndex);
|
||||
String pw = userpw.substring(seperatorIndex + 1);
|
||||
atr = getToken(user, pw);
|
||||
String[] parts=userpw.split(":");
|
||||
|
||||
atr = getToken(parts[0], parts[1]);
|
||||
tokenString = atr.getToken();
|
||||
} catch (Exception e) {
|
||||
log.debug("Failed to obtain token", e);
|
||||
@@ -83,8 +82,8 @@ public class BasicAuthRequestAuthenticator extends BearerTokenRequestAuthenticat
|
||||
}
|
||||
|
||||
return authenticateToken(exchange, atr.getToken());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private AccessTokenResponse getToken(String username, String password) throws Exception {
|
||||
AccessTokenResponse tokenResponse=null;
|
||||
HttpClient client = deployment.getClient();
|
||||
|
||||
-17
@@ -23,8 +23,6 @@ import org.keycloak.adapters.spi.AuthChallenge;
|
||||
import org.keycloak.adapters.spi.AuthOutcome;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
import org.keycloak.jose.jws.JWSInputException;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
|
||||
import javax.security.cert.X509Certificate;
|
||||
@@ -85,16 +83,6 @@ public class BearerTokenRequestAuthenticator {
|
||||
}
|
||||
|
||||
protected AuthOutcome authenticateToken(HttpFacade exchange, String tokenString) {
|
||||
log.debug("Verifying access_token");
|
||||
if (log.isTraceEnabled()) {
|
||||
try {
|
||||
JWSInput jwsInput = new JWSInput(tokenString);
|
||||
String wireString = jwsInput.getWireString();
|
||||
log.tracef("\taccess_token: %s", wireString.substring(0, wireString.lastIndexOf(".")) + ".signature");
|
||||
} catch (JWSInputException e) {
|
||||
log.errorf(e, "Failed to parse access_token: %s", tokenString);
|
||||
}
|
||||
}
|
||||
try {
|
||||
token = AdapterRSATokenVerifier.verifyToken(tokenString, deployment);
|
||||
} catch (VerificationException e) {
|
||||
@@ -136,7 +124,6 @@ public class BearerTokenRequestAuthenticator {
|
||||
}
|
||||
surrogate = chain[0].getSubjectDN().getName();
|
||||
}
|
||||
log.debug("successful authorized");
|
||||
return AuthOutcome.AUTHENTICATED;
|
||||
}
|
||||
|
||||
@@ -174,10 +161,6 @@ public class BearerTokenRequestAuthenticator {
|
||||
|
||||
@Override
|
||||
public boolean challenge(HttpFacade facade) {
|
||||
if (deployment.getPolicyEnforcer() != null) {
|
||||
deployment.getPolicyEnforcer().enforce(OIDCHttpFacade.class.cast(facade));
|
||||
return true;
|
||||
}
|
||||
OIDCAuthenticationError error = new OIDCAuthenticationError(reason, description);
|
||||
facade.getRequest().setError(error);
|
||||
facade.getResponse().addHeader("WWW-Authenticate", challenge);
|
||||
|
||||
@@ -57,8 +57,6 @@ import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.apache.http.client.params.ClientPNames;
|
||||
import org.apache.http.client.params.CookiePolicy;
|
||||
|
||||
/**
|
||||
* Abstraction for creating HttpClients. Allows SSL configuration.
|
||||
@@ -291,7 +289,6 @@ public class HttpClientBuilder {
|
||||
cm = new SingleClientConnManager(registry);
|
||||
}
|
||||
BasicHttpParams params = new BasicHttpParams();
|
||||
params.setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);
|
||||
|
||||
if (proxyHost != null) {
|
||||
params.setParameter(ConnRoutePNames.DEFAULT_PROXY, proxyHost);
|
||||
|
||||
-11
@@ -68,7 +68,6 @@ public class KeycloakDeployment {
|
||||
|
||||
protected String scope;
|
||||
protected SslRequired sslRequired = SslRequired.ALL;
|
||||
protected int confidentialPort = -1;
|
||||
protected TokenStore tokenStore = TokenStore.SESSION;
|
||||
protected String stateCookieName = "OAuth_Token_Request_State";
|
||||
protected boolean useResourceRoleMappings;
|
||||
@@ -154,8 +153,6 @@ public class KeycloakDeployment {
|
||||
log.debug("resolveUrls");
|
||||
}
|
||||
|
||||
authServerBaseUrl = authUrlBuilder.build().toString();
|
||||
|
||||
String login = authUrlBuilder.clone().path(ServiceUrlConstants.AUTH_PATH).build(getRealm()).toString();
|
||||
authUrl = KeycloakUriBuilder.fromUri(login);
|
||||
realmInfoUrl = authUrlBuilder.clone().path(ServiceUrlConstants.REALM_INFO_PATH).build(getRealm()).toString();
|
||||
@@ -280,14 +277,6 @@ public class KeycloakDeployment {
|
||||
this.sslRequired = sslRequired;
|
||||
}
|
||||
|
||||
public int getConfidentialPort() {
|
||||
return confidentialPort;
|
||||
}
|
||||
|
||||
public void setConfidentialPort(int confidentialPort) {
|
||||
this.confidentialPort = confidentialPort;
|
||||
}
|
||||
|
||||
public TokenStore getTokenStore() {
|
||||
return tokenStore;
|
||||
}
|
||||
|
||||
-5
@@ -78,11 +78,6 @@ public class KeycloakDeploymentBuilder {
|
||||
} else {
|
||||
deployment.setSslRequired(SslRequired.EXTERNAL);
|
||||
}
|
||||
|
||||
if (adapterConfig.getConfidentialPort() != -1) {
|
||||
deployment.setConfidentialPort(adapterConfig.getConfidentialPort());
|
||||
}
|
||||
|
||||
if (adapterConfig.getTokenStore() != null) {
|
||||
deployment.setTokenStore(TokenStore.valueOf(adapterConfig.getTokenStore().toUpperCase()));
|
||||
} else {
|
||||
|
||||
+2
-26
@@ -66,7 +66,7 @@ public class OAuthRequestAuthenticator {
|
||||
this.reqAuthenticator = requestAuthenticator;
|
||||
this.facade = facade;
|
||||
this.deployment = deployment;
|
||||
this.sslRedirectPort = deployment.getConfidentialPort() != -1 ? deployment.getConfidentialPort() : sslRedirectPort;
|
||||
this.sslRedirectPort = sslRedirectPort;
|
||||
this.tokenStore = tokenStore;
|
||||
}
|
||||
|
||||
@@ -170,9 +170,6 @@ public class OAuthRequestAuthenticator {
|
||||
String maxAge = getQueryParamValue(OAuth2Constants.MAX_AGE);
|
||||
url = UriUtils.stripQueryParam(url, OAuth2Constants.MAX_AGE);
|
||||
|
||||
String uiLocales = getQueryParamValue(OAuth2Constants.UI_LOCALES_PARAM);
|
||||
url = UriUtils.stripQueryParam(url, OAuth2Constants.UI_LOCALES_PARAM);
|
||||
|
||||
KeycloakUriBuilder redirectUriBuilder = deployment.getAuthUrl().clone()
|
||||
.queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE)
|
||||
.queryParam(OAuth2Constants.CLIENT_ID, deployment.getResourceName())
|
||||
@@ -191,9 +188,6 @@ public class OAuthRequestAuthenticator {
|
||||
if (maxAge != null && maxAge.length() > 0) {
|
||||
redirectUriBuilder.queryParam(OAuth2Constants.MAX_AGE, maxAge);
|
||||
}
|
||||
if (uiLocales != null && uiLocales.length() > 0) {
|
||||
redirectUriBuilder.queryParam(OAuth2Constants.UI_LOCALES_PARAM, uiLocales);
|
||||
}
|
||||
|
||||
scope = TokenUtil.attachOIDCScope(scope);
|
||||
redirectUriBuilder.queryParam(OAuth2Constants.SCOPE, scope);
|
||||
@@ -350,14 +344,6 @@ public class OAuthRequestAuthenticator {
|
||||
tokenString = tokenResponse.getToken();
|
||||
refreshToken = tokenResponse.getRefreshToken();
|
||||
idTokenString = tokenResponse.getIdToken();
|
||||
|
||||
log.debug("Verifying tokens");
|
||||
if (log.isTraceEnabled()) {
|
||||
logToken("\taccess_token", tokenString);
|
||||
logToken("\tid_token", idTokenString);
|
||||
logToken("\trefresh_token", refreshToken);
|
||||
}
|
||||
|
||||
try {
|
||||
token = AdapterRSATokenVerifier.verifyToken(tokenString, deployment);
|
||||
if (idTokenString != null) {
|
||||
@@ -390,8 +376,7 @@ public class OAuthRequestAuthenticator {
|
||||
protected String stripOauthParametersFromRedirect() {
|
||||
KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(facade.getRequest().getURI())
|
||||
.replaceQueryParam(OAuth2Constants.CODE, null)
|
||||
.replaceQueryParam(OAuth2Constants.STATE, null)
|
||||
.replaceQueryParam(OAuth2Constants.SESSION_STATE, null);
|
||||
.replaceQueryParam(OAuth2Constants.STATE, null);
|
||||
return builder.build().toString();
|
||||
}
|
||||
|
||||
@@ -413,13 +398,4 @@ public class OAuthRequestAuthenticator {
|
||||
return originalUri;
|
||||
}
|
||||
|
||||
private void logToken(String name, String token) {
|
||||
try {
|
||||
JWSInput jwsInput = new JWSInput(token);
|
||||
String wireString = jwsInput.getWireString();
|
||||
log.tracef("\t%s: %s", name, wireString.substring(0, wireString.lastIndexOf(".")) + ".signature");
|
||||
} catch (JWSInputException e) {
|
||||
log.errorf(e, "Failed to parse %s: %s", name, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -32,7 +32,7 @@ import java.util.Map;
|
||||
*/
|
||||
public class ClientIdAndSecretCredentialsProvider implements ClientCredentialsProvider {
|
||||
|
||||
private static Logger logger = Logger.getLogger(ClientIdAndSecretCredentialsProvider.class);
|
||||
private static Logger logger = Logger.getLogger(ClientCredentialsProviderUtils.class);
|
||||
|
||||
public static final String PROVIDER_ID = CredentialRepresentation.SECRET;
|
||||
|
||||
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
package org.keycloak.adapters.authentication;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.adapters.AdapterUtils;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.jose.jws.JWSBuilder;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
import org.keycloak.representations.JsonWebToken;
|
||||
|
||||
/**
|
||||
* Client authentication based on JWT signed by client secret instead of private key .
|
||||
* See <a href="http://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication">specs</a> for more details.
|
||||
*
|
||||
* @author <a href="mailto:takashi.norimatsu.ws@hitachi.com">Takashi Norimatsu</a>
|
||||
*/
|
||||
public class JWTClientSecretCredentialsProvider implements ClientCredentialsProvider {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(JWTClientSecretCredentialsProvider.class);
|
||||
|
||||
public static final String PROVIDER_ID = "secret-jwt";
|
||||
|
||||
private SecretKey clientSecret;
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(KeycloakDeployment deployment, Object config) {
|
||||
if (config == null || !(config instanceof Map)) {
|
||||
throw new RuntimeException("Configuration of jwt credentials by client secret is missing or incorrect for client '" + deployment.getResourceName() + "'. Check your adapter configuration");
|
||||
}
|
||||
|
||||
Map<String, Object> cfg = (Map<String, Object>) config;
|
||||
String clientSecretString = (String) cfg.get("secret");
|
||||
if (clientSecretString == null) {
|
||||
throw new RuntimeException("Missing parameter secret-jwt in configuration of jwt for client " + deployment.getResourceName());
|
||||
}
|
||||
setClientSecret(clientSecretString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientCredentials(KeycloakDeployment deployment, Map<String, String> requestHeaders, Map<String, String> formParams) {
|
||||
String signedToken = createSignedRequestToken(deployment.getResourceName(), deployment.getRealmInfoUrl());
|
||||
formParams.put(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT);
|
||||
formParams.put(OAuth2Constants.CLIENT_ASSERTION, signedToken);
|
||||
}
|
||||
|
||||
public void setClientSecret(String clientSecretString) {
|
||||
// Get client secret and validate signature
|
||||
// According to <a href="http://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication">OIDC's client authentication spec</a>,
|
||||
// The HMAC (Hash-based Message Authentication Code) is calculated using the octets of the UTF-8 representation of the client_secret as the shared key.
|
||||
// Use "HmacSHA256" consulting <a href="https://docs.oracle.com/javase/jp/8/docs/api/javax/crypto/Mac.html">java8 api</a>
|
||||
// because it must be implemented in every java platform.
|
||||
try {
|
||||
clientSecret = new SecretKeySpec(clientSecretString.getBytes("UTF-8"), "HmacSHA256");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("Failed to create secret key spec due to unsupported encoding.");
|
||||
}
|
||||
}
|
||||
|
||||
public String createSignedRequestToken(String clientId, String realmInfoUrl) {
|
||||
JsonWebToken jwt = createRequestToken(clientId, realmInfoUrl);
|
||||
// JOSE header {"alg":"HS256","typ" : "JWT"} no need "kid" due to using only one registered client secret.
|
||||
// Use "HmacSHA256" consulting <a href="https://docs.oracle.com/javase/jp/8/docs/api/javax/crypto/Mac.html">java8 api</a>.
|
||||
// because it must be implemented in every java platform.
|
||||
return new JWSBuilder().jsonContent(jwt).hmac256(clientSecret);
|
||||
}
|
||||
|
||||
private JsonWebToken createRequestToken(String clientId, String realmInfoUrl) {
|
||||
// According to <a href="http://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication">OIDC's client authentication spec</a>,
|
||||
// JWT claims is the same as one by private_key_jwt
|
||||
|
||||
JsonWebToken reqToken = new JsonWebToken();
|
||||
reqToken.id(AdapterUtils.generateId());
|
||||
reqToken.issuer(clientId);
|
||||
reqToken.subject(clientId);
|
||||
reqToken.audience(realmInfoUrl);
|
||||
|
||||
int now = Time.currentTime();
|
||||
reqToken.issuedAt(now);
|
||||
// the same as in KEYCLOAK-2986, JWTClientCredentialsProvider's timeout field
|
||||
reqToken.expiration(now + 10);
|
||||
reqToken.notBefore(now);
|
||||
return reqToken;
|
||||
}
|
||||
|
||||
}
|
||||
+53
-79
@@ -18,6 +18,7 @@
|
||||
package org.keycloak.adapters.authorization;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -32,7 +33,6 @@ import org.keycloak.authorization.client.ClientAuthorizationContext;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
|
||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.EnforcementMode;
|
||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.MethodConfig;
|
||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
|
||||
import org.keycloak.representations.idm.authorization.Permission;
|
||||
|
||||
@@ -64,67 +64,63 @@ public abstract class AbstractPolicyEnforcer {
|
||||
return createEmptyAuthorizationContext(true);
|
||||
}
|
||||
|
||||
Request request = httpFacade.getRequest();
|
||||
String path = getPath(request);
|
||||
PathConfig pathConfig = this.pathMatcher.matches(path, this.paths);
|
||||
KeycloakSecurityContext securityContext = httpFacade.getSecurityContext();
|
||||
|
||||
if (securityContext == null) {
|
||||
if (pathConfig != null) {
|
||||
challenge(pathConfig, getRequiredScopes(pathConfig, request), httpFacade);
|
||||
}
|
||||
return createEmptyAuthorizationContext(false);
|
||||
}
|
||||
if (securityContext != null) {
|
||||
AccessToken accessToken = securityContext.getToken();
|
||||
|
||||
AccessToken accessToken = securityContext.getToken();
|
||||
if (accessToken != null) {
|
||||
Request request = httpFacade.getRequest();
|
||||
String path = getPath(request);
|
||||
PathConfig pathConfig = this.pathMatcher.matches(path, this.paths);
|
||||
|
||||
if (accessToken != null) {
|
||||
LOGGER.debugf("Checking permissions for path [%s] with config [%s].", request.getURI(), pathConfig);
|
||||
LOGGER.debugf("Checking permissions for path [%s] with config [%s].", request.getURI(), pathConfig);
|
||||
|
||||
if (pathConfig == null) {
|
||||
if (EnforcementMode.PERMISSIVE.equals(enforcementMode)) {
|
||||
return createAuthorizationContext(accessToken, null);
|
||||
if (pathConfig == null) {
|
||||
if (EnforcementMode.PERMISSIVE.equals(enforcementMode)) {
|
||||
return createAuthorizationContext(accessToken, null);
|
||||
}
|
||||
|
||||
LOGGER.debugf("Could not find a configuration for path [%s]", path);
|
||||
|
||||
if (isDefaultAccessDeniedUri(request, enforcerConfig)) {
|
||||
return createAuthorizationContext(accessToken, null);
|
||||
}
|
||||
|
||||
handleAccessDenied(httpFacade);
|
||||
|
||||
return createEmptyAuthorizationContext(false);
|
||||
}
|
||||
|
||||
LOGGER.debugf("Could not find a configuration for path [%s]", path);
|
||||
|
||||
if (isDefaultAccessDeniedUri(request, enforcerConfig)) {
|
||||
return createAuthorizationContext(accessToken, null);
|
||||
if (EnforcementMode.DISABLED.equals(pathConfig.getEnforcementMode())) {
|
||||
return createEmptyAuthorizationContext(true);
|
||||
}
|
||||
|
||||
handleAccessDenied(httpFacade);
|
||||
Set<String> requiredScopes = getRequiredScopes(pathConfig, request);
|
||||
|
||||
return createEmptyAuthorizationContext(false);
|
||||
}
|
||||
|
||||
if (EnforcementMode.DISABLED.equals(pathConfig.getEnforcementMode())) {
|
||||
return createEmptyAuthorizationContext(true);
|
||||
}
|
||||
|
||||
MethodConfig methodConfig = getRequiredScopes(pathConfig, request);
|
||||
|
||||
if (isAuthorized(pathConfig, methodConfig, accessToken, httpFacade)) {
|
||||
try {
|
||||
return createAuthorizationContext(accessToken, pathConfig);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error processing path [" + pathConfig.getPath() + "].", e);
|
||||
if (isAuthorized(pathConfig, requiredScopes, accessToken, httpFacade)) {
|
||||
try {
|
||||
return createAuthorizationContext(accessToken, pathConfig);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error processing path [" + pathConfig.getPath() + "].", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOGGER.debugf("Sending challenge to the client. Path [%s]", pathConfig);
|
||||
LOGGER.debugf("Sending challenge to the client. Path [%s]", pathConfig);
|
||||
|
||||
if (!challenge(pathConfig, methodConfig, httpFacade)) {
|
||||
LOGGER.debugf("Challenge not sent, sending default forbidden response. Path [%s]", pathConfig);
|
||||
handleAccessDenied(httpFacade);
|
||||
if (!challenge(pathConfig, requiredScopes, httpFacade)) {
|
||||
LOGGER.debugf("Challenge not sent, sending default forbidden response. Path [%s]", pathConfig);
|
||||
handleAccessDenied(httpFacade);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return createEmptyAuthorizationContext(false);
|
||||
}
|
||||
|
||||
protected abstract boolean challenge(PathConfig pathConfig, MethodConfig methodConfig, OIDCHttpFacade facade);
|
||||
protected abstract boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade);
|
||||
|
||||
protected boolean isAuthorized(PathConfig actualPathConfig, MethodConfig methodConfig, AccessToken accessToken, OIDCHttpFacade httpFacade) {
|
||||
protected boolean isAuthorized(PathConfig actualPathConfig, Set<String> requiredScopes, AccessToken accessToken, OIDCHttpFacade httpFacade) {
|
||||
Request request = httpFacade.getRequest();
|
||||
PolicyEnforcerConfig enforcerConfig = getEnforcerConfig();
|
||||
|
||||
@@ -142,7 +138,7 @@ public abstract class AbstractPolicyEnforcer {
|
||||
boolean hasPermission = false;
|
||||
|
||||
for (Permission permission : permissions) {
|
||||
if (permission.getResourceId() != null) {
|
||||
if (permission.getResourceSetId() != null) {
|
||||
if (isResourcePermission(actualPathConfig, permission)) {
|
||||
hasPermission = true;
|
||||
|
||||
@@ -150,7 +146,7 @@ public abstract class AbstractPolicyEnforcer {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hasResourceScopePermission(methodConfig, permission)) {
|
||||
if (hasResourceScopePermission(requiredScopes, permission, actualPathConfig)) {
|
||||
LOGGER.debugf("Authorization GRANTED for path [%s]. Permissions [%s].", actualPathConfig, permissions);
|
||||
if (request.getMethod().equalsIgnoreCase("DELETE") && actualPathConfig.isInstance()) {
|
||||
this.paths.remove(actualPathConfig);
|
||||
@@ -159,7 +155,7 @@ public abstract class AbstractPolicyEnforcer {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (hasResourceScopePermission(methodConfig, permission)) {
|
||||
if (hasResourceScopePermission(requiredScopes, permission, actualPathConfig)) {
|
||||
hasPermission = true;
|
||||
return true;
|
||||
}
|
||||
@@ -170,7 +166,7 @@ public abstract class AbstractPolicyEnforcer {
|
||||
return true;
|
||||
}
|
||||
|
||||
LOGGER.debugf("Authorization FAILED for path [%s]. Not enough permissions [%s].", actualPathConfig, permissions);
|
||||
LOGGER.debugf("Authorization FAILED for path [%s]. No enough permissions [%s].", actualPathConfig, permissions);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -190,29 +186,9 @@ public abstract class AbstractPolicyEnforcer {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasResourceScopePermission(MethodConfig methodConfig, Permission permission) {
|
||||
List<String> requiredScopes = methodConfig.getScopes();
|
||||
private boolean hasResourceScopePermission(Set<String> requiredScopes, Permission permission, PathConfig actualPathConfig) {
|
||||
Set<String> allowedScopes = permission.getScopes();
|
||||
|
||||
if (allowedScopes.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
PolicyEnforcerConfig.ScopeEnforcementMode enforcementMode = methodConfig.getScopesEnforcementMode();
|
||||
|
||||
if (PolicyEnforcerConfig.ScopeEnforcementMode.ALL.equals(enforcementMode)) {
|
||||
return allowedScopes.containsAll(requiredScopes);
|
||||
}
|
||||
|
||||
if (PolicyEnforcerConfig.ScopeEnforcementMode.ANY.equals(enforcementMode)) {
|
||||
for (String requiredScope : requiredScopes) {
|
||||
if (allowedScopes.contains(requiredScope)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return requiredScopes.isEmpty();
|
||||
return (allowedScopes.containsAll(requiredScopes) || allowedScopes.isEmpty());
|
||||
}
|
||||
|
||||
protected AuthzClient getAuthzClient() {
|
||||
@@ -260,22 +236,20 @@ public abstract class AbstractPolicyEnforcer {
|
||||
return request.getRelativePath();
|
||||
}
|
||||
|
||||
private MethodConfig getRequiredScopes(PathConfig pathConfig, Request request) {
|
||||
private Set<String> getRequiredScopes(PathConfig pathConfig, Request request) {
|
||||
Set<String> requiredScopes = new HashSet<>();
|
||||
|
||||
requiredScopes.addAll(pathConfig.getScopes());
|
||||
|
||||
String method = request.getMethod();
|
||||
|
||||
for (MethodConfig methodConfig : pathConfig.getMethods()) {
|
||||
for (PolicyEnforcerConfig.MethodConfig methodConfig : pathConfig.getMethods()) {
|
||||
if (methodConfig.getMethod().equals(method)) {
|
||||
return methodConfig;
|
||||
requiredScopes.addAll(methodConfig.getScopes());
|
||||
}
|
||||
}
|
||||
|
||||
MethodConfig methodConfig = new MethodConfig();
|
||||
|
||||
methodConfig.setMethod(request.getMethod());
|
||||
methodConfig.setScopes(pathConfig.getScopes());
|
||||
methodConfig.setScopesEnforcementMode(PolicyEnforcerConfig.ScopeEnforcementMode.ANY);
|
||||
|
||||
return methodConfig;
|
||||
return requiredScopes;
|
||||
}
|
||||
|
||||
private AuthorizationContext createAuthorizationContext(AccessToken accessToken, PathConfig pathConfig) {
|
||||
@@ -295,6 +269,6 @@ public abstract class AbstractPolicyEnforcer {
|
||||
}
|
||||
|
||||
private boolean matchResourcePermission(PathConfig actualPathConfig, Permission permission) {
|
||||
return permission.getResourceId().equals(actualPathConfig.getId());
|
||||
return permission.getResourceSetId().equals(actualPathConfig.getId());
|
||||
}
|
||||
}
|
||||
+38
-34
@@ -17,17 +17,16 @@
|
||||
*/
|
||||
package org.keycloak.adapters.authorization;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.adapters.OIDCHttpFacade;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.authorization.client.AuthzClient;
|
||||
import org.keycloak.authorization.client.representation.PermissionRequest;
|
||||
import org.keycloak.authorization.client.resource.PermissionResource;
|
||||
import org.keycloak.authorization.client.resource.ProtectionResource;
|
||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
|
||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
|
||||
import org.keycloak.representations.idm.authorization.PermissionRequest;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
@@ -41,41 +40,46 @@ public class BearerTokenPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean challenge(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, OIDCHttpFacade facade) {
|
||||
HttpFacade.Response response = facade.getResponse();
|
||||
AuthzClient authzClient = getAuthzClient();
|
||||
String ticket = getPermissionTicket(pathConfig, methodConfig, authzClient);
|
||||
|
||||
if (ticket == null) {
|
||||
response.setStatus(403);
|
||||
return true;
|
||||
}
|
||||
|
||||
String realm = authzClient.getConfiguration().getRealm();
|
||||
String authorizationServerUri = authzClient.getServerConfiguration().getIssuer().toString();
|
||||
response.setStatus(401);
|
||||
StringBuilder wwwAuthenticate = new StringBuilder("UMA realm=\"").append(realm).append("\"").append(",as_uri=\"").append(authorizationServerUri).append("\"");
|
||||
|
||||
if (ticket != null) {
|
||||
wwwAuthenticate.append(",ticket=\"").append(ticket).append("\"");
|
||||
}
|
||||
|
||||
response.setHeader("WWW-Authenticate", wwwAuthenticate.toString());
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Sending UMA challenge");
|
||||
protected boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
|
||||
if (getEnforcerConfig().getUserManagedAccess() != null) {
|
||||
challengeUmaAuthentication(pathConfig, requiredScopes, facade);
|
||||
} else {
|
||||
challengeEntitlementAuthentication(facade);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private String getPermissionTicket(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, AuthzClient authzClient) {
|
||||
if (getEnforcerConfig().getUserManagedAccess() != null) {
|
||||
ProtectionResource protection = authzClient.protection();
|
||||
PermissionResource permission = protection.permission();
|
||||
PermissionRequest permissionRequest = new PermissionRequest();
|
||||
permissionRequest.setResourceId(pathConfig.getId());
|
||||
permissionRequest.setScopes(new HashSet<>(methodConfig.getScopes()));
|
||||
return permission.create(permissionRequest).getTicket();
|
||||
private void challengeEntitlementAuthentication(OIDCHttpFacade facade) {
|
||||
HttpFacade.Response response = facade.getResponse();
|
||||
AuthzClient authzClient = getAuthzClient();
|
||||
String clientId = authzClient.getConfiguration().getResource();
|
||||
String authorizationServerUri = authzClient.getServerConfiguration().getIssuer().toString() + "/authz/entitlement";
|
||||
response.setStatus(401);
|
||||
response.setHeader("WWW-Authenticate", "KC_ETT realm=\"" + clientId + "\",as_uri=\"" + authorizationServerUri + "\"");
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Sending Entitlement challenge");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void challengeUmaAuthentication(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
|
||||
HttpFacade.Response response = facade.getResponse();
|
||||
AuthzClient authzClient = getAuthzClient();
|
||||
String ticket = getPermissionTicket(pathConfig, requiredScopes, authzClient);
|
||||
String clientId = authzClient.getConfiguration().getResource();
|
||||
String authorizationServerUri = authzClient.getServerConfiguration().getIssuer().toString() + "/authz/authorize";
|
||||
response.setStatus(401);
|
||||
response.setHeader("WWW-Authenticate", "UMA realm=\"" + clientId + "\",as_uri=\"" + authorizationServerUri + "\",ticket=\"" + ticket + "\"");
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Sending UMA challenge");
|
||||
}
|
||||
}
|
||||
|
||||
private String getPermissionTicket(PathConfig pathConfig, Set<String> requiredScopes, AuthzClient authzClient) {
|
||||
ProtectionResource protection = authzClient.protection();
|
||||
PermissionResource permission = protection.permission();
|
||||
PermissionRequest permissionRequest = new PermissionRequest();
|
||||
permissionRequest.setResourceSetId(pathConfig.getId());
|
||||
permissionRequest.setScopes(requiredScopes);
|
||||
return permission.forResource(permissionRequest).getTicket();
|
||||
}
|
||||
}
|
||||
+45
-46
@@ -19,23 +19,24 @@ package org.keycloak.adapters.authorization;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.OIDCHttpFacade;
|
||||
import org.keycloak.adapters.rotation.AdapterRSATokenVerifier;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.authorization.client.AuthorizationDeniedException;
|
||||
import org.keycloak.authorization.client.AuthzClient;
|
||||
import org.keycloak.authorization.client.representation.AuthorizationRequest;
|
||||
import org.keycloak.authorization.client.representation.AuthorizationResponse;
|
||||
import org.keycloak.authorization.client.representation.EntitlementRequest;
|
||||
import org.keycloak.authorization.client.representation.EntitlementResponse;
|
||||
import org.keycloak.authorization.client.representation.PermissionRequest;
|
||||
import org.keycloak.authorization.client.representation.PermissionResponse;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
|
||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
|
||||
import org.keycloak.representations.idm.authorization.AuthorizationRequest;
|
||||
import org.keycloak.representations.idm.authorization.AuthorizationResponse;
|
||||
import org.keycloak.representations.idm.authorization.Permission;
|
||||
import org.keycloak.representations.idm.authorization.PermissionRequest;
|
||||
import org.keycloak.representations.idm.authorization.PermissionResponse;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
@@ -49,14 +50,14 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAuthorized(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, AccessToken accessToken, OIDCHttpFacade httpFacade) {
|
||||
protected boolean isAuthorized(PathConfig pathConfig, Set<String> requiredScopes, AccessToken accessToken, OIDCHttpFacade httpFacade) {
|
||||
AccessToken original = accessToken;
|
||||
|
||||
if (super.isAuthorized(pathConfig, methodConfig, accessToken, httpFacade)) {
|
||||
if (super.isAuthorized(pathConfig, requiredScopes, accessToken, httpFacade)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
accessToken = requestAuthorizationToken(pathConfig, methodConfig, httpFacade);
|
||||
accessToken = requestAuthorizationToken(pathConfig, requiredScopes, httpFacade);
|
||||
|
||||
if (accessToken == null) {
|
||||
return false;
|
||||
@@ -77,23 +78,17 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||
|
||||
original.setAuthorization(authorization);
|
||||
|
||||
return super.isAuthorized(pathConfig, methodConfig, accessToken, httpFacade);
|
||||
return super.isAuthorized(pathConfig, requiredScopes, accessToken, httpFacade);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean challenge(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, OIDCHttpFacade facade) {
|
||||
protected boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
|
||||
handleAccessDenied(facade);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleAccessDenied(OIDCHttpFacade facade) {
|
||||
KeycloakSecurityContext securityContext = facade.getSecurityContext();
|
||||
|
||||
if (securityContext == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String accessDeniedPath = getEnforcerConfig().getOnDenyRedirectTo();
|
||||
HttpFacade.Response response = facade.getResponse();
|
||||
|
||||
@@ -105,43 +100,47 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
||||
}
|
||||
}
|
||||
|
||||
private AccessToken requestAuthorizationToken(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, OIDCHttpFacade httpFacade) {
|
||||
private AccessToken requestAuthorizationToken(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade httpFacade) {
|
||||
try {
|
||||
KeycloakSecurityContext securityContext = httpFacade.getSecurityContext();
|
||||
String accessTokenString = securityContext.getTokenString();
|
||||
String accessToken = httpFacade.getSecurityContext().getTokenString();
|
||||
AuthzClient authzClient = getAuthzClient();
|
||||
KeycloakDeployment deployment = getPolicyEnforcer().getDeployment();
|
||||
PermissionRequest permissionRequest = new PermissionRequest();
|
||||
|
||||
permissionRequest.setResourceId(pathConfig.getId());
|
||||
permissionRequest.setScopes(new HashSet<>(methodConfig.getScopes()));
|
||||
|
||||
AccessToken accessToken = securityContext.getToken();
|
||||
AuthorizationRequest authzRequest;
|
||||
|
||||
if (getEnforcerConfig().getUserManagedAccess() != null) {
|
||||
PermissionResponse permissionResponse = authzClient.protection().permission().create(permissionRequest);
|
||||
authzRequest = new AuthorizationRequest();
|
||||
authzRequest.setTicket(permissionResponse.getTicket());
|
||||
LOGGER.debug("Obtaining authorization for authenticated user.");
|
||||
PermissionRequest permissionRequest = new PermissionRequest();
|
||||
|
||||
permissionRequest.setResourceSetId(pathConfig.getId());
|
||||
permissionRequest.setScopes(requiredScopes);
|
||||
|
||||
PermissionResponse permissionResponse = authzClient.protection().permission().forResource(permissionRequest);
|
||||
AuthorizationRequest authzRequest = new AuthorizationRequest(permissionResponse.getTicket());
|
||||
AuthorizationResponse authzResponse = authzClient.authorization(accessToken).authorize(authzRequest);
|
||||
|
||||
if (authzResponse != null) {
|
||||
return AdapterRSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment);
|
||||
}
|
||||
|
||||
return null;
|
||||
} else {
|
||||
authzRequest = new AuthorizationRequest();
|
||||
if (accessToken.getAuthorization() != null) {
|
||||
authzRequest.addPermission(pathConfig.getId(), methodConfig.getScopes());
|
||||
LOGGER.debug("Obtaining entitlements for authenticated user.");
|
||||
AccessToken token = httpFacade.getSecurityContext().getToken();
|
||||
|
||||
if (token.getAuthorization() == null) {
|
||||
EntitlementResponse authzResponse = authzClient.entitlement(accessToken).getAll(authzClient.getConfiguration().getResource());
|
||||
return AdapterRSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment);
|
||||
} else {
|
||||
EntitlementRequest request = new EntitlementRequest();
|
||||
PermissionRequest permissionRequest = new PermissionRequest();
|
||||
permissionRequest.setResourceSetId(pathConfig.getId());
|
||||
permissionRequest.setResourceSetName(pathConfig.getName());
|
||||
permissionRequest.setScopes(new HashSet<>(pathConfig.getScopes()));
|
||||
LOGGER.debugf("Sending entitlements request: resource_set_id [%s], resource_set_name [%s], scopes [%s].", permissionRequest.getResourceSetId(), permissionRequest.getResourceSetName(), permissionRequest.getScopes());
|
||||
request.addPermission(permissionRequest);
|
||||
EntitlementResponse authzResponse = authzClient.entitlement(accessToken).get(authzClient.getConfiguration().getResource(), request);
|
||||
return AdapterRSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment);
|
||||
}
|
||||
}
|
||||
|
||||
if (accessToken.getAuthorization() != null) {
|
||||
authzRequest.setRpt(accessTokenString);
|
||||
}
|
||||
|
||||
LOGGER.debug("Obtaining authorization for authenticated user.");
|
||||
AuthorizationResponse authzResponse = authzClient.authorization(accessTokenString).authorize(authzRequest);
|
||||
|
||||
if (authzResponse != null) {
|
||||
return AdapterRSATokenVerifier.verifyToken(authzResponse.getToken(), deployment);
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (AuthorizationDeniedException e) {
|
||||
LOGGER.debug("Authorization denied", e);
|
||||
return null;
|
||||
|
||||
+4
-6
@@ -18,8 +18,8 @@
|
||||
package org.keycloak.adapters.authorization;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.keycloak.authorization.client.AuthzClient;
|
||||
import org.keycloak.authorization.client.representation.ResourceRepresentation;
|
||||
@@ -95,9 +95,7 @@ class PathMatcher {
|
||||
}
|
||||
|
||||
if (WILDCARD == expectedUri.charAt(expectedUri.length() - 1)) {
|
||||
if (matchingAnyPath == null || matchingAnyPath.getPath().length() < matchingUri.length()) {
|
||||
matchingAnyPath = entry;
|
||||
}
|
||||
matchingAnyPath = entry;
|
||||
} else {
|
||||
int suffixIndex = expectedUri.indexOf(WILDCARD + ".");
|
||||
|
||||
@@ -223,11 +221,11 @@ class PathMatcher {
|
||||
private PathConfig resolvePathConfig(PathConfig originalConfig, String path) {
|
||||
if (originalConfig.hasPattern()) {
|
||||
ProtectedResource resource = this.authzClient.protection().resource();
|
||||
List<ResourceRepresentation> search = resource.findByUri(path);
|
||||
Set<String> search = resource.findByFilter("uri=" + path);
|
||||
|
||||
if (!search.isEmpty()) {
|
||||
// resource does exist on the server, cache it
|
||||
ResourceRepresentation targetResource = search.get(0);
|
||||
ResourceRepresentation targetResource = resource.findById(search.iterator().next()).getResourceDescription();
|
||||
PathConfig config = PolicyEnforcer.createPathConfig(targetResource);
|
||||
|
||||
config.setScopes(originalConfig.getScopes());
|
||||
|
||||
+25
-37
@@ -17,15 +17,6 @@
|
||||
*/
|
||||
package org.keycloak.adapters.authorization;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.AuthorizationContext;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
@@ -34,6 +25,7 @@ import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
|
||||
import org.keycloak.authorization.client.AuthzClient;
|
||||
import org.keycloak.authorization.client.ClientAuthenticator;
|
||||
import org.keycloak.authorization.client.Configuration;
|
||||
import org.keycloak.authorization.client.representation.RegistrationResponse;
|
||||
import org.keycloak.authorization.client.representation.ResourceRepresentation;
|
||||
import org.keycloak.authorization.client.representation.ScopeRepresentation;
|
||||
import org.keycloak.authorization.client.resource.ProtectedResource;
|
||||
@@ -42,6 +34,14 @@ import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
|
||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
|
||||
import org.keycloak.representations.idm.authorization.Permission;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
@@ -58,15 +58,10 @@ public class PolicyEnforcer {
|
||||
public PolicyEnforcer(KeycloakDeployment deployment, AdapterConfig adapterConfig) {
|
||||
this.deployment = deployment;
|
||||
this.enforcerConfig = adapterConfig.getPolicyEnforcerConfig();
|
||||
Configuration configuration = new Configuration(adapterConfig.getAuthServerUrl(), adapterConfig.getRealm(), adapterConfig.getResource(), adapterConfig.getCredentials(), deployment.getClient());
|
||||
this.authzClient = AuthzClient.create(configuration, new ClientAuthenticator() {
|
||||
this.authzClient = AuthzClient.create(new Configuration(adapterConfig.getAuthServerUrl(), adapterConfig.getRealm(), adapterConfig.getResource(), adapterConfig.getCredentials(), deployment.getClient()), new ClientAuthenticator() {
|
||||
@Override
|
||||
public void configureClientCredentials(Map<String, List<String>> requestParams, Map<String, String> requestHeaders) {
|
||||
Map<String, String> formparams = new HashMap<>();
|
||||
ClientCredentialsProviderUtils.setClientCredentials(PolicyEnforcer.this.deployment, requestHeaders, formparams);
|
||||
for (Entry<String, String> param : formparams.entrySet()) {
|
||||
requestParams.put(param.getKey(), Arrays.asList(param.getValue()));
|
||||
}
|
||||
public void configureClientCredentials(HashMap<String, String> requestParams, HashMap<String, String> requestHeaders) {
|
||||
ClientCredentialsProviderUtils.setClientCredentials(PolicyEnforcer.this.deployment, requestHeaders, requestParams);
|
||||
}
|
||||
});
|
||||
this.pathMatcher = new PathMatcher(this.authzClient);
|
||||
@@ -147,34 +142,26 @@ public class PolicyEnforcer {
|
||||
Map<String, PathConfig> paths = Collections.synchronizedMap(new HashMap<String, PathConfig>());
|
||||
|
||||
for (PathConfig pathConfig : enforcerConfig.getPaths()) {
|
||||
ResourceRepresentation resource;
|
||||
Set<String> search;
|
||||
String resourceName = pathConfig.getName();
|
||||
String path = pathConfig.getPath();
|
||||
|
||||
if (resourceName != null) {
|
||||
LOGGER.debugf("Trying to find resource with name [%s] for path [%s].", resourceName, path);
|
||||
resource = protectedResource.findByName(resourceName);
|
||||
search = protectedResource.findByFilter("name=" + resourceName);
|
||||
} else {
|
||||
LOGGER.debugf("Trying to find resource with uri [%s] for path [%s].", path, path);
|
||||
List<ResourceRepresentation> resources = protectedResource.findByUri(path);
|
||||
|
||||
if (resources.size() == 1) {
|
||||
resource = resources.get(0);
|
||||
} else if (resources.size() > 1) {
|
||||
throw new RuntimeException("Multiple resources found with the same uri");
|
||||
} else {
|
||||
resource = null;
|
||||
}
|
||||
search = protectedResource.findByFilter("uri=" + path);
|
||||
}
|
||||
|
||||
if (resource == null) {
|
||||
if (search.isEmpty()) {
|
||||
if (enforcerConfig.isCreateResources()) {
|
||||
LOGGER.debugf("Creating resource on server for path [%s].", pathConfig);
|
||||
ResourceRepresentation representation = new ResourceRepresentation();
|
||||
ResourceRepresentation resource = new ResourceRepresentation();
|
||||
|
||||
representation.setName(resourceName);
|
||||
representation.setType(pathConfig.getType());
|
||||
representation.setUri(path);
|
||||
resource.setName(resourceName);
|
||||
resource.setType(pathConfig.getType());
|
||||
resource.setUri(path);
|
||||
|
||||
HashSet<ScopeRepresentation> scopes = new HashSet<>();
|
||||
|
||||
@@ -186,16 +173,16 @@ public class PolicyEnforcer {
|
||||
scopes.add(scope);
|
||||
}
|
||||
|
||||
representation.setScopes(scopes);
|
||||
resource.setScopes(scopes);
|
||||
|
||||
ResourceRepresentation registrationResponse = protectedResource.create(representation);
|
||||
RegistrationResponse registrationResponse = protectedResource.create(resource);
|
||||
|
||||
pathConfig.setId(registrationResponse.getId());
|
||||
} else {
|
||||
throw new RuntimeException("Could not find matching resource on server with uri [" + path + "] or name [" + resourceName + "]. Make sure you have created a resource on the server that matches with the path configuration.");
|
||||
}
|
||||
} else {
|
||||
pathConfig.setId(resource.getId());
|
||||
pathConfig.setId(search.iterator().next());
|
||||
}
|
||||
|
||||
PathConfig existingPath = null;
|
||||
@@ -223,7 +210,8 @@ public class PolicyEnforcer {
|
||||
Map<String, PathConfig> paths = Collections.synchronizedMap(new HashMap<String, PathConfig>());
|
||||
|
||||
for (String id : protectedResource.findAll()) {
|
||||
ResourceRepresentation resourceDescription = protectedResource.findById(id);
|
||||
RegistrationResponse response = protectedResource.findById(id);
|
||||
ResourceRepresentation resourceDescription = response.getResourceDescription();
|
||||
|
||||
if (resourceDescription.getUri() != null) {
|
||||
PathConfig pathConfig = createPathConfig(resourceDescription);
|
||||
|
||||
+1
-1
@@ -81,7 +81,7 @@ public class JWKPublicKeyLocator implements PublicKeyLocator {
|
||||
|
||||
|
||||
private PublicKey lookupCachedKey(int publicKeyCacheTtl, int currentTime, String kid) {
|
||||
if (lastRequestTime + publicKeyCacheTtl > currentTime && kid != null) {
|
||||
if (lastRequestTime + publicKeyCacheTtl > currentTime) {
|
||||
return currentKeys.get(kid);
|
||||
} else {
|
||||
return null;
|
||||
|
||||
+1
-2
@@ -16,5 +16,4 @@
|
||||
#
|
||||
|
||||
org.keycloak.adapters.authentication.ClientIdAndSecretCredentialsProvider
|
||||
org.keycloak.adapters.authentication.JWTClientCredentialsProvider
|
||||
org.keycloak.adapters.authentication.JWTClientSecretCredentialsProvider
|
||||
org.keycloak.adapters.authentication.JWTClientCredentialsProvider
|
||||
-6
@@ -21,7 +21,6 @@ import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.adapters.authentication.ClientIdAndSecretCredentialsProvider;
|
||||
import org.keycloak.adapters.authentication.JWTClientCredentialsProvider;
|
||||
import org.keycloak.adapters.authentication.JWTClientSecretCredentialsProvider;
|
||||
import org.keycloak.adapters.rotation.HardcodedPublicKeyLocator;
|
||||
import org.keycloak.adapters.rotation.JWKPublicKeyLocator;
|
||||
import org.keycloak.common.enums.RelativeUrlsUsed;
|
||||
@@ -95,9 +94,4 @@ public class KeycloakDeploymentBuilderTest {
|
||||
assertEquals(JWTClientCredentialsProvider.PROVIDER_ID, deployment.getClientAuthenticator().getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadSecretJwtCredentials() throws Exception {
|
||||
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(getClass().getResourceAsStream("/keycloak-secret-jwt.json"));
|
||||
assertEquals(JWTClientSecretCredentialsProvider.PROVIDER_ID, deployment.getClientAuthenticator().getId());
|
||||
}
|
||||
}
|
||||
-19
@@ -17,9 +17,7 @@
|
||||
package org.keycloak.adapters;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.keycloak.representations.adapters.config.AdapterConfig;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@@ -48,21 +46,4 @@ public class KeycloakDeploymentTest {
|
||||
|
||||
assertTrue(keycloakDeployment.isOAuthQueryParameterEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stripDefaultPorts() {
|
||||
KeycloakDeployment keycloakDeployment = new KeycloakDeployment();
|
||||
keycloakDeployment.setRealm("test");
|
||||
AdapterConfig config = new AdapterConfig();
|
||||
config.setAuthServerUrl("http://localhost:80/auth");
|
||||
keycloakDeployment.setAuthServerBaseUrl(config);
|
||||
|
||||
assertEquals("http://localhost/auth", keycloakDeployment.getAuthServerBaseUrl());
|
||||
|
||||
config.setAuthServerUrl("https://localhost:443/auth");
|
||||
keycloakDeployment.setAuthServerBaseUrl(config);
|
||||
|
||||
assertEquals("https://localhost/auth", keycloakDeployment.getAuthServerBaseUrl());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"realm": "demo",
|
||||
"resource": "customer-portal",
|
||||
"realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||
"auth-server-url": "https://localhost:8443/auth",
|
||||
"ssl-required": "external",
|
||||
"credentials": {
|
||||
"secret-jwt": {
|
||||
"secret": "234234-234234-234234"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-as7-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-as7-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-as7-integration-pom</artifactId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak AS7 / JBoss EAP 6 Integration</name>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -63,15 +63,6 @@
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
||||
<artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
+9
-24
@@ -53,13 +53,7 @@ public class KeycloakCliSso {
|
||||
login();
|
||||
} else if (args[0].equalsIgnoreCase("login-manual")) {
|
||||
loginManual();
|
||||
}
|
||||
/*
|
||||
else if (args[0].equalsIgnoreCase("login-cli")) {
|
||||
loginCli();
|
||||
}
|
||||
*/
|
||||
else if (args[0].equalsIgnoreCase("token")) {
|
||||
} else if (args[0].equalsIgnoreCase("token")) {
|
||||
token();
|
||||
} else if (args[0].equalsIgnoreCase("logout")) {
|
||||
logout();
|
||||
@@ -75,7 +69,6 @@ public class KeycloakCliSso {
|
||||
System.err.println("Commands:");
|
||||
System.err.println(" login - login with desktop browser if available, otherwise do manual login. Output is access token.");
|
||||
System.err.println(" login-manual - manual login");
|
||||
//System.err.println(" login-cli - attempt Keycloak proprietary cli protocol. Otherwise do normal login");
|
||||
System.err.println(" token - print access token if logged in");
|
||||
System.err.println(" logout - logout.");
|
||||
System.exit(1);
|
||||
@@ -117,7 +110,7 @@ public class KeycloakCliSso {
|
||||
return config;
|
||||
}
|
||||
|
||||
public boolean checkToken(boolean outputToken) throws Exception {
|
||||
public boolean checkToken() throws Exception {
|
||||
String token = getTokenResponse();
|
||||
if (token == null) return false;
|
||||
|
||||
@@ -134,7 +127,7 @@ public class KeycloakCliSso {
|
||||
AdapterConfig config = getConfig();
|
||||
KeycloakInstalled installed = new KeycloakInstalled(KeycloakDeploymentBuilder.build(config));
|
||||
installed.refreshToken(tokenResponse.getRefreshToken());
|
||||
processResponse(installed, outputToken);
|
||||
processResponse(installed);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
System.err.println("Error processing existing token");
|
||||
@@ -191,19 +184,11 @@ public class KeycloakCliSso {
|
||||
}
|
||||
|
||||
public void login() throws Exception {
|
||||
if (checkToken(true)) return;
|
||||
if (checkToken()) return;
|
||||
AdapterConfig config = getConfig();
|
||||
KeycloakInstalled installed = new KeycloakInstalled(KeycloakDeploymentBuilder.build(config));
|
||||
installed.login();
|
||||
processResponse(installed, true);
|
||||
}
|
||||
|
||||
public void loginCli() throws Exception {
|
||||
if (checkToken(false)) return;
|
||||
AdapterConfig config = getConfig();
|
||||
KeycloakInstalled installed = new KeycloakInstalled(KeycloakDeploymentBuilder.build(config));
|
||||
if (!installed.loginCommandLine()) installed.login();
|
||||
processResponse(installed, false);
|
||||
processResponse(installed);
|
||||
}
|
||||
|
||||
public String getHome() {
|
||||
@@ -225,7 +210,7 @@ public class KeycloakCliSso {
|
||||
return Paths.get(getHome(), System.getProperty("basepath", ".keycloak-sso"), System.getProperty("KEYCLOAK_REALM"), System.getProperty("KEYCLOAK_CLIENT") + ".json").toFile();
|
||||
}
|
||||
|
||||
private void processResponse(KeycloakInstalled installed, boolean outputToken) throws IOException {
|
||||
private void processResponse(KeycloakInstalled installed) throws IOException {
|
||||
AccessTokenResponse tokenResponse = installed.getTokenResponse();
|
||||
tokenResponse.setExpiresIn(Time.currentTime() + tokenResponse.getExpiresIn());
|
||||
tokenResponse.setIdToken(null);
|
||||
@@ -235,16 +220,16 @@ public class KeycloakCliSso {
|
||||
fos.write(output.getBytes("UTF-8"));
|
||||
fos.flush();
|
||||
fos.close();
|
||||
if (outputToken) System.out.println(tokenResponse.getToken());
|
||||
System.out.println(tokenResponse.getToken());
|
||||
}
|
||||
|
||||
public void loginManual() throws Exception {
|
||||
if (checkToken(true)) return;
|
||||
if (checkToken()) return;
|
||||
AdapterConfig config = getConfig();
|
||||
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(config);
|
||||
KeycloakInstalled installed = new KeycloakInstalled(deployment);
|
||||
installed.loginManual();
|
||||
processResponse(installed, true);
|
||||
processResponse(installed);
|
||||
}
|
||||
|
||||
public void logout() throws Exception {
|
||||
|
||||
+1
-173
@@ -17,8 +17,7 @@
|
||||
|
||||
package org.keycloak.adapters.installed;
|
||||
|
||||
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
|
||||
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
|
||||
import org.apache.commons.codec.Charsets;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.OAuthErrorException;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
@@ -33,11 +32,6 @@ import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.AccessTokenResponse;
|
||||
import org.keycloak.representations.IDToken;
|
||||
|
||||
import javax.ws.rs.client.Client;
|
||||
import javax.ws.rs.client.Entity;
|
||||
import javax.ws.rs.core.Form;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.awt.*;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
@@ -46,7 +40,6 @@ import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.PushbackInputStream;
|
||||
import java.io.Reader;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
@@ -55,8 +48,6 @@ import java.net.URISyntaxException;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
@@ -86,9 +77,6 @@ public class KeycloakInstalled {
|
||||
private Locale locale;
|
||||
private HttpResponseWriter loginResponseWriter;
|
||||
private HttpResponseWriter logoutResponseWriter;
|
||||
Pattern callbackPattern = Pattern.compile("callback\\s*=\\s*\"([^\"]+)\"");
|
||||
Pattern paramPattern = Pattern.compile("param=\"([^\"]+)\"\\s+label=\"([^\"]+)\"\\s+mask=(\\S+)");
|
||||
Pattern codePattern = Pattern.compile("code=([^&]+)");
|
||||
|
||||
|
||||
|
||||
@@ -302,86 +290,6 @@ public class KeycloakInstalled {
|
||||
status = Status.LOGGED_MANUAL;
|
||||
}
|
||||
|
||||
public boolean loginCommandLine() throws IOException, ServerRequest.HttpFailure, VerificationException {
|
||||
String redirectUri = "urn:ietf:wg:oauth:2.0:oob";
|
||||
|
||||
return loginCommandLine(redirectUri);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Experimental proprietary WWW-Authentication challenge protocol.
|
||||
* WWW-Authentication: X-Text-Form-Challenge callback="{url}" param="{param-name}" label="{param-display-label}"
|
||||
*
|
||||
* @param redirectUri
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ServerRequest.HttpFailure
|
||||
* @throws VerificationException
|
||||
*/
|
||||
public boolean loginCommandLine(String redirectUri) throws IOException, ServerRequest.HttpFailure, VerificationException {
|
||||
String authUrl = deployment.getAuthUrl().clone()
|
||||
.queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE)
|
||||
.queryParam(OAuth2Constants.CLIENT_ID, deployment.getResourceName())
|
||||
.queryParam(OAuth2Constants.REDIRECT_URI, redirectUri)
|
||||
.queryParam(OAuth2Constants.SCOPE, OAuth2Constants.SCOPE_OPENID)
|
||||
.build().toString();
|
||||
ResteasyClient client = new ResteasyClientBuilder().disableTrustManager().build();
|
||||
try {
|
||||
Response response = client.target(authUrl).request().get();
|
||||
if (response.getStatus() != 401) {
|
||||
return false;
|
||||
}
|
||||
while (true) {
|
||||
String authenticationHeader = response.getHeaderString(HttpHeaders.WWW_AUTHENTICATE);
|
||||
if (authenticationHeader == null) {
|
||||
return false;
|
||||
}
|
||||
if (!authenticationHeader.contains("X-Text-Form-Challenge")) {
|
||||
return false;
|
||||
}
|
||||
if (response.getMediaType() != null) {
|
||||
String splash = response.readEntity(String.class);
|
||||
System.console().writer().println(splash);
|
||||
}
|
||||
Matcher m = callbackPattern.matcher(authenticationHeader);
|
||||
if (!m.find()) return false;
|
||||
String callback = m.group(1);
|
||||
//System.err.println("callback: " + callback);
|
||||
m = paramPattern.matcher(authenticationHeader);
|
||||
Form form = new Form();
|
||||
while (m.find()) {
|
||||
String param = m.group(1);
|
||||
String label = m.group(2);
|
||||
String mask = m.group(3).trim();
|
||||
boolean maskInput = mask.equals("true");
|
||||
String value = null;
|
||||
if (maskInput) {
|
||||
char[] txt = System.console().readPassword(label);
|
||||
value = new String(txt);
|
||||
} else {
|
||||
value = System.console().readLine(label);
|
||||
}
|
||||
form.param(param, value);
|
||||
}
|
||||
response = client.target(callback).request().post(Entity.form(form));
|
||||
if (response.getStatus() == 401) continue;
|
||||
if (response.getStatus() != 302) return false;
|
||||
String location = response.getLocation().toString();
|
||||
m = codePattern.matcher(location);
|
||||
if (!m.find()) return false;
|
||||
String code = m.group(1);
|
||||
processCode(code, redirectUri);
|
||||
return true;
|
||||
}
|
||||
} finally {
|
||||
client.close();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String getTokenString() throws VerificationException, IOException, ServerRequest.HttpFailure {
|
||||
return tokenString;
|
||||
}
|
||||
@@ -474,86 +382,6 @@ public class KeycloakInstalled {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static class MaskingThread extends Thread {
|
||||
private volatile boolean stop;
|
||||
private char echochar = '*';
|
||||
|
||||
public MaskingThread() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin masking until asked to stop.
|
||||
*/
|
||||
public void run() {
|
||||
|
||||
int priority = Thread.currentThread().getPriority();
|
||||
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
|
||||
|
||||
try {
|
||||
stop = true;
|
||||
while(stop) {
|
||||
System.out.print("\010" + echochar);
|
||||
try {
|
||||
// attempt masking at this rate
|
||||
Thread.currentThread().sleep(1);
|
||||
}catch (InterruptedException iex) {
|
||||
Thread.currentThread().interrupt();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} finally { // restore the original priority
|
||||
Thread.currentThread().setPriority(priority);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instruct the thread to stop masking.
|
||||
*/
|
||||
public void stopMasking() {
|
||||
this.stop = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static String readMasked(Reader reader) {
|
||||
MaskingThread et = new MaskingThread();
|
||||
Thread mask = new Thread(et);
|
||||
mask.start();
|
||||
|
||||
BufferedReader in = new BufferedReader(reader);
|
||||
String password = "";
|
||||
|
||||
try {
|
||||
password = in.readLine();
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
// stop masking
|
||||
et.stopMasking();
|
||||
// return the password entered by the user
|
||||
return password;
|
||||
}
|
||||
|
||||
private String readLine(Reader reader, boolean mask) throws IOException {
|
||||
if (mask) {
|
||||
System.out.print(" ");
|
||||
return readMasked(reader);
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
char cb[] = new char[1];
|
||||
while (reader.read(cb) != -1) {
|
||||
char c = cb[0];
|
||||
if ((c == '\n') || (c == '\r')) {
|
||||
break;
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
public class CallbackListener extends Thread {
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak Jetty Integration</name>
|
||||
@@ -33,7 +33,6 @@
|
||||
<modules>
|
||||
<module>jetty-core</module>
|
||||
<module>jetty8.1</module>
|
||||
<module>jetty9.1</module>
|
||||
<module>jetty9.2</module>
|
||||
<module>jetty9.3</module>
|
||||
</modules>
|
||||
@@ -47,6 +46,7 @@
|
||||
</property>
|
||||
</activation>
|
||||
<modules>
|
||||
<module>jetty9.1</module>
|
||||
<module>jetty9.4</module>
|
||||
</modules>
|
||||
</profile>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -18,14 +18,14 @@
|
||||
|
||||
(function( window, undefined ) {
|
||||
|
||||
var KeycloakAuthorization = function (keycloak, options) {
|
||||
var KeycloakAuthorization = function (keycloak) {
|
||||
var _instance = this;
|
||||
this.rpt = null;
|
||||
|
||||
this.init = function () {
|
||||
var request = new XMLHttpRequest();
|
||||
|
||||
request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/.well-known/uma2-configuration');
|
||||
request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/.well-known/uma-configuration');
|
||||
request.onreadystatechange = function () {
|
||||
if (request.readyState == 4) {
|
||||
if (request.status == 200) {
|
||||
@@ -47,61 +47,68 @@
|
||||
* necessary information to ask a Keycloak server for authorization data using both UMA and Entitlement protocol,
|
||||
* depending on how the policy enforcer at the resource server was configured.
|
||||
*/
|
||||
this.authorize = function (authorizationRequest) {
|
||||
this.authorize = function (wwwAuthenticateHeader) {
|
||||
this.then = function (onGrant, onDeny, onError) {
|
||||
if (authorizationRequest && authorizationRequest.ticket) {
|
||||
var request = new XMLHttpRequest();
|
||||
if (wwwAuthenticateHeader.indexOf('UMA') != -1) {
|
||||
var params = wwwAuthenticateHeader.split(',');
|
||||
|
||||
request.open('POST', _instance.config.token_endpoint, true);
|
||||
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token);
|
||||
for (i = 0; i < params.length; i++) {
|
||||
var param = params[i].split('=');
|
||||
|
||||
request.onreadystatechange = function () {
|
||||
if (request.readyState == 4) {
|
||||
var status = request.status;
|
||||
if (param[0] == 'ticket') {
|
||||
var request = new XMLHttpRequest();
|
||||
|
||||
if (status >= 200 && status < 300) {
|
||||
var rpt = JSON.parse(request.responseText).access_token;
|
||||
_instance.rpt = rpt;
|
||||
onGrant(rpt);
|
||||
} else if (status == 403) {
|
||||
if (onDeny) {
|
||||
onDeny();
|
||||
} else {
|
||||
console.error('Authorization request was denied by the server.');
|
||||
request.open('POST', _instance.config.rpt_endpoint, true);
|
||||
request.setRequestHeader('Content-Type', 'application/json')
|
||||
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
|
||||
|
||||
request.onreadystatechange = function () {
|
||||
if (request.readyState == 4) {
|
||||
var status = request.status;
|
||||
|
||||
if (status >= 200 && status < 300) {
|
||||
var rpt = JSON.parse(request.responseText).rpt;
|
||||
_instance.rpt = rpt;
|
||||
onGrant(rpt);
|
||||
} else if (status == 403) {
|
||||
if (onDeny) {
|
||||
onDeny();
|
||||
} else {
|
||||
console.error('Authorization request was denied by the server.');
|
||||
}
|
||||
} else {
|
||||
if (onError) {
|
||||
onError();
|
||||
} else {
|
||||
console.error('Could not obtain authorization data from server.');
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (onError) {
|
||||
onError();
|
||||
} else {
|
||||
console.error('Could not obtain authorization data from server.');
|
||||
};
|
||||
|
||||
var ticket = param[1].substring(1, param[1].length - 1).trim();
|
||||
|
||||
request.send(JSON.stringify(
|
||||
{
|
||||
ticket: ticket,
|
||||
rpt: _instance.rpt
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
var params = "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket&client_id=" + keycloak.clientId + "&ticket=" + authorizationRequest.ticket;
|
||||
|
||||
if (authorizationRequest.submitRequest != undefined) {
|
||||
params += "&submit_request=" + authorizationRequest.submitRequest;
|
||||
}
|
||||
} else if (wwwAuthenticateHeader.indexOf('KC_ETT') != -1) {
|
||||
var params = wwwAuthenticateHeader.substring('KC_ETT'.length).trim().split(',');
|
||||
var clientId = null;
|
||||
|
||||
var metadata = authorizationRequest.metadata;
|
||||
for (i = 0; i < params.length; i++) {
|
||||
var param = params[i].split('=');
|
||||
|
||||
if (metadata) {
|
||||
if (metadata.responseIncludeResourceName) {
|
||||
params += "&response_include_resource_name=" + metadata.responseIncludeResourceName;
|
||||
}
|
||||
if (metadata.responsePermissionsLimit) {
|
||||
params += "&response_permissions_limit=" + metadata.responsePermissionsLimit;
|
||||
if (param[0] == 'realm') {
|
||||
clientId = param[1].substring(1, param[1].length - 1).trim();
|
||||
}
|
||||
}
|
||||
|
||||
if (_instance.rpt && (authorizationRequest.incrementalAuthorization == undefined || authorizationRequest.incrementalAuthorization)) {
|
||||
params += "&rpt=" + _instance.rpt;
|
||||
}
|
||||
|
||||
request.send(params);
|
||||
_instance.entitlement(clientId).then(onGrant, onDeny, onError);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -109,22 +116,20 @@
|
||||
};
|
||||
|
||||
/**
|
||||
* Obtains all entitlements from a Keycloak Server based on a given resourceServerId.
|
||||
* Obtains all entitlements from a Keycloak Server based on a give resourceServerId.
|
||||
*/
|
||||
this.entitlement = function (resourceServerId, authorizationRequest) {
|
||||
this.entitlement = function (resourceSeververId, entitlementRequest ) {
|
||||
this.then = function (onGrant, onDeny, onError) {
|
||||
var request = new XMLHttpRequest();
|
||||
|
||||
request.open('POST', _instance.config.token_endpoint, true);
|
||||
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token);
|
||||
|
||||
|
||||
request.onreadystatechange = function () {
|
||||
if (request.readyState == 4) {
|
||||
var status = request.status;
|
||||
|
||||
if (status >= 200 && status < 300) {
|
||||
var rpt = JSON.parse(request.responseText).access_token;
|
||||
var rpt = JSON.parse(request.responseText).rpt;
|
||||
_instance.rpt = rpt;
|
||||
onGrant(rpt);
|
||||
} else if (status == 403) {
|
||||
@@ -143,62 +148,19 @@
|
||||
}
|
||||
};
|
||||
|
||||
if (!authorizationRequest) {
|
||||
authorizationRequest = {};
|
||||
var erJson = null
|
||||
|
||||
if(entitlementRequest) {
|
||||
request.open('POST', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true);
|
||||
request.setRequestHeader("Content-type", "application/json");
|
||||
erJson = JSON.stringify(entitlementRequest)
|
||||
} else {
|
||||
request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true);
|
||||
}
|
||||
|
||||
var params = "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket&client_id=" + keycloak.clientId;
|
||||
request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
|
||||
request.send(erJson);
|
||||
|
||||
if (authorizationRequest.claimToken) {
|
||||
params += "&claim_token=" + authorizationRequest.claimToken;
|
||||
|
||||
if (authorizationRequest.claimTokenFormat) {
|
||||
params += "&claim_token_format=" + authorizationRequest.claimTokenFormat;
|
||||
}
|
||||
}
|
||||
|
||||
params += "&audience=" + resourceServerId;
|
||||
|
||||
var permissions = authorizationRequest.permissions;
|
||||
|
||||
if (!permissions) {
|
||||
permissions = [];
|
||||
}
|
||||
|
||||
for (i = 0; i < permissions.length; i++) {
|
||||
var resource = permissions[i];
|
||||
var permission = resource.id;
|
||||
|
||||
if (resource.scopes && resource.scopes.length > 0) {
|
||||
permission += "#";
|
||||
for (j = 0; j < resource.scopes.length; j++) {
|
||||
var scope = resource.scopes[j];
|
||||
if (permission.indexOf('#') != permission.length - 1) {
|
||||
permission += ",";
|
||||
}
|
||||
permission += scope;
|
||||
}
|
||||
}
|
||||
|
||||
params += "&permission=" + permission;
|
||||
}
|
||||
|
||||
var metadata = authorizationRequest.metadata;
|
||||
|
||||
if (metadata) {
|
||||
if (metadata.responseIncludeResourceName) {
|
||||
params += "&response_include_resource_name=" + metadata.responseIncludeResourceName;
|
||||
}
|
||||
if (metadata.responsePermissionsLimit) {
|
||||
params += "&response_permissions_limit=" + metadata.responsePermissionsLimit;
|
||||
}
|
||||
}
|
||||
|
||||
if (_instance.rpt) {
|
||||
params += "&rpt=" + _instance.rpt;
|
||||
}
|
||||
|
||||
request.send(params);
|
||||
};
|
||||
|
||||
return this;
|
||||
|
||||
+2
-7
@@ -36,16 +36,11 @@ declare namespace Keycloak {
|
||||
type KeycloakFlow = 'standard'|'implicit'|'hybrid';
|
||||
|
||||
interface KeycloakInitOptions {
|
||||
/**
|
||||
* @private Undocumented.
|
||||
*/
|
||||
useNonce?: boolean;
|
||||
|
||||
/**
|
||||
* @private Undocumented.
|
||||
*/
|
||||
adapter?: KeycloakAdapterName;
|
||||
|
||||
|
||||
/**
|
||||
* Specifies an action to do on load.
|
||||
*/
|
||||
@@ -83,7 +78,7 @@ declare namespace Keycloak {
|
||||
* Set the interval to check login state (in seconds).
|
||||
* @default 5
|
||||
*/
|
||||
checkLoginIframeInterval?: number;
|
||||
checkLoginIframeInterval?: boolean;
|
||||
|
||||
/**
|
||||
* Set the OpenID Connect response mode to send to Keycloak upon login.
|
||||
|
||||
@@ -40,8 +40,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
var useNonce = true;
|
||||
|
||||
kc.init = function (initOptions) {
|
||||
kc.authenticated = false;
|
||||
|
||||
@@ -60,10 +58,6 @@
|
||||
}
|
||||
|
||||
if (initOptions) {
|
||||
if (typeof initOptions.useNonce !== 'undefined') {
|
||||
useNonce = initOptions.useNonce;
|
||||
}
|
||||
|
||||
if (typeof initOptions.checkLoginIframe !== 'undefined') {
|
||||
loginIframe.enable = initOptions.checkLoginIframe;
|
||||
}
|
||||
@@ -165,15 +159,10 @@
|
||||
var callback = parseCallback(window.location.href);
|
||||
|
||||
if (callback) {
|
||||
setupCheckLoginIframe();
|
||||
window.history.replaceState({}, null, callback.newUrl);
|
||||
}
|
||||
|
||||
if (callback && callback.valid) {
|
||||
return setupCheckLoginIframe().success(function() {
|
||||
processCallback(callback, initPromise);
|
||||
}).error(function (e) {
|
||||
initPromise.setError();
|
||||
});
|
||||
processCallback(callback, initPromise);
|
||||
return;
|
||||
} else if (initOptions) {
|
||||
if (initOptions.token && initOptions.refreshToken) {
|
||||
setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken);
|
||||
@@ -241,25 +230,22 @@
|
||||
|
||||
callbackStorage.add(callbackState);
|
||||
|
||||
var baseUrl;
|
||||
var action = 'auth';
|
||||
if (options && options.action == 'register') {
|
||||
baseUrl = kc.endpoints.register();
|
||||
} else {
|
||||
baseUrl = kc.endpoints.authorize();
|
||||
action = 'registrations';
|
||||
}
|
||||
|
||||
var scope = (options && options.scope) ? "openid " + options.scope : "openid";
|
||||
|
||||
var url = baseUrl
|
||||
var url = getRealmUrl()
|
||||
+ '/protocol/openid-connect/' + action
|
||||
+ '?client_id=' + encodeURIComponent(kc.clientId)
|
||||
+ '&redirect_uri=' + encodeURIComponent(redirectUri)
|
||||
+ '&state=' + encodeURIComponent(state)
|
||||
+ '&nonce=' + encodeURIComponent(nonce)
|
||||
+ '&response_mode=' + encodeURIComponent(kc.responseMode)
|
||||
+ '&response_type=' + encodeURIComponent(kc.responseType)
|
||||
+ '&scope=' + encodeURIComponent(scope);
|
||||
if (useNonce) {
|
||||
url = url + '&nonce=' + encodeURIComponent(nonce);
|
||||
}
|
||||
|
||||
if (options && options.prompt) {
|
||||
url += '&prompt=' + encodeURIComponent(options.prompt);
|
||||
@@ -289,7 +275,8 @@
|
||||
}
|
||||
|
||||
kc.createLogoutUrl = function(options) {
|
||||
var url = kc.endpoints.logout()
|
||||
var url = getRealmUrl()
|
||||
+ '/protocol/openid-connect/logout'
|
||||
+ '?redirect_uri=' + encodeURIComponent(adapter.redirectUri(options, false));
|
||||
|
||||
return url;
|
||||
@@ -308,14 +295,11 @@
|
||||
}
|
||||
|
||||
kc.createAccountUrl = function(options) {
|
||||
var realm = getRealmUrl();
|
||||
var url = undefined;
|
||||
if (typeof realm !== 'undefined') {
|
||||
url = realm
|
||||
var url = getRealmUrl()
|
||||
+ '/account'
|
||||
+ '?referrer=' + encodeURIComponent(kc.clientId)
|
||||
+ '&referrer_uri=' + encodeURIComponent(adapter.redirectUri(options));
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
@@ -363,7 +347,7 @@
|
||||
}
|
||||
|
||||
kc.loadUserInfo = function() {
|
||||
var url = kc.endpoints.userinfo();
|
||||
var url = getRealmUrl() + '/protocol/openid-connect/userinfo';
|
||||
var req = new XMLHttpRequest();
|
||||
req.open('GET', url, true);
|
||||
req.setRequestHeader('Accept', 'application/json');
|
||||
@@ -428,7 +412,7 @@
|
||||
promise.setSuccess(false);
|
||||
} else {
|
||||
var params = 'grant_type=refresh_token&' + 'refresh_token=' + kc.refreshToken;
|
||||
var url = kc.endpoints.token();
|
||||
var url = getRealmUrl() + '/protocol/openid-connect/token';
|
||||
|
||||
refreshQueue.push(promise);
|
||||
|
||||
@@ -502,14 +486,10 @@
|
||||
}
|
||||
|
||||
function getRealmUrl() {
|
||||
if (typeof kc.authServerUrl !== 'undefined') {
|
||||
if (kc.authServerUrl.charAt(kc.authServerUrl.length - 1) == '/') {
|
||||
return kc.authServerUrl + 'realms/' + encodeURIComponent(kc.realm);
|
||||
} else {
|
||||
return kc.authServerUrl + '/realms/' + encodeURIComponent(kc.realm);
|
||||
}
|
||||
if (kc.authServerUrl.charAt(kc.authServerUrl.length - 1) == '/') {
|
||||
return kc.authServerUrl + 'realms/' + encodeURIComponent(kc.realm);
|
||||
} else {
|
||||
return undefined;
|
||||
return kc.authServerUrl + '/realms/' + encodeURIComponent(kc.realm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,7 +523,7 @@
|
||||
|
||||
if ((kc.flow != 'implicit') && code) {
|
||||
var params = 'code=' + code + '&grant_type=authorization_code';
|
||||
var url = kc.endpoints.token();
|
||||
var url = getRealmUrl() + '/protocol/openid-connect/token';
|
||||
|
||||
var req = new XMLHttpRequest();
|
||||
req.open('POST', url, true);
|
||||
@@ -580,9 +560,9 @@
|
||||
|
||||
setToken(accessToken, refreshToken, idToken, timeLocal);
|
||||
|
||||
if (useNonce && ((kc.tokenParsed && kc.tokenParsed.nonce != oauth.storedNonce) ||
|
||||
if ((kc.tokenParsed && kc.tokenParsed.nonce != oauth.storedNonce) ||
|
||||
(kc.refreshTokenParsed && kc.refreshTokenParsed.nonce != oauth.storedNonce) ||
|
||||
(kc.idTokenParsed && kc.idTokenParsed.nonce != oauth.storedNonce))) {
|
||||
(kc.idTokenParsed && kc.idTokenParsed.nonce != oauth.storedNonce)) {
|
||||
|
||||
console.info('[KEYCLOAK] Invalid nonce, clearing token');
|
||||
kc.clearToken();
|
||||
@@ -607,65 +587,6 @@
|
||||
configUrl = config;
|
||||
}
|
||||
|
||||
function setupOidcEndoints(oidcConfiguration) {
|
||||
if (! oidcConfiguration) {
|
||||
kc.endpoints = {
|
||||
authorize: function() {
|
||||
return getRealmUrl() + '/protocol/openid-connect/auth';
|
||||
},
|
||||
token: function() {
|
||||
return getRealmUrl() + '/protocol/openid-connect/token';
|
||||
},
|
||||
logout: function() {
|
||||
return getRealmUrl() + '/protocol/openid-connect/logout';
|
||||
},
|
||||
checkSessionIframe: function() {
|
||||
var src = getRealmUrl() + '/protocol/openid-connect/login-status-iframe.html';
|
||||
if (kc.iframeVersion) {
|
||||
src = src + '?version=' + kc.iframeVersion;
|
||||
}
|
||||
return src;
|
||||
},
|
||||
register: function() {
|
||||
return getRealmUrl() + '/protocol/openid-connect/registrations';
|
||||
},
|
||||
userinfo: function() {
|
||||
return getRealmUrl() + '/protocol/openid-connect/userinfo';
|
||||
}
|
||||
};
|
||||
} else {
|
||||
kc.endpoints = {
|
||||
authorize: function() {
|
||||
return oidcConfiguration.authorization_endpoint;
|
||||
},
|
||||
token: function() {
|
||||
return oidcConfiguration.token_endpoint;
|
||||
},
|
||||
logout: function() {
|
||||
if (!oidcConfiguration.end_session_endpoint) {
|
||||
throw "Not supported by the OIDC server";
|
||||
}
|
||||
return oidcConfiguration.end_session_endpoint;
|
||||
},
|
||||
checkSessionIframe: function() {
|
||||
if (!oidcConfiguration.check_session_iframe) {
|
||||
throw "Not supported by the OIDC server";
|
||||
}
|
||||
return oidcConfiguration.check_session_iframe;
|
||||
},
|
||||
register: function() {
|
||||
throw 'Redirection to "Register user" page not supported in standard OIDC mode';
|
||||
},
|
||||
userinfo: function() {
|
||||
if (!oidcConfiguration.userinfo_endpoint) {
|
||||
throw "Not supported by the OIDC server";
|
||||
}
|
||||
return oidcConfiguration.userinfo_endpoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (configUrl) {
|
||||
var req = new XMLHttpRequest();
|
||||
req.open('GET', configUrl, true);
|
||||
@@ -680,7 +601,7 @@
|
||||
kc.realm = config['realm'];
|
||||
kc.clientId = config['resource'];
|
||||
kc.clientSecret = (config['credentials'] || {})['secret'];
|
||||
setupOidcEndoints(null);
|
||||
|
||||
promise.setSuccess();
|
||||
} else {
|
||||
promise.setError();
|
||||
@@ -690,62 +611,30 @@
|
||||
|
||||
req.send();
|
||||
} else {
|
||||
if (!config['url']) {
|
||||
var scripts = document.getElementsByTagName('script');
|
||||
for (var i = 0; i < scripts.length; i++) {
|
||||
if (scripts[i].src.match(/.*keycloak\.js/)) {
|
||||
config.url = scripts[i].src.substr(0, scripts[i].src.indexOf('/js/keycloak.js'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.realm) {
|
||||
throw 'realm missing';
|
||||
}
|
||||
|
||||
if (!config.clientId) {
|
||||
throw 'clientId missing';
|
||||
}
|
||||
|
||||
kc.authServerUrl = config.url;
|
||||
kc.realm = config.realm;
|
||||
kc.clientId = config.clientId;
|
||||
kc.clientSecret = (config.credentials || {}).secret;
|
||||
|
||||
var oidcProvider = config['oidcProvider'];
|
||||
if (!oidcProvider) {
|
||||
if (!config['url']) {
|
||||
var scripts = document.getElementsByTagName('script');
|
||||
for (var i = 0; i < scripts.length; i++) {
|
||||
if (scripts[i].src.match(/.*keycloak\.js/)) {
|
||||
config.url = scripts[i].src.substr(0, scripts[i].src.indexOf('/js/keycloak.js'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!config.realm) {
|
||||
throw 'realm missing';
|
||||
}
|
||||
|
||||
kc.authServerUrl = config.url;
|
||||
kc.realm = config.realm;
|
||||
setupOidcEndoints(null);
|
||||
promise.setSuccess();
|
||||
} else {
|
||||
if (typeof oidcProvider === 'string') {
|
||||
var oidcProviderConfigUrl;
|
||||
if (oidcProvider.charAt(oidcProvider.length - 1) == '/') {
|
||||
oidcProviderConfigUrl = oidcProvider + '.well-known/openid-configuration';
|
||||
} else {
|
||||
oidcProviderConfigUrl = oidcProvider + '/.well-known/openid-configuration';
|
||||
}
|
||||
var req = new XMLHttpRequest();
|
||||
req.open('GET', oidcProviderConfigUrl, true);
|
||||
req.setRequestHeader('Accept', 'application/json');
|
||||
|
||||
req.onreadystatechange = function () {
|
||||
if (req.readyState == 4) {
|
||||
if (req.status == 200 || fileLoaded(req)) {
|
||||
var oidcProviderConfig = JSON.parse(req.responseText);
|
||||
setupOidcEndoints(oidcProviderConfig);
|
||||
promise.setSuccess();
|
||||
} else {
|
||||
promise.setError();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
req.send();
|
||||
} else {
|
||||
setupOidcEndoints(oidcProvider);
|
||||
promise.setSuccess();
|
||||
}
|
||||
}
|
||||
promise.setSuccess();
|
||||
}
|
||||
|
||||
return promise.promise;
|
||||
@@ -864,137 +753,23 @@
|
||||
}
|
||||
|
||||
function parseCallback(url) {
|
||||
var oauth = parseCallbackUrl(url);
|
||||
if (!oauth) {
|
||||
return;
|
||||
}
|
||||
|
||||
var oauth = new CallbackParser(url, kc.responseMode).parseUri();
|
||||
var oauthState = callbackStorage.get(oauth.state);
|
||||
|
||||
if (oauthState) {
|
||||
oauth.valid = true;
|
||||
if (oauthState && (oauth.code || oauth.error || oauth.access_token || oauth.id_token)) {
|
||||
oauth.redirectUri = oauthState.redirectUri;
|
||||
oauth.storedNonce = oauthState.nonce;
|
||||
oauth.prompt = oauthState.prompt;
|
||||
}
|
||||
|
||||
return oauth;
|
||||
}
|
||||
|
||||
function parseCallbackUrl(url) {
|
||||
var supportedParams;
|
||||
switch (kc.flow) {
|
||||
case 'standard':
|
||||
supportedParams = ['code', 'state', 'session_state'];
|
||||
break;
|
||||
case 'implicit':
|
||||
supportedParams = ['access_token', 'id_token', 'state', 'session_state'];
|
||||
break;
|
||||
case 'hybrid':
|
||||
supportedParams = ['access_token', 'id_token', 'code', 'state', 'session_state'];
|
||||
break;
|
||||
}
|
||||
|
||||
supportedParams.push('error');
|
||||
supportedParams.push('error_description');
|
||||
supportedParams.push('error_uri');
|
||||
|
||||
var queryIndex = url.indexOf('?');
|
||||
var fragmentIndex = url.indexOf('#');
|
||||
|
||||
var newUrl;
|
||||
var parsed;
|
||||
|
||||
if (kc.responseMode === 'query' && queryIndex !== -1) {
|
||||
newUrl = url.substring(0, queryIndex);
|
||||
parsed = parseCallbackParams(url.substring(queryIndex + 1, fragmentIndex !== -1 ? fragmentIndex : url.length), supportedParams);
|
||||
if (parsed.paramsString !== '') {
|
||||
newUrl += '?' + parsed.paramsString;
|
||||
if (oauth.fragment) {
|
||||
oauth.newUrl += '#' + oauth.fragment;
|
||||
}
|
||||
if (fragmentIndex !== -1) {
|
||||
newUrl += url.substring(fragmentIndex);
|
||||
}
|
||||
} else if (kc.responseMode === 'fragment' && fragmentIndex !== -1) {
|
||||
newUrl = url.substring(0, fragmentIndex);
|
||||
parsed = parseCallbackParams(url.substring(fragmentIndex + 1), supportedParams);
|
||||
if (parsed.paramsString !== '') {
|
||||
newUrl += '#' + parsed.paramsString;
|
||||
}
|
||||
}
|
||||
|
||||
if (parsed && parsed.oauthParams) {
|
||||
if (kc.flow === 'standard' || kc.flow === 'hybrid') {
|
||||
if ((parsed.oauthParams.code || parsed.oauthParams.error) && parsed.oauthParams.state) {
|
||||
parsed.oauthParams.newUrl = newUrl;
|
||||
return parsed.oauthParams;
|
||||
}
|
||||
} else if (kc.flow === 'implicit') {
|
||||
if ((parsed.oauthParams.access_token || parsed.oauthParams.error) && parsed.oauthParams.state) {
|
||||
parsed.oauthParams.newUrl = newUrl;
|
||||
return parsed.oauthParams;
|
||||
}
|
||||
}
|
||||
return oauth;
|
||||
}
|
||||
}
|
||||
|
||||
function parseCallbackParams(paramsString, supportedParams) {
|
||||
var p = paramsString.split('&');
|
||||
var result = {
|
||||
paramsString: '',
|
||||
oauthParams: {}
|
||||
}
|
||||
for (var i = 0; i < p.length; i++) {
|
||||
var t = p[i].split('=');
|
||||
if (supportedParams.indexOf(t[0]) !== -1) {
|
||||
result.oauthParams[t[0]] = t[1];
|
||||
} else {
|
||||
if (result.paramsString !== '') {
|
||||
result.paramsString += '&';
|
||||
}
|
||||
result.paramsString += p[i];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function createPromise() {
|
||||
if (typeof Promise === "function") {
|
||||
return createNativePromise();
|
||||
} else {
|
||||
return createLegacyPromise();
|
||||
}
|
||||
}
|
||||
|
||||
function createNativePromise() {
|
||||
// Need to create a native Promise which also preserves the
|
||||
// interface of the custom promise type previously used by the API
|
||||
var p = {
|
||||
setSuccess: function(result) {
|
||||
p.success = true;
|
||||
p.resolve(result);
|
||||
},
|
||||
|
||||
setError: function(result) {
|
||||
p.success = false;
|
||||
p.reject(result);
|
||||
}
|
||||
};
|
||||
p.promise = new Promise(function(resolve, reject) {
|
||||
p.resolve = resolve;
|
||||
p.reject = reject;
|
||||
});
|
||||
p.promise.success = function(callback) {
|
||||
p.promise.then(callback);
|
||||
return p.promise;
|
||||
}
|
||||
p.promise.error = function(callback) {
|
||||
p.promise.catch(callback);
|
||||
return p.promise;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
function createLegacyPromise() {
|
||||
var p = {
|
||||
setSuccess: function(result) {
|
||||
p.success = true;
|
||||
@@ -1051,18 +826,22 @@
|
||||
loginIframe.iframe = iframe;
|
||||
|
||||
iframe.onload = function() {
|
||||
var authUrl = kc.endpoints.authorize();
|
||||
if (authUrl.charAt(0) === '/') {
|
||||
var realmUrl = getRealmUrl();
|
||||
if (realmUrl.charAt(0) === '/') {
|
||||
loginIframe.iframeOrigin = getOrigin();
|
||||
} else {
|
||||
loginIframe.iframeOrigin = authUrl.substring(0, authUrl.indexOf('/', 8));
|
||||
loginIframe.iframeOrigin = realmUrl.substring(0, realmUrl.indexOf('/', 8));
|
||||
}
|
||||
promise.setSuccess();
|
||||
|
||||
setTimeout(check, loginIframe.interval * 1000);
|
||||
}
|
||||
|
||||
var src = kc.endpoints.checkSessionIframe();
|
||||
var src = getRealmUrl() + '/protocol/openid-connect/login-status-iframe.html';
|
||||
if (kc.iframeVersion) {
|
||||
src = src + '?version=' + kc.iframeVersion;
|
||||
}
|
||||
|
||||
iframe.setAttribute('src', src );
|
||||
iframe.setAttribute('title', 'keycloak-session-iframe' );
|
||||
iframe.style.display = 'none';
|
||||
@@ -1142,12 +921,7 @@
|
||||
},
|
||||
|
||||
accountManagement : function() {
|
||||
var accountUrl = kc.createAccountUrl();
|
||||
if (typeof accountUrl !== 'undefined') {
|
||||
window.location.href = accountUrl;
|
||||
} else {
|
||||
throw "Not supported by the OIDC server";
|
||||
}
|
||||
window.location.href = kc.createAccountUrl();
|
||||
return createPromise().promise;
|
||||
},
|
||||
|
||||
@@ -1161,7 +935,12 @@
|
||||
} else if (kc.redirectUri) {
|
||||
return kc.redirectUri;
|
||||
} else {
|
||||
return location.href;
|
||||
var redirectUri = location.href;
|
||||
if (location.hash && encodeHash) {
|
||||
redirectUri = redirectUri.substring(0, location.href.indexOf('#'));
|
||||
redirectUri += (redirectUri.indexOf('?') == -1 ? '?' : '&') + 'redirect_fragment=' + encodeURIComponent(location.hash.substring(1));
|
||||
}
|
||||
return redirectUri;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1263,16 +1042,12 @@
|
||||
|
||||
accountManagement : function() {
|
||||
var accountUrl = kc.createAccountUrl();
|
||||
if (typeof accountUrl !== 'undefined') {
|
||||
var ref = cordovaOpenWindowWrapper(accountUrl, '_blank', 'location=no');
|
||||
ref.addEventListener('loadstart', function(event) {
|
||||
if (event.url.indexOf('http://localhost') == 0) {
|
||||
ref.close();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
throw "Not supported by the OIDC server";
|
||||
}
|
||||
var ref = cordovaOpenWindowWrapper(accountUrl, '_blank', 'location=no');
|
||||
ref.addEventListener('loadstart', function(event) {
|
||||
if (event.url.indexOf('http://localhost') == 0) {
|
||||
ref.close();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
redirectUri: function(options) {
|
||||
@@ -1402,6 +1177,99 @@
|
||||
|
||||
return new CookieStorage();
|
||||
}
|
||||
|
||||
var CallbackParser = function(uriToParse, responseMode) {
|
||||
if (!(this instanceof CallbackParser)) {
|
||||
return new CallbackParser(uriToParse, responseMode);
|
||||
}
|
||||
var parser = this;
|
||||
|
||||
var initialParse = function() {
|
||||
var baseUri = null;
|
||||
var queryString = null;
|
||||
var fragmentString = null;
|
||||
|
||||
var questionMarkIndex = uriToParse.indexOf("?");
|
||||
var fragmentIndex = uriToParse.indexOf("#", questionMarkIndex + 1);
|
||||
if (questionMarkIndex == -1 && fragmentIndex == -1) {
|
||||
baseUri = uriToParse;
|
||||
} else if (questionMarkIndex != -1) {
|
||||
baseUri = uriToParse.substring(0, questionMarkIndex);
|
||||
queryString = uriToParse.substring(questionMarkIndex + 1);
|
||||
if (fragmentIndex != -1) {
|
||||
fragmentIndex = queryString.indexOf("#");
|
||||
fragmentString = queryString.substring(fragmentIndex + 1);
|
||||
queryString = queryString.substring(0, fragmentIndex);
|
||||
}
|
||||
} else {
|
||||
baseUri = uriToParse.substring(0, fragmentIndex);
|
||||
fragmentString = uriToParse.substring(fragmentIndex + 1);
|
||||
}
|
||||
|
||||
return { baseUri: baseUri, queryString: queryString, fragmentString: fragmentString };
|
||||
}
|
||||
|
||||
var parseParams = function(paramString) {
|
||||
var result = {};
|
||||
var params = paramString.split('&');
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var p = params[i].split('=');
|
||||
var paramName = decodeURIComponent(p[0]);
|
||||
var paramValue = decodeURIComponent(p[1]);
|
||||
result[paramName] = paramValue;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
var handleQueryParam = function(paramName, paramValue, oauth) {
|
||||
var supportedOAuthParams = [ 'code', 'state', 'error', 'error_description' ];
|
||||
|
||||
for (var i = 0 ; i< supportedOAuthParams.length ; i++) {
|
||||
if (paramName === supportedOAuthParams[i]) {
|
||||
oauth[paramName] = paramValue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
parser.parseUri = function() {
|
||||
var parsedUri = initialParse();
|
||||
|
||||
var queryParams = {};
|
||||
if (parsedUri.queryString) {
|
||||
queryParams = parseParams(parsedUri.queryString);
|
||||
}
|
||||
|
||||
var oauth = { newUrl: parsedUri.baseUri };
|
||||
for (var param in queryParams) {
|
||||
switch (param) {
|
||||
case 'redirect_fragment':
|
||||
oauth.fragment = queryParams[param];
|
||||
break;
|
||||
default:
|
||||
if (responseMode != 'query' || !handleQueryParam(param, queryParams[param], oauth)) {
|
||||
oauth.newUrl += (oauth.newUrl.indexOf('?') == -1 ? '?' : '&') + param + '=' + encodeURIComponent(queryParams[param]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (responseMode === 'fragment') {
|
||||
var fragmentParams = {};
|
||||
if (parsedUri.fragmentString) {
|
||||
fragmentParams = parseParams(parsedUri.fragmentString);
|
||||
}
|
||||
for (var param in fragmentParams) {
|
||||
oauth[param] = fragmentParams[param];
|
||||
}
|
||||
}
|
||||
|
||||
return oauth;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( typeof module === "object" && module && typeof module.exports === "object" ) {
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
req.onreadystatechange = function () {
|
||||
if (req.readyState === 4) {
|
||||
if (req.status === 204 || req.status === 1223) {
|
||||
if (req.status === 204) {
|
||||
init = {
|
||||
clientId: clientId,
|
||||
origin: origin
|
||||
@@ -79,10 +79,6 @@
|
||||
|
||||
function receiveMessage(event)
|
||||
{
|
||||
if (typeof event.data !== 'string') {
|
||||
return
|
||||
}
|
||||
|
||||
var origin = event.origin;
|
||||
var data = event.data.split(' ');
|
||||
if (data.length != 2) {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak OIDC Client Adapter Modules</name>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-boot-container-bundle</artifactId>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+3
-5
@@ -132,8 +132,10 @@ public class KeycloakAutoConfiguration {
|
||||
loginConfig.addFirstAuthMethod("KEYCLOAK");
|
||||
|
||||
deploymentInfo.setLoginConfig(loginConfig);
|
||||
|
||||
deploymentInfo.addInitParameter("keycloak.config.resolver", KeycloakSpringBootConfigResolver.class.getName());
|
||||
deploymentInfo.addSecurityConstraints(getSecurityConstraints());
|
||||
|
||||
deploymentInfo.addServletExtension(new KeycloakServletExtension());
|
||||
}
|
||||
|
||||
@@ -155,6 +157,7 @@ public class KeycloakAutoConfiguration {
|
||||
undertowSecurityConstraint.addWebResourceCollections(webResourceCollection);
|
||||
|
||||
}
|
||||
|
||||
undertowSecurityConstraints.add(undertowSecurityConstraint);
|
||||
}
|
||||
return undertowSecurityConstraints;
|
||||
@@ -277,11 +280,6 @@ public class KeycloakAutoConfiguration {
|
||||
|
||||
for (String authRole : constraint.getAuthRoles()) {
|
||||
tomcatConstraint.addAuthRole(authRole);
|
||||
if(authRole.equals("*") || authRole.equals("**")) {
|
||||
// For some reasons embed tomcat don't set the auth constraint on true when wildcard is
|
||||
// used
|
||||
tomcatConstraint.setAuthConstraint(true);
|
||||
}
|
||||
}
|
||||
|
||||
for (KeycloakSpringBootProperties.SecurityCollection collection : constraint.getSecurityCollections()) {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+5
-1
@@ -45,7 +45,11 @@ public class HttpHeaderInspectingApiRequestMatcher implements RequestMatcher {
|
||||
*/
|
||||
@Override
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
return X_REQUESTED_WITH_HEADER_AJAX_VALUE.equals(request.getHeader(X_REQUESTED_WITH_HEADER));
|
||||
boolean ajax = X_REQUESTED_WITH_HEADER_AJAX_VALUE.equals(request.getHeader(X_REQUESTED_WITH_HEADER));
|
||||
boolean html = request.getHeader(HttpHeaders.ACCEPT) != null && request.getHeader(HttpHeaders.ACCEPT).contains(
|
||||
MediaType.TEXT_HTML_VALUE);
|
||||
|
||||
return ajax || !html;
|
||||
}
|
||||
|
||||
}
|
||||
+17
-15
@@ -17,16 +17,7 @@
|
||||
|
||||
package org.keycloak.adapters.springsecurity.authentication;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.adapters.springsecurity.facade.SimpleHttpFacade;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@@ -35,6 +26,17 @@ import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
|
||||
import org.keycloak.adapters.springsecurity.facade.SimpleHttpFacade;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
|
||||
/**
|
||||
* Provides a Keycloak {@link AuthenticationEntryPoint authentication entry point}. Uses a
|
||||
* {@link RequestMatcher} to determine if the request is an interactive login request or a
|
||||
@@ -60,14 +62,15 @@ public class KeycloakAuthenticationEntryPoint implements AuthenticationEntryPoin
|
||||
private final RequestMatcher apiRequestMatcher;
|
||||
private String loginUri = DEFAULT_LOGIN_URI;
|
||||
private String realm = DEFAULT_REALM;
|
||||
|
||||
|
||||
private AdapterDeploymentContext adapterDeploymentContext;
|
||||
|
||||
/**
|
||||
* Creates a new Keycloak authentication entry point.
|
||||
*/
|
||||
public KeycloakAuthenticationEntryPoint(AdapterDeploymentContext adapterDeploymentContext) {
|
||||
this(adapterDeploymentContext, DEFAULT_API_REQUEST_MATCHER);
|
||||
this(DEFAULT_API_REQUEST_MATCHER);
|
||||
this.adapterDeploymentContext = adapterDeploymentContext;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,15 +80,14 @@ public class KeycloakAuthenticationEntryPoint implements AuthenticationEntryPoin
|
||||
* @param apiRequestMatcher the <code>RequestMatcher</code> to use to determine
|
||||
* if the current request is an API request or a browser request (required)
|
||||
*/
|
||||
public KeycloakAuthenticationEntryPoint(AdapterDeploymentContext adapterDeploymentContext, RequestMatcher apiRequestMatcher) {
|
||||
public KeycloakAuthenticationEntryPoint(RequestMatcher apiRequestMatcher) {
|
||||
Assert.notNull(apiRequestMatcher, "apiRequestMatcher required");
|
||||
Assert.notNull(adapterDeploymentContext, "adapterDeploymentContext required");
|
||||
this.adapterDeploymentContext = adapterDeploymentContext;
|
||||
this.apiRequestMatcher = apiRequestMatcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException
|
||||
{
|
||||
HttpFacade facade = new SimpleHttpFacade(request, response);
|
||||
if (apiRequestMatcher.matches(request) || adapterDeploymentContext.resolveDeployment(facade).isBearerOnly()) {
|
||||
commenceUnauthorizedResponse(request, response);
|
||||
|
||||
-15
@@ -23,11 +23,9 @@ import org.keycloak.adapters.springsecurity.AdapterDeploymentContextFactoryBean;
|
||||
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationEntryPoint;
|
||||
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
|
||||
import org.keycloak.adapters.springsecurity.authentication.KeycloakLogoutHandler;
|
||||
import org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter;
|
||||
import org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter;
|
||||
import org.keycloak.adapters.springsecurity.filter.KeycloakCsrfRequestMatcher;
|
||||
import org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter;
|
||||
import org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter;
|
||||
import org.keycloak.adapters.springsecurity.management.HttpSessionManager;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -43,7 +41,6 @@ import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.logout.LogoutFilter;
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
||||
|
||||
/**
|
||||
* Provides a convenient base class for creating a {@link WebSecurityConfigurer}
|
||||
@@ -94,11 +91,6 @@ public abstract class KeycloakWebSecurityConfigurerAdapter extends WebSecurityCo
|
||||
return new KeycloakPreAuthActionsFilter(httpSessionManager());
|
||||
}
|
||||
|
||||
@Bean
|
||||
protected KeycloakAuthenticatedActionsFilter keycloakAuthenticatedActionsFilter() {
|
||||
return new KeycloakAuthenticatedActionsFilter();
|
||||
}
|
||||
|
||||
protected KeycloakCsrfRequestMatcher keycloakCsrfRequestMatcher() {
|
||||
return new KeycloakCsrfRequestMatcher();
|
||||
}
|
||||
@@ -125,8 +117,6 @@ public abstract class KeycloakWebSecurityConfigurerAdapter extends WebSecurityCo
|
||||
.and()
|
||||
.addFilterBefore(keycloakPreAuthActionsFilter(), LogoutFilter.class)
|
||||
.addFilterBefore(keycloakAuthenticationProcessingFilter(), BasicAuthenticationFilter.class)
|
||||
.addFilterBefore(keycloakAuthenticatedActionsFilter(), BasicAuthenticationFilter.class)
|
||||
.addFilterAfter(keycloakSecurityContextRequestFilter(), SecurityContextHolderAwareRequestFilter.class)
|
||||
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())
|
||||
.and()
|
||||
.logout()
|
||||
@@ -134,9 +124,4 @@ public abstract class KeycloakWebSecurityConfigurerAdapter extends WebSecurityCo
|
||||
.logoutUrl("/sso/logout").permitAll()
|
||||
.logoutSuccessUrl("/");
|
||||
}
|
||||
|
||||
@Bean
|
||||
protected KeycloakSecurityContextRequestFilter keycloakSecurityContextRequestFilter() {
|
||||
return new KeycloakSecurityContextRequestFilter();
|
||||
}
|
||||
}
|
||||
-113
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.adapters.springsecurity.filter;
|
||||
|
||||
import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||
import org.keycloak.adapters.springsecurity.facade.SimpleHttpFacade;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.filter.GenericFilterBean;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class KeycloakSecurityContextRequestFilter extends GenericFilterBean implements ApplicationContextAware {
|
||||
|
||||
private static final String FILTER_APPLIED = KeycloakSecurityContext.class.getPackage().getName() + ".token-refreshed";
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
private AdapterDeploymentContext deploymentContext;
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
|
||||
if (request.getAttribute(FILTER_APPLIED) != null) {
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
|
||||
|
||||
KeycloakSecurityContext keycloakSecurityContext = getKeycloakPrincipal();
|
||||
|
||||
if (keycloakSecurityContext instanceof RefreshableKeycloakSecurityContext) {
|
||||
RefreshableKeycloakSecurityContext refreshableSecurityContext = (RefreshableKeycloakSecurityContext) keycloakSecurityContext;
|
||||
|
||||
if (refreshableSecurityContext.isActive()) {
|
||||
KeycloakDeployment deployment = resolveDeployment(request, response);
|
||||
|
||||
if (deployment.isAlwaysRefreshToken()) {
|
||||
if (refreshableSecurityContext.refreshExpiredToken(false)) {
|
||||
request.setAttribute(KeycloakSecurityContext.class.getName(), refreshableSecurityContext);
|
||||
} else {
|
||||
clearAuthenticationContext();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
clearAuthenticationContext();
|
||||
}
|
||||
}
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initFilterBean() throws ServletException {
|
||||
deploymentContext = applicationContext.getBean(AdapterDeploymentContext.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
private KeycloakSecurityContext getKeycloakPrincipal() {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
if (authentication != null) {
|
||||
Object principal = authentication.getPrincipal();
|
||||
|
||||
if (principal instanceof KeycloakPrincipal) {
|
||||
return KeycloakPrincipal.class.cast(principal).getKeycloakSecurityContext();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private KeycloakDeployment resolveDeployment(ServletRequest servletRequest, ServletResponse servletResponse) {
|
||||
return deploymentContext.resolveDeployment(new SimpleHttpFacade(HttpServletRequest.class.cast(servletRequest), HttpServletResponse.class.cast(servletResponse)));
|
||||
}
|
||||
|
||||
private void clearAuthenticationContext() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
}
|
||||
+7
-2
@@ -39,9 +39,14 @@ public class HttpHeaderInspectingApiRequestMatcherTest {
|
||||
request = new MockHttpServletRequest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatches() throws Exception {
|
||||
assertTrue(apiRequestMatcher.matches(request));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchesBrowserRequest() throws Exception {
|
||||
request.addHeader(HttpHeaders.ACCEPT, "application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
|
||||
request.addHeader(HttpHeaders.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
|
||||
assertFalse(apiRequestMatcher.matches(request));
|
||||
}
|
||||
|
||||
@@ -50,7 +55,7 @@ public class HttpHeaderInspectingApiRequestMatcherTest {
|
||||
request.addHeader(
|
||||
HttpHeaderInspectingApiRequestMatcher.X_REQUESTED_WITH_HEADER,
|
||||
HttpHeaderInspectingApiRequestMatcher.X_REQUESTED_WITH_HEADER_AJAX_VALUE);
|
||||
|
||||
assertTrue(apiRequestMatcher.matches(request));
|
||||
}
|
||||
|
||||
}
|
||||
+16
-30
@@ -17,27 +17,24 @@
|
||||
|
||||
package org.keycloak.adapters.springsecurity.authentication;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||
import org.keycloak.adapters.KeycloakDeployment;
|
||||
import org.keycloak.adapters.spi.HttpFacade;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import org.mockito.Mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* Keycloak authentication entry point tests.
|
||||
@@ -49,16 +46,13 @@ public class KeycloakAuthenticationEntryPointTest {
|
||||
private MockHttpServletResponse response;
|
||||
@Mock
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
|
||||
@Mock
|
||||
private AdapterDeploymentContext adapterDeploymentContext;
|
||||
|
||||
|
||||
@Mock
|
||||
private KeycloakDeployment keycloakDeployment;
|
||||
|
||||
@Mock
|
||||
private RequestMatcher requestMatcher;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
@@ -92,8 +86,8 @@ public class KeycloakAuthenticationEntryPointTest {
|
||||
public void testCommenceWithUnauthorizedWithAccept() throws Exception {
|
||||
request.addHeader(HttpHeaders.ACCEPT, "application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
|
||||
authenticationEntryPoint.commence(request, response, null);
|
||||
assertEquals(HttpStatus.FOUND.value(), response.getStatus());
|
||||
assertNull(response.getHeader(HttpHeaders.WWW_AUTHENTICATE));
|
||||
assertEquals(HttpStatus.UNAUTHORIZED.value(), response.getStatus());
|
||||
assertNotNull(response.getHeader(HttpHeaders.WWW_AUTHENTICATE));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -106,14 +100,6 @@ public class KeycloakAuthenticationEntryPointTest {
|
||||
assertEquals(logoutUri, response.getHeader("Location"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommenceWithCustomRequestMatcher() throws Exception {
|
||||
new KeycloakAuthenticationEntryPoint(adapterDeploymentContext, requestMatcher)
|
||||
.commence(request, response, null);
|
||||
|
||||
verify(requestMatcher).matches(request);
|
||||
}
|
||||
|
||||
private void configureBrowserRequest() {
|
||||
request.addHeader(HttpHeaders.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak Tomcat Integration</name>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-tomcat-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-tomcat-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-tomcat-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-tomcat-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -40,7 +40,7 @@
|
||||
<dependency>
|
||||
<groupId>org.wildfly.common</groupId>
|
||||
<artifactId>wildfly-common</artifactId>
|
||||
<scope>provided</scope>
|
||||
<version>1.2.0.Beta1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.wildfly.security</groupId>
|
||||
|
||||
+1
-4
@@ -30,10 +30,8 @@ import org.keycloak.KeycloakPrincipal;
|
||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||
import org.wildfly.security.auth.callback.AuthenticationCompleteCallback;
|
||||
import org.wildfly.security.auth.callback.EvidenceVerifyCallback;
|
||||
import org.wildfly.security.auth.callback.IdentityCredentialCallback;
|
||||
import org.wildfly.security.auth.callback.SecurityIdentityCallback;
|
||||
import org.wildfly.security.auth.server.SecurityIdentity;
|
||||
import org.wildfly.security.credential.BearerTokenCredential;
|
||||
import org.wildfly.security.evidence.Evidence;
|
||||
import org.wildfly.security.http.HttpAuthenticationException;
|
||||
|
||||
@@ -65,9 +63,8 @@ final class SecurityIdentityUtil {
|
||||
}
|
||||
|
||||
SecurityIdentityCallback securityIdentityCallback = new SecurityIdentityCallback();
|
||||
IdentityCredentialCallback credentialCallback = new IdentityCredentialCallback(new BearerTokenCredential(KeycloakPrincipal.class.cast(principal).getKeycloakSecurityContext().getTokenString()), true);
|
||||
|
||||
callbackHandler.handle(new Callback[]{credentialCallback, AuthenticationCompleteCallback.SUCCEEDED, securityIdentityCallback});
|
||||
callbackHandler.handle(new Callback[]{AuthenticationCompleteCallback.SUCCEEDED, securityIdentityCallback});
|
||||
|
||||
SecurityIdentity securityIdentity = securityIdentityCallback.getSecurityIdentity();
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak WildFly Integration</name>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
+5
-7
@@ -276,13 +276,11 @@ public final class KeycloakAdapterConfigService {
|
||||
}
|
||||
|
||||
private void setJSONValues(ModelNode json, ModelNode values) {
|
||||
synchronized (values) {
|
||||
for (Property prop : new ArrayList<>(values.asPropertyList())) {
|
||||
String name = prop.getName();
|
||||
ModelNode value = prop.getValue();
|
||||
if (value.isDefined()) {
|
||||
json.get(name).set(value);
|
||||
}
|
||||
for (Property prop : new ArrayList<>(values.asPropertyList())) {
|
||||
String name = prop.getName();
|
||||
ModelNode value = prop.getValue();
|
||||
if (value.isDefined()) {
|
||||
json.get(name).set(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-7
@@ -186,12 +186,7 @@ public class SharedAttributeDefinitons {
|
||||
.setDefaultValue(new ModelNode(false))
|
||||
.build();
|
||||
|
||||
protected static final SimpleAttributeDefinition CONFIDENTIAL_PORT =
|
||||
new SimpleAttributeDefinitionBuilder("confidential-port", ModelType.INT, true)
|
||||
.setXmlName("confidential-port")
|
||||
.setAllowExpression(true)
|
||||
.setDefaultValue(new ModelNode(8443))
|
||||
.build();
|
||||
|
||||
|
||||
|
||||
protected static final List<SimpleAttributeDefinition> ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||
@@ -201,7 +196,6 @@ public class SharedAttributeDefinitons {
|
||||
ATTRIBUTES.add(TRUSTSTORE);
|
||||
ATTRIBUTES.add(TRUSTSTORE_PASSWORD);
|
||||
ATTRIBUTES.add(SSL_REQUIRED);
|
||||
ATTRIBUTES.add(CONFIDENTIAL_PORT);
|
||||
ATTRIBUTES.add(ALLOW_ANY_HOSTNAME);
|
||||
ATTRIBUTES.add(DISABLE_TRUST_MANAGER);
|
||||
ATTRIBUTES.add(CONNECTION_POOL_SIZE);
|
||||
|
||||
-3
@@ -30,7 +30,6 @@ keycloak.realm.realm-public-key=Public key of the realm
|
||||
keycloak.realm.auth-server-url=Base URL of the Realm Auth Server
|
||||
keycloak.realm.disable-trust-manager=Adapter will not use a trust manager when making adapter HTTPS requests
|
||||
keycloak.realm.ssl-required=Specify if SSL is required (valid values are all, external and none)
|
||||
keycloak.realm.confidential-port=Specify the confidential port (SSL/TLS) used by the Realm Auth Server
|
||||
keycloak.realm.allow-any-hostname=SSL Setting
|
||||
keycloak.realm.truststore=Truststore used for adapter client HTTPS requests
|
||||
keycloak.realm.truststore-password=Password of the Truststore
|
||||
@@ -61,7 +60,6 @@ keycloak.secure-deployment.realm-public-key=Public key of the realm
|
||||
keycloak.secure-deployment.auth-server-url=Base URL of the Realm Auth Server
|
||||
keycloak.secure-deployment.disable-trust-manager=Adapter will not use a trust manager when making adapter HTTPS requests
|
||||
keycloak.secure-deployment.ssl-required=Specify if SSL is required (valid values are all, external and none)
|
||||
keycloak.secure-deployment.confidential-port=Specify the confidential port (SSL/TLS) used by the Realm Auth Server
|
||||
keycloak.secure-deployment.allow-any-hostname=SSL Setting
|
||||
keycloak.secure-deployment.truststore=Truststore used for adapter client HTTPS requests
|
||||
keycloak.secure-deployment.truststore-password=Password of the Truststore
|
||||
@@ -102,7 +100,6 @@ keycloak.secure-server.realm-public-key=Public key of the realm
|
||||
keycloak.secure-server.auth-server-url=Base URL of the Realm Auth Server
|
||||
keycloak.secure-server.disable-trust-manager=Adapter will not use a trust manager when making adapter HTTPS requests
|
||||
keycloak.secure-server.ssl-required=Specify if SSL is required (valid values are all, external and none)
|
||||
keycloak.secure-server.confidential-port=Specify the confidential port (SSL/TLS) used by the Realm Auth Server
|
||||
keycloak.secure-server.allow-any-hostname=SSL Setting
|
||||
keycloak.secure-server.truststore=Truststore used for adapter client HTTPS requests
|
||||
keycloak.secure-server.truststore-password=Password of the Truststore
|
||||
|
||||
-2
@@ -58,7 +58,6 @@
|
||||
<xs:element name="expose-token" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="disable-trust-manager" type="xs:boolean" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="ssl-required" type="xs:string" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="confidential-port" type="xs:integer" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="cors-allowed-methods" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="cors-exposed-headers" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="realm-public-key" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
@@ -101,7 +100,6 @@
|
||||
<xs:element name="connection-pool-size" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="expose-token" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="ssl-required" type="xs:string" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="confidential-port" type="xs:integer" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="realm-public-key" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="credential" type="credential-type" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="redirect-rewrite-rule" type="redirect-rewrite-rule-type" minOccurs="0" maxOccurs="1"/>
|
||||
|
||||
-1
@@ -51,7 +51,6 @@ public class SubsystemParsingTestCase extends AbstractSubsystemBaseTest {
|
||||
node.get("auth-url").set("http://localhost:8080/auth-server/rest/realms/demo/protocol/openid-connect/login");
|
||||
node.get("code-url").set("http://localhost:8080/auth-server/rest/realms/demo/protocol/openid-connect/access/codes");
|
||||
node.get("ssl-required").set("external");
|
||||
node.get("confidential-port").set(443);
|
||||
node.get("expose-token").set(true);
|
||||
|
||||
ModelNode jwtCredential = new ModelNode();
|
||||
|
||||
-4
@@ -22,7 +22,6 @@
|
||||
<truststore>truststore.jks</truststore>
|
||||
<truststore-password>secret</truststore-password>
|
||||
<ssl-required>EXTERNAL</ssl-required>
|
||||
<confidential-port>443</confidential-port>
|
||||
<allow-any-hostname>false</allow-any-hostname>
|
||||
<disable-trust-manager>true</disable-trust-manager>
|
||||
<connection-pool-size>20</connection-pool-size>
|
||||
@@ -57,7 +56,6 @@
|
||||
</realm-public-key>
|
||||
<auth-server-url>http://localhost:8080/auth</auth-server-url>
|
||||
<ssl-required>EXTERNAL</ssl-required>
|
||||
<confidential-port>443</confidential-port>
|
||||
<credential name="secret">0aa31d98-e0aa-404c-b6e0-e771dba1e798</credential>
|
||||
<redirect-rewrite-rule name="^/wsmaster/api/(.*)$">api/$1/</redirect-rewrite-rule>
|
||||
</secure-deployment>
|
||||
@@ -86,7 +84,5 @@
|
||||
<realm>jboss-infra</realm>
|
||||
<resource>wildfly-console</resource>
|
||||
<public-client>true</public-client>
|
||||
<ssl-required>EXTERNAL</ssl-required>
|
||||
<confidential-port>443</confidential-port>
|
||||
</secure-server>
|
||||
</subsystem>
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak Adapters</name>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-saml-eap-integration-pom</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Keycloak SAML EAP Integration</name>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-saml-eap-integration-pom</artifactId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
+2
-3
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package org.keycloak.subsystem.saml.as7;
|
||||
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
|
||||
*/
|
||||
@@ -45,8 +46,6 @@ public class Constants {
|
||||
static final String SIGN_REQUEST = "signRequest";
|
||||
static final String VALIDATE_RESPONSE_SIGNATURE = "validateResponseSignature";
|
||||
static final String VALIDATE_ASSERTION_SIGNATURE = "validateAssertionSignature";
|
||||
static final String ASSERTION_CONSUMER_SERVICE_URL = "assertionConsumerServiceUrl";
|
||||
|
||||
static final String REQUEST_BINDING = "requestBinding";
|
||||
static final String BINDING_URL = "bindingUrl";
|
||||
static final String VALIDATE_REQUEST_SIGNATURE = "validateRequestSignature";
|
||||
@@ -70,6 +69,7 @@ public class Constants {
|
||||
static final String SIGNATURES_REQUIRED = "signaturesRequired";
|
||||
}
|
||||
|
||||
|
||||
static class XML {
|
||||
static final String SECURE_DEPLOYMENT = "secure-deployment";
|
||||
static final String SERVICE_PROVIDER = "SP";
|
||||
@@ -122,6 +122,5 @@ public class Constants {
|
||||
static final String ALIAS = "alias";
|
||||
static final String FILE = "file";
|
||||
static final String SIGNATURES_REQUIRED = "signaturesRequired";
|
||||
static final String ASSERTION_CONSUMER_SERVICE_URL = "assertionConsumerServiceUrl";
|
||||
}
|
||||
}
|
||||
+1
-6
@@ -56,13 +56,8 @@ abstract class SingleSignOnDefinition {
|
||||
new SimpleAttributeDefinitionBuilder(Constants.Model.BINDING_URL, ModelType.STRING, true)
|
||||
.setXmlName(Constants.XML.BINDING_URL)
|
||||
.build();
|
||||
|
||||
static final SimpleAttributeDefinition ASSERTION_CONSUMER_SERVICE_URL =
|
||||
new SimpleAttributeDefinitionBuilder(Constants.Model.ASSERTION_CONSUMER_SERVICE_URL, ModelType.STRING, true)
|
||||
.setXmlName(Constants.XML.ASSERTION_CONSUMER_SERVICE_URL)
|
||||
.build();
|
||||
|
||||
static final SimpleAttributeDefinition[] ATTRIBUTES = {SIGN_REQUEST, VALIDATE_RESPONSE_SIGNATURE, VALIDATE_ASSERTION_SIGNATURE, REQUEST_BINDING, RESPONSE_BINDING, BINDING_URL, ASSERTION_CONSUMER_SERVICE_URL};
|
||||
static final SimpleAttributeDefinition[] ATTRIBUTES = {SIGN_REQUEST, VALIDATE_RESPONSE_SIGNATURE, VALIDATE_ASSERTION_SIGNATURE, REQUEST_BINDING, RESPONSE_BINDING, BINDING_URL};
|
||||
|
||||
static final HashMap<String, SimpleAttributeDefinition> ATTRIBUTE_MAP = new HashMap<>();
|
||||
|
||||
|
||||
-1
@@ -71,7 +71,6 @@ keycloak-saml.IDP.SingleSignOnService.validateAssertionSignature=Validate an SSO
|
||||
keycloak-saml.IDP.SingleSignOnService.requestBinding=HTTP method to use for requests
|
||||
keycloak-saml.IDP.SingleSignOnService.responseBinding=HTTP method to use for responses
|
||||
keycloak-saml.IDP.SingleSignOnService.bindingUrl=SSO endpoint URL
|
||||
keycloak-saml.IDP.SingleSignOnService.assertionConsumerServiceUrl=Endpoint of Assertion Consumer Service at SP
|
||||
keycloak-saml.IDP.SingleLogoutService=Single logout configuration
|
||||
keycloak-saml.IDP.SingleLogoutService.validateRequestSignature=Validate a SingleLogoutService request signature
|
||||
keycloak-saml.IDP.SingleLogoutService.validateResponseSignature=Validate a SingleLogoutService response signature
|
||||
|
||||
-5
@@ -152,11 +152,6 @@
|
||||
<xs:documentation>SSO endpoint URL</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="assertionConsumerServiceUrl" type="xs:string" use="optional">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Endpoint of Assertion Consumer Service at SP</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="single-logout-type">
|
||||
<xs:attribute name="validateRequestSignature" type="xs:boolean" use="optional">
|
||||
|
||||
+1
-2
@@ -44,8 +44,7 @@
|
||||
validateResponseSignature="true"
|
||||
validateAssertionSignature="true"
|
||||
requestBinding="POST"
|
||||
bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"
|
||||
assertionConsumerServiceUrl="acsUrl"/>
|
||||
bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
|
||||
<SingleLogoutService
|
||||
validateRequestSignature="true"
|
||||
validateResponseSignature="true"
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>4.0.0.Beta1</version>
|
||||
<version>3.4.0.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -71,11 +71,6 @@
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-all</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
|
||||
@@ -56,8 +56,6 @@ import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.apache.http.client.params.ClientPNames;
|
||||
import org.apache.http.client.params.CookiePolicy;
|
||||
|
||||
/**
|
||||
* Abstraction for creating HttpClients. Allows SSL configuration.
|
||||
@@ -290,7 +288,6 @@ public class HttpClientBuilder {
|
||||
cm = new SingleClientConnManager(registry);
|
||||
}
|
||||
BasicHttpParams params = new BasicHttpParams();
|
||||
params.setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);
|
||||
|
||||
if (proxyHost != null) {
|
||||
params.setParameter(ConnRoutePNames.DEFAULT_PROXY, proxyHost);
|
||||
|
||||
@@ -27,36 +27,35 @@ import org.keycloak.adapters.cloned.AdapterHttpClientConfig;
|
||||
*/
|
||||
public class IDP implements Serializable {
|
||||
public static class SingleSignOnService implements Serializable {
|
||||
private Boolean signRequest;
|
||||
private Boolean validateResponseSignature;
|
||||
private boolean signRequest;
|
||||
private boolean validateResponseSignature;
|
||||
private String requestBinding;
|
||||
private String responseBinding;
|
||||
private String bindingUrl;
|
||||
private String assertionConsumerServiceUrl;
|
||||
private Boolean validateAssertionSignature;
|
||||
private boolean signaturesRequired = false;
|
||||
private boolean validateAssertionSignature;
|
||||
|
||||
public boolean isSignRequest() {
|
||||
return signRequest == null ? signaturesRequired : signRequest;
|
||||
return signRequest;
|
||||
}
|
||||
|
||||
public void setSignRequest(Boolean signRequest) {
|
||||
public void setSignRequest(boolean signRequest) {
|
||||
this.signRequest = signRequest;
|
||||
}
|
||||
|
||||
public boolean isValidateResponseSignature() {
|
||||
return validateResponseSignature == null ? signaturesRequired : validateResponseSignature;
|
||||
return validateResponseSignature;
|
||||
}
|
||||
|
||||
public void setValidateResponseSignature(Boolean validateResponseSignature) {
|
||||
public void setValidateResponseSignature(boolean validateResponseSignature) {
|
||||
this.validateResponseSignature = validateResponseSignature;
|
||||
}
|
||||
|
||||
public boolean isValidateAssertionSignature() {
|
||||
return validateAssertionSignature == null ? false : validateAssertionSignature;
|
||||
return validateAssertionSignature;
|
||||
}
|
||||
|
||||
public void setValidateAssertionSignature(Boolean validateAssertionSignature) {
|
||||
public void setValidateAssertionSignature(boolean validateAssertionSignature) {
|
||||
this.validateAssertionSignature = validateAssertionSignature;
|
||||
}
|
||||
|
||||
@@ -91,52 +90,47 @@ public class IDP implements Serializable {
|
||||
public void setAssertionConsumerServiceUrl(String assertionConsumerServiceUrl) {
|
||||
this.assertionConsumerServiceUrl = assertionConsumerServiceUrl;
|
||||
}
|
||||
|
||||
private void setSignaturesRequired(boolean signaturesRequired) {
|
||||
this.signaturesRequired = signaturesRequired;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SingleLogoutService implements Serializable {
|
||||
private Boolean signRequest;
|
||||
private Boolean signResponse;
|
||||
private Boolean validateRequestSignature;
|
||||
private Boolean validateResponseSignature;
|
||||
private boolean signRequest;
|
||||
private boolean signResponse;
|
||||
private boolean validateRequestSignature;
|
||||
private boolean validateResponseSignature;
|
||||
private String requestBinding;
|
||||
private String responseBinding;
|
||||
private String postBindingUrl;
|
||||
private String redirectBindingUrl;
|
||||
private boolean signaturesRequired = false;
|
||||
|
||||
public boolean isSignRequest() {
|
||||
return signRequest == null ? signaturesRequired : signRequest;
|
||||
return signRequest;
|
||||
}
|
||||
|
||||
public void setSignRequest(Boolean signRequest) {
|
||||
public void setSignRequest(boolean signRequest) {
|
||||
this.signRequest = signRequest;
|
||||
}
|
||||
|
||||
public boolean isSignResponse() {
|
||||
return signResponse == null ? signaturesRequired : signResponse;
|
||||
return signResponse;
|
||||
}
|
||||
|
||||
public void setSignResponse(Boolean signResponse) {
|
||||
public void setSignResponse(boolean signResponse) {
|
||||
this.signResponse = signResponse;
|
||||
}
|
||||
|
||||
public boolean isValidateRequestSignature() {
|
||||
return validateRequestSignature == null ? signaturesRequired : validateRequestSignature;
|
||||
return validateRequestSignature;
|
||||
}
|
||||
|
||||
public void setValidateRequestSignature(Boolean validateRequestSignature) {
|
||||
public void setValidateRequestSignature(boolean validateRequestSignature) {
|
||||
this.validateRequestSignature = validateRequestSignature;
|
||||
}
|
||||
|
||||
public boolean isValidateResponseSignature() {
|
||||
return validateResponseSignature == null ? signaturesRequired : validateResponseSignature;
|
||||
return validateResponseSignature;
|
||||
}
|
||||
|
||||
public void setValidateResponseSignature(Boolean validateResponseSignature) {
|
||||
public void setValidateResponseSignature(boolean validateResponseSignature) {
|
||||
this.validateResponseSignature = validateResponseSignature;
|
||||
}
|
||||
|
||||
@@ -171,10 +165,6 @@ public class IDP implements Serializable {
|
||||
public void setRedirectBindingUrl(String redirectBindingUrl) {
|
||||
this.redirectBindingUrl = redirectBindingUrl;
|
||||
}
|
||||
|
||||
private void setSignaturesRequired(boolean signaturesRequired) {
|
||||
this.signaturesRequired = signaturesRequired;
|
||||
}
|
||||
}
|
||||
|
||||
public static class HttpClientConfig implements AdapterHttpClientConfig {
|
||||
@@ -268,7 +258,6 @@ public class IDP implements Serializable {
|
||||
private SingleLogoutService singleLogoutService;
|
||||
private List<Key> keys;
|
||||
private AdapterHttpClientConfig httpClientConfig = new HttpClientConfig();
|
||||
private boolean signaturesRequired = false;
|
||||
|
||||
public String getEntityID() {
|
||||
return entityID;
|
||||
@@ -284,9 +273,6 @@ public class IDP implements Serializable {
|
||||
|
||||
public void setSingleSignOnService(SingleSignOnService singleSignOnService) {
|
||||
this.singleSignOnService = singleSignOnService;
|
||||
if (singleSignOnService != null) {
|
||||
singleSignOnService.setSignaturesRequired(signaturesRequired);
|
||||
}
|
||||
}
|
||||
|
||||
public SingleLogoutService getSingleLogoutService() {
|
||||
@@ -295,9 +281,6 @@ public class IDP implements Serializable {
|
||||
|
||||
public void setSingleLogoutService(SingleLogoutService singleLogoutService) {
|
||||
this.singleLogoutService = singleLogoutService;
|
||||
if (singleLogoutService != null) {
|
||||
singleLogoutService.setSignaturesRequired(signaturesRequired);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Key> getKeys() {
|
||||
@@ -332,12 +315,4 @@ public class IDP implements Serializable {
|
||||
this.httpClientConfig = httpClientConfig;
|
||||
}
|
||||
|
||||
public boolean isSignaturesRequired() {
|
||||
return signaturesRequired;
|
||||
}
|
||||
|
||||
public void setSignaturesRequired(boolean signaturesRequired) {
|
||||
this.signaturesRequired = signaturesRequired;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -114,16 +114,16 @@ public class Key implements Serializable {
|
||||
return signing;
|
||||
}
|
||||
|
||||
public void setSigning(Boolean signing) {
|
||||
this.signing = signing != null && signing;
|
||||
public void setSigning(boolean signing) {
|
||||
this.signing = signing;
|
||||
}
|
||||
|
||||
public boolean isEncryption() {
|
||||
return encryption;
|
||||
}
|
||||
|
||||
public void setEncryption(Boolean encryption) {
|
||||
this.encryption = encryption != null && encryption;
|
||||
public void setEncryption(boolean encryption) {
|
||||
this.encryption = encryption;
|
||||
}
|
||||
|
||||
public KeyStoreConfig getKeystore() {
|
||||
|
||||
+3
-4
@@ -26,14 +26,13 @@ import java.util.List;
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class KeycloakSamlAdapter implements Serializable {
|
||||
private final List<SP> sps = new LinkedList<>();
|
||||
private List<SP> sps = new LinkedList<>();
|
||||
|
||||
public List<SP> getSps() {
|
||||
return sps;
|
||||
}
|
||||
|
||||
public void addSp(SP sp) {
|
||||
sps.add(sp);
|
||||
public void setSps(List<SP> sps) {
|
||||
this.sps = sps;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -80,24 +80,24 @@ public class SP implements Serializable {
|
||||
return forceAuthentication;
|
||||
}
|
||||
|
||||
public void setForceAuthentication(Boolean forceAuthentication) {
|
||||
this.forceAuthentication = forceAuthentication != null && forceAuthentication;
|
||||
public void setForceAuthentication(boolean forceAuthentication) {
|
||||
this.forceAuthentication = forceAuthentication;
|
||||
}
|
||||
|
||||
public boolean isIsPassive() {
|
||||
return isPassive;
|
||||
}
|
||||
|
||||
public void setIsPassive(Boolean isPassive) {
|
||||
this.isPassive = isPassive != null && isPassive;
|
||||
public void setIsPassive(boolean isPassive) {
|
||||
this.isPassive = isPassive;
|
||||
}
|
||||
|
||||
public boolean isTurnOffChangeSessionIdOnLogin() {
|
||||
return turnOffChangeSessionIdOnLogin;
|
||||
}
|
||||
|
||||
public void setTurnOffChangeSessionIdOnLogin(Boolean turnOffChangeSessionIdOnLogin) {
|
||||
this.turnOffChangeSessionIdOnLogin = turnOffChangeSessionIdOnLogin != null && turnOffChangeSessionIdOnLogin;
|
||||
public void setTurnOffChangeSessionIdOnLogin(boolean turnOffChangeSessionIdOnLogin) {
|
||||
this.turnOffChangeSessionIdOnLogin = turnOffChangeSessionIdOnLogin;
|
||||
}
|
||||
|
||||
public List<Key> getKeys() {
|
||||
@@ -152,7 +152,7 @@ public class SP implements Serializable {
|
||||
return autodetectBearerOnly;
|
||||
}
|
||||
|
||||
public void setAutodetectBearerOnly(Boolean autodetectBearerOnly) {
|
||||
this.autodetectBearerOnly = autodetectBearerOnly != null && autodetectBearerOnly;
|
||||
public void setAutodetectBearerOnly(boolean autodetectBearerOnly) {
|
||||
this.autodetectBearerOnly = autodetectBearerOnly;
|
||||
}
|
||||
}
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.adapters.saml.config.parsers;
|
||||
|
||||
import org.keycloak.saml.common.parsers.AbstractStaxParser;
|
||||
|
||||
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||
import org.keycloak.saml.processing.core.parsers.util.QNameEnumLookup;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.events.StartElement;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractKeycloakSamlAdapterV1Parser<T> extends AbstractStaxParser<T, KeycloakSamlAdapterV1QNames> {
|
||||
|
||||
protected static final QNameEnumLookup<KeycloakSamlAdapterV1QNames> LOOKUP = new QNameEnumLookup(KeycloakSamlAdapterV1QNames.values());
|
||||
|
||||
private static final Set<String> ALTERNATE_NAMESPACES = Collections.singleton(XMLConstants.NULL_NS_URI);
|
||||
|
||||
public AbstractKeycloakSamlAdapterV1Parser(KeycloakSamlAdapterV1QNames expectedStartElement) {
|
||||
super(expectedStartElement.getQName(), KeycloakSamlAdapterV1QNames.UNKNOWN_ELEMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected KeycloakSamlAdapterV1QNames getElementFromName(QName name) {
|
||||
return (ALTERNATE_NAMESPACES.contains(name.getNamespaceURI()))
|
||||
? LOOKUP.from(new QName(KeycloakSamlAdapterV1QNames.NS_URI, name.getLocalPart()))
|
||||
: LOOKUP.from(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateStartElement(StartElement startElement) {
|
||||
QName name = startElement.getName();
|
||||
QName validatedQName = ALTERNATE_NAMESPACES.contains(name.getNamespaceURI())
|
||||
? new QName(name.getNamespaceURI(), expectedStartElement.getLocalPart())
|
||||
: expectedStartElement;
|
||||
StaxParserUtil.validate(startElement, validatedQName);
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.adapters.saml.config.parsers;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class ConfigXmlConstants {
|
||||
public static final String KEYCLOAK_SAML_ADAPTER = "keycloak-saml-adapter";
|
||||
public static final String SP_ELEMENT = "SP";
|
||||
public static final String ENTITY_ID_ATTR = "entityID";
|
||||
public static final String SSL_POLICY_ATTR = "sslPolicy";
|
||||
public static final String NAME_ID_POLICY_FORMAT_ATTR = "nameIDPolicyFormat";
|
||||
public static final String FORCE_AUTHENTICATION_ATTR = "forceAuthentication";
|
||||
public static final String IS_PASSIVE_ATTR = "isPassive";
|
||||
public static final String TURN_OFF_CHANGE_SESSSION_ID_ON_LOGIN_ATTR = "turnOffChangeSessionIdOnLogin";
|
||||
public static final String SIGNATURE_ALGORITHM_ATTR = "signatureAlgorithm";
|
||||
public static final String SIGNATURE_CANONICALIZATION_METHOD_ATTR = "signatureCanonicalizationMethod";
|
||||
public static final String LOGOUT_PAGE_ATTR = "logoutPage";
|
||||
public static final String AUTODETECT_BEARER_ONLY_ATTR = "autodetectBearerOnly";
|
||||
|
||||
public static final String KEYS_ELEMENT = "Keys";
|
||||
public static final String KEY_ELEMENT = "Key";
|
||||
public static final String SIGNING_ATTR = "signing";
|
||||
public static final String ENCRYPTION_ATTR = "encryption";
|
||||
public static final String CERTIFICATE_PEM_ELEMENT = "CertificatePem";
|
||||
public static final String PRIVATE_KEY_PEM_ELEMENT = "PrivateKeyPem";
|
||||
public static final String PUBLIC_KEY_PEM_ELEMENT = "PublicKeyPem";
|
||||
public static final String FILE_ATTR = "file";
|
||||
public static final String TYPE_ATTR = "type";
|
||||
public static final String RESOURCE_ATTR = "resource";
|
||||
public static final String PASSWORD_ATTR = "password";
|
||||
public static final String ALIAS_ATTR = "alias";
|
||||
public static final String KEYS_STORE_ELEMENT = "KeyStore";
|
||||
public static final String CERTIFICATE_ELEMENT = "Certificate";
|
||||
public static final String PRIVATE_KEY_ELEMENT = "PrivateKey";
|
||||
|
||||
public static final String PRINCIPAL_NAME_MAPPING_ELEMENT = "PrincipalNameMapping";
|
||||
public static final String POLICY_ATTR = "policy";
|
||||
public static final String ATTRIBUTE_ATTR = "attribute";
|
||||
|
||||
public static final String ROLE_IDENTIFIERS_ELEMENT = "RoleIdentifiers";
|
||||
public static final String ATTRIBUTE_ELEMENT = "Attribute";
|
||||
public static final String NAME_ATTR = "name";
|
||||
|
||||
public static final String IDP_ELEMENT = "IDP";
|
||||
public static final String SIGNATURES_REQUIRED_ATTR = "signaturesRequired";
|
||||
public static final String SINGLE_SIGN_ON_SERVICE_ELEMENT = "SingleSignOnService";
|
||||
public static final String SINGLE_LOGOUT_SERVICE_ELEMENT = "SingleLogoutService";
|
||||
public static final String SIGN_REQUEST_ATTR = "signRequest";
|
||||
public static final String SIGN_RESPONSE_ATTR = "signResponse";
|
||||
public static final String REQUEST_BINDING_ATTR = "requestBinding";
|
||||
public static final String RESPONSE_BINDING_ATTR = "responseBinding";
|
||||
public static final String BINDING_URL_ATTR = "bindingUrl";
|
||||
public static final String VALIDATE_RESPONSE_SIGNATURE_ATTR = "validateResponseSignature";
|
||||
public static final String VALIDATE_ASSERTION_SIGNATURE_ATTR = "validateAssertionSignature";
|
||||
public static final String VALIDATE_REQUEST_SIGNATURE_ATTR = "validateRequestSignature";
|
||||
public static final String POST_BINDING_URL_ATTR = "postBindingUrl";
|
||||
public static final String REDIRECT_BINDING_URL_ATTR = "redirectBindingUrl";
|
||||
public static final String ASSERTION_CONSUMER_SERVICE_URL_ATTR = "assertionConsumerServiceUrl";
|
||||
|
||||
public static final String HTTP_CLIENT_ELEMENT = "HttpClient";
|
||||
public static final String ALLOW_ANY_HOSTNAME_ATTR = "allowAnyHostname";
|
||||
public static final String CLIENT_KEYSTORE_ATTR = "clientKeystore";
|
||||
public static final String CLIENT_KEYSTORE_PASSWORD_ATTR = "clientKeystorePassword";
|
||||
public static final String CONNECTION_POOL_SIZE_ATTR = "connectionPoolSize";
|
||||
public static final String DISABLE_TRUST_MANAGER_ATTR = "disableTrustManager";
|
||||
public static final String PROXY_URL_ATTR = "proxyUrl";
|
||||
public static final String TRUSTSTORE_ATTR = "truststore";
|
||||
public static final String TRUSTSTORE_PASSWORD_ATTR = "truststorePassword";
|
||||
|
||||
}
|
||||
+1
-1
@@ -59,7 +59,7 @@ public class DeploymentBuilder {
|
||||
idp.setSingleSignOnService(sso);
|
||||
idp.setSingleLogoutService(slo);
|
||||
|
||||
KeycloakSamlAdapter adapter = (KeycloakSamlAdapter) KeycloakSamlAdapterParser.getInstance().parse(xml);
|
||||
KeycloakSamlAdapter adapter = (KeycloakSamlAdapter)(new KeycloakSamlAdapterXMLParser().parse(xml));
|
||||
SP sp = adapter.getSps().get(0);
|
||||
deployment.setConfigured(true);
|
||||
deployment.setEntityID(sp.getEntityID());
|
||||
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.adapters.saml.config.parsers;
|
||||
|
||||
import org.keycloak.adapters.saml.config.IDP.HttpClientConfig;
|
||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.events.StartElement;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class HttpClientParser extends AbstractKeycloakSamlAdapterV1Parser<HttpClientConfig> {
|
||||
|
||||
private static final HttpClientParser INSTANCE = new HttpClientParser();
|
||||
|
||||
private HttpClientParser() {
|
||||
super(KeycloakSamlAdapterV1QNames.HTTP_CLIENT);
|
||||
}
|
||||
|
||||
public static HttpClientParser getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpClientConfig instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
|
||||
final HttpClientConfig config = new HttpClientConfig();
|
||||
|
||||
final Boolean allowAnyHostname = StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ALLOW_ANY_HOSTNAME);
|
||||
config.setAllowAnyHostname(allowAnyHostname == null ? false : allowAnyHostname);
|
||||
config.setClientKeystore(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_CLIENT_KEYSTORE));
|
||||
config.setClientKeystorePassword(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_CLIENT_KEYSTORE_PASSWORD));
|
||||
final Integer connPoolSize = StaxParserUtil.getIntegerAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_CONNECTION_POOL_SIZE);
|
||||
config.setConnectionPoolSize(connPoolSize == null ? 0 : connPoolSize);
|
||||
final Boolean disableTrustManager = StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_DISABLE_TRUST_MANAGER);
|
||||
config.setDisableTrustManager(disableTrustManager == null ? false : disableTrustManager);
|
||||
config.setProxyUrl(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_PROXY_URL));
|
||||
config.setTruststore(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_TRUSTSTORE));
|
||||
config.setTruststorePassword(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_TRUSTSTORE_PASSWORD));
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processSubElement(XMLEventReader xmlEventReader, HttpClientConfig target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
|
||||
}
|
||||
}
|
||||
Executable
+163
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.adapters.saml.config.parsers;
|
||||
|
||||
import org.keycloak.adapters.saml.config.IDP;
|
||||
import org.keycloak.adapters.saml.config.Key;
|
||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||
import org.keycloak.saml.common.parsers.AbstractParser;
|
||||
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.events.EndElement;
|
||||
import javax.xml.stream.events.StartElement;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
import java.util.List;
|
||||
import org.keycloak.adapters.saml.config.IDP.HttpClientConfig;
|
||||
import static org.keycloak.adapters.saml.config.parsers.SPXmlParser.getAttributeValue;
|
||||
import static org.keycloak.adapters.saml.config.parsers.SPXmlParser.getBooleanAttributeValue;
|
||||
import static org.keycloak.adapters.saml.config.parsers.SPXmlParser.getIntegerAttributeValue;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class IDPXmlParser extends AbstractParser {
|
||||
|
||||
@Override
|
||||
public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
|
||||
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
StaxParserUtil.validate(startElement, ConfigXmlConstants.IDP_ELEMENT);
|
||||
IDP idp = new IDP();
|
||||
String entityID = getAttributeValue(startElement, ConfigXmlConstants.ENTITY_ID_ATTR);
|
||||
if (entityID == null) {
|
||||
throw new ParsingException("entityID must be set on IDP");
|
||||
|
||||
}
|
||||
idp.setEntityID(entityID);
|
||||
|
||||
boolean signaturesRequired = getBooleanAttributeValue(startElement, ConfigXmlConstants.SIGNATURES_REQUIRED_ATTR);
|
||||
idp.setSignatureCanonicalizationMethod(getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_CANONICALIZATION_METHOD_ATTR));
|
||||
idp.setSignatureAlgorithm(getAttributeValue(startElement, ConfigXmlConstants.SIGNATURE_ALGORITHM_ATTR));
|
||||
while (xmlEventReader.hasNext()) {
|
||||
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
|
||||
if (xmlEvent == null)
|
||||
break;
|
||||
if (xmlEvent instanceof EndElement) {
|
||||
EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
|
||||
String endElementName = StaxParserUtil.getEndElementName(endElement);
|
||||
if (endElementName.equals(ConfigXmlConstants.IDP_ELEMENT))
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
|
||||
if (startElement == null)
|
||||
break;
|
||||
String tag = StaxParserUtil.getStartElementName(startElement);
|
||||
if (tag.equals(ConfigXmlConstants.SINGLE_SIGN_ON_SERVICE_ELEMENT)) {
|
||||
IDP.SingleSignOnService sso = parseSingleSignOnService(xmlEventReader, signaturesRequired);
|
||||
idp.setSingleSignOnService(sso);
|
||||
|
||||
} else if (tag.equals(ConfigXmlConstants.SINGLE_LOGOUT_SERVICE_ELEMENT)) {
|
||||
IDP.SingleLogoutService slo = parseSingleLogoutService(xmlEventReader, signaturesRequired);
|
||||
idp.setSingleLogoutService(slo);
|
||||
|
||||
} else if (tag.equals(ConfigXmlConstants.HTTP_CLIENT_ELEMENT)) {
|
||||
HttpClientConfig config = parseHttpClientElement(xmlEventReader);
|
||||
idp.setHttpClientConfig(config);
|
||||
|
||||
} else if (tag.equals(ConfigXmlConstants.KEYS_ELEMENT)) {
|
||||
KeysXmlParser parser = new KeysXmlParser();
|
||||
List<Key> keys = (List<Key>)parser.parse(xmlEventReader);
|
||||
idp.setKeys(keys);
|
||||
} else {
|
||||
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
|
||||
}
|
||||
|
||||
}
|
||||
return idp;
|
||||
}
|
||||
|
||||
protected IDP.SingleLogoutService parseSingleLogoutService(XMLEventReader xmlEventReader, boolean signaturesRequired) throws ParsingException {
|
||||
IDP.SingleLogoutService slo = new IDP.SingleLogoutService();
|
||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
slo.setSignRequest(getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
|
||||
slo.setValidateResponseSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
|
||||
slo.setValidateRequestSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_REQUEST_SIGNATURE_ATTR, signaturesRequired));
|
||||
slo.setRequestBinding(getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
|
||||
slo.setResponseBinding(getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
|
||||
slo.setSignResponse(getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_RESPONSE_ATTR, signaturesRequired));
|
||||
slo.setPostBindingUrl(getAttributeValue(element, ConfigXmlConstants.POST_BINDING_URL_ATTR));
|
||||
slo.setRedirectBindingUrl(getAttributeValue(element, ConfigXmlConstants.REDIRECT_BINDING_URL_ATTR));
|
||||
return slo;
|
||||
}
|
||||
|
||||
protected IDP.SingleSignOnService parseSingleSignOnService(XMLEventReader xmlEventReader, boolean signaturesRequired) throws ParsingException {
|
||||
IDP.SingleSignOnService sso = new IDP.SingleSignOnService();
|
||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
sso.setSignRequest(getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
|
||||
sso.setValidateResponseSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
|
||||
sso.setValidateAssertionSignature(getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_ASSERTION_SIGNATURE_ATTR));
|
||||
sso.setRequestBinding(getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
|
||||
sso.setResponseBinding(getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
|
||||
sso.setBindingUrl(getAttributeValue(element, ConfigXmlConstants.BINDING_URL_ATTR));
|
||||
sso.setAssertionConsumerServiceUrl(getAttributeValue(element, ConfigXmlConstants.ASSERTION_CONSUMER_SERVICE_URL_ATTR));
|
||||
return sso;
|
||||
}
|
||||
|
||||
private HttpClientConfig parseHttpClientElement(XMLEventReader xmlEventReader) throws ParsingException {
|
||||
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
StaxParserUtil.validate(startElement, ConfigXmlConstants.HTTP_CLIENT_ELEMENT);
|
||||
HttpClientConfig config = new HttpClientConfig();
|
||||
|
||||
config.setAllowAnyHostname(getBooleanAttributeValue(startElement, ConfigXmlConstants.ALLOW_ANY_HOSTNAME_ATTR, false));
|
||||
config.setClientKeystore(getAttributeValue(startElement, ConfigXmlConstants.CLIENT_KEYSTORE_ATTR));
|
||||
config.setClientKeystorePassword(getAttributeValue(startElement, ConfigXmlConstants.CLIENT_KEYSTORE_PASSWORD_ATTR));
|
||||
config.setConnectionPoolSize(getIntegerAttributeValue(startElement, ConfigXmlConstants.CONNECTION_POOL_SIZE_ATTR, 0));
|
||||
config.setDisableTrustManager(getBooleanAttributeValue(startElement, ConfigXmlConstants.ALLOW_ANY_HOSTNAME_ATTR, false));
|
||||
config.setProxyUrl(getAttributeValue(startElement, ConfigXmlConstants.PROXY_URL_ATTR));
|
||||
config.setTruststore(getAttributeValue(startElement, ConfigXmlConstants.TRUSTSTORE_ATTR));
|
||||
config.setTruststorePassword(getAttributeValue(startElement, ConfigXmlConstants.TRUSTSTORE_PASSWORD_ATTR));
|
||||
|
||||
while (xmlEventReader.hasNext()) {
|
||||
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
|
||||
if (xmlEvent == null)
|
||||
break;
|
||||
if (xmlEvent instanceof EndElement) {
|
||||
EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
|
||||
String endElementName = StaxParserUtil.getEndElementName(endElement);
|
||||
if (endElementName.equals(ConfigXmlConstants.ROLE_IDENTIFIERS_ELEMENT))
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
String tag = StaxParserUtil.getStartElementName(startElement);
|
||||
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(QName qname) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.adapters.saml.config.parsers;
|
||||
|
||||
import org.keycloak.adapters.saml.config.IDP;
|
||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.events.StartElement;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class IdpParser extends AbstractKeycloakSamlAdapterV1Parser<IDP> {
|
||||
|
||||
private static final IdpParser INSTANCE = new IdpParser();
|
||||
|
||||
private IdpParser() {
|
||||
super(KeycloakSamlAdapterV1QNames.IDP);
|
||||
}
|
||||
|
||||
public static IdpParser getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IDP instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
|
||||
final IDP idp = new IDP();
|
||||
|
||||
idp.setEntityID(StaxParserUtil.getRequiredAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ENTITY_ID));
|
||||
|
||||
Boolean signaturesRequired = StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGNATURES_REQUIRED);
|
||||
idp.setSignaturesRequired(signaturesRequired == null ? false : signaturesRequired);
|
||||
idp.setSignatureCanonicalizationMethod(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGNATURE_CANONICALIZATION_METHOD));
|
||||
idp.setSignatureAlgorithm(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGNATURE_ALGORITHM));
|
||||
|
||||
return idp;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processSubElement(XMLEventReader xmlEventReader, IDP target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
|
||||
switch (element) {
|
||||
case HTTP_CLIENT:
|
||||
target.setHttpClientConfig(HttpClientParser.getInstance().parse(xmlEventReader));
|
||||
break;
|
||||
|
||||
case KEYS:
|
||||
target.setKeys(KeysParser.getInstance().parse(xmlEventReader));
|
||||
break;
|
||||
|
||||
case SINGLE_SIGN_ON_SERVICE:
|
||||
target.setSingleSignOnService(SingleSignOnServiceParser.getInstance().parse(xmlEventReader));
|
||||
break;
|
||||
|
||||
case SINGLE_LOGOUT_SERVICE:
|
||||
target.setSingleLogoutService(SingleLogoutServiceParser.getInstance().parse(xmlEventReader));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
-79
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.adapters.saml.config.parsers;
|
||||
|
||||
import org.keycloak.adapters.saml.config.Key;
|
||||
import org.keycloak.common.util.StringPropertyReplacer;
|
||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.events.StartElement;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class KeyParser extends AbstractKeycloakSamlAdapterV1Parser<Key> {
|
||||
|
||||
private static final KeyParser INSTANCE = new KeyParser();
|
||||
|
||||
private KeyParser() {
|
||||
super(KeycloakSamlAdapterV1QNames.KEY);
|
||||
}
|
||||
|
||||
public static KeyParser getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Key instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
|
||||
Key key = new Key();
|
||||
key.setSigning(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_SIGNING));
|
||||
key.setEncryption(StaxParserUtil.getBooleanAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ENCRYPTION));
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processSubElement(XMLEventReader xmlEventReader, Key target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
|
||||
String value;
|
||||
switch (element) {
|
||||
case KEY_STORE:
|
||||
target.setKeystore(KeyStoreParser.getInstance().parse(xmlEventReader));
|
||||
break;
|
||||
|
||||
case CERTIFICATE_PEM:
|
||||
StaxParserUtil.advance(xmlEventReader);
|
||||
value = StaxParserUtil.getElementText(xmlEventReader);
|
||||
target.setCertificatePem(StringPropertyReplacer.replaceProperties(value));
|
||||
break;
|
||||
|
||||
case PUBLIC_KEY_PEM:
|
||||
StaxParserUtil.advance(xmlEventReader);
|
||||
value = StaxParserUtil.getElementText(xmlEventReader);
|
||||
target.setPublicKeyPem(StringPropertyReplacer.replaceProperties(value));
|
||||
break;
|
||||
|
||||
case PRIVATE_KEY_PEM:
|
||||
StaxParserUtil.advance(xmlEventReader);
|
||||
value = StaxParserUtil.getElementText(xmlEventReader);
|
||||
target.setPrivateKeyPem(StringPropertyReplacer.replaceProperties(value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
-73
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.adapters.saml.config.parsers;
|
||||
|
||||
import org.keycloak.adapters.saml.config.Key;
|
||||
import org.keycloak.adapters.saml.config.Key.KeyStoreConfig;
|
||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.events.StartElement;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class KeyStoreParser extends AbstractKeycloakSamlAdapterV1Parser<KeyStoreConfig> {
|
||||
|
||||
private static final KeyStoreParser INSTANCE = new KeyStoreParser();
|
||||
|
||||
private KeyStoreParser() {
|
||||
super(KeycloakSamlAdapterV1QNames.KEY_STORE);
|
||||
}
|
||||
|
||||
public static KeyStoreParser getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected KeyStoreConfig instantiateElement(XMLEventReader xmlEventReader, StartElement element) throws ParsingException {
|
||||
final KeyStoreConfig keyStore = new Key.KeyStoreConfig();
|
||||
keyStore.setType(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_TYPE));
|
||||
keyStore.setAlias(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_ALIAS));
|
||||
keyStore.setFile(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_FILE));
|
||||
keyStore.setResource(StaxParserUtil.getAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_RESOURCE));
|
||||
keyStore.setPassword(StaxParserUtil.getRequiredAttributeValueRP(element, KeycloakSamlAdapterV1QNames.ATTR_PASSWORD));
|
||||
|
||||
if (keyStore.getFile() == null && keyStore.getResource() == null) {
|
||||
throw new ParsingException("KeyStore element must have the url or classpath attribute set");
|
||||
}
|
||||
|
||||
return keyStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processSubElement(XMLEventReader xmlEventReader, KeyStoreConfig target, KeycloakSamlAdapterV1QNames element, StartElement elementDetail) throws ParsingException {
|
||||
switch (element) {
|
||||
case CERTIFICATE:
|
||||
target.setCertificateAlias(StaxParserUtil.getRequiredAttributeValueRP(elementDetail, KeycloakSamlAdapterV1QNames.ATTR_ALIAS));
|
||||
break;
|
||||
|
||||
case PRIVATE_KEY:
|
||||
target.setPrivateKeyAlias(StaxParserUtil.getRequiredAttributeValueRP(elementDetail, KeycloakSamlAdapterV1QNames.ATTR_ALIAS));
|
||||
target.setPrivateKeyPassword(StaxParserUtil.getRequiredAttributeValueRP(elementDetail, KeycloakSamlAdapterV1QNames.ATTR_PASSWORD));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+145
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.adapters.saml.config.parsers;
|
||||
|
||||
import org.keycloak.adapters.saml.config.Key;
|
||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||
import org.keycloak.saml.common.parsers.AbstractParser;
|
||||
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.events.EndElement;
|
||||
import javax.xml.stream.events.StartElement;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class KeyXmlParser extends AbstractParser {
|
||||
|
||||
@Override
|
||||
public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
|
||||
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
StaxParserUtil.validate(startElement, ConfigXmlConstants.KEY_ELEMENT);
|
||||
Key key = new Key();
|
||||
key.setSigning(SPXmlParser.getBooleanAttributeValue(startElement, ConfigXmlConstants.SIGNING_ATTR));
|
||||
key.setEncryption(SPXmlParser.getBooleanAttributeValue(startElement, ConfigXmlConstants.ENCRYPTION_ATTR));
|
||||
while (xmlEventReader.hasNext()) {
|
||||
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
|
||||
if (xmlEvent == null)
|
||||
break;
|
||||
if (xmlEvent instanceof EndElement) {
|
||||
EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
|
||||
String endElementName = StaxParserUtil.getEndElementName(endElement);
|
||||
if (endElementName.equals(ConfigXmlConstants.KEY_ELEMENT))
|
||||
break;
|
||||
else
|
||||
throw logger.parserUnknownEndElement(endElementName);
|
||||
}
|
||||
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
|
||||
if (startElement == null)
|
||||
break;
|
||||
String tag = StaxParserUtil.getStartElementName(startElement);
|
||||
if (tag.equals(ConfigXmlConstants.KEYS_STORE_ELEMENT)) {
|
||||
key.setKeystore(parseKeyStore(xmlEventReader));
|
||||
} else if (tag.equals(ConfigXmlConstants.CERTIFICATE_PEM_ELEMENT)) {
|
||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
key.setCertificatePem(SPXmlParser.getElementText(xmlEventReader));
|
||||
} else if (tag.equals(ConfigXmlConstants.PUBLIC_KEY_PEM_ELEMENT)) {
|
||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
key.setPublicKeyPem(SPXmlParser.getElementText(xmlEventReader));
|
||||
} else if (tag.equals(ConfigXmlConstants.PRIVATE_KEY_PEM_ELEMENT)) {
|
||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
key.setPrivateKeyPem(SPXmlParser.getElementText(xmlEventReader));
|
||||
} else {
|
||||
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
|
||||
}
|
||||
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
protected Key.KeyStoreConfig parseKeyStore(XMLEventReader xmlEventReader) throws ParsingException {
|
||||
StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
StaxParserUtil.validate(startElement, ConfigXmlConstants.KEYS_STORE_ELEMENT);
|
||||
Key.KeyStoreConfig keyStore = new Key.KeyStoreConfig();
|
||||
keyStore.setType(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.TYPE_ATTR));
|
||||
keyStore.setAlias(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.ALIAS_ATTR));
|
||||
keyStore.setFile(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.FILE_ATTR));
|
||||
keyStore.setResource(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.RESOURCE_ATTR));
|
||||
if (keyStore.getFile() == null && keyStore.getResource() == null) {
|
||||
throw new ParsingException("KeyStore element must have the url or classpath attribute set");
|
||||
}
|
||||
keyStore.setPassword(SPXmlParser.getAttributeValue(startElement, ConfigXmlConstants.PASSWORD_ATTR));
|
||||
if (keyStore.getPassword() == null) {
|
||||
throw new ParsingException("KeyStore element must have the password attribute set");
|
||||
}
|
||||
|
||||
|
||||
|
||||
while (xmlEventReader.hasNext()) {
|
||||
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
|
||||
if (xmlEvent == null)
|
||||
break;
|
||||
if (xmlEvent instanceof EndElement) {
|
||||
EndElement endElement = (EndElement) StaxParserUtil.getNextEvent(xmlEventReader);
|
||||
String endElementName = StaxParserUtil.getEndElementName(endElement);
|
||||
if (endElementName.equals(ConfigXmlConstants.KEYS_STORE_ELEMENT))
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
startElement = StaxParserUtil.peekNextStartElement(xmlEventReader);
|
||||
if (startElement == null)
|
||||
break;
|
||||
String tag = StaxParserUtil.getStartElementName(startElement);
|
||||
if (tag.equals(ConfigXmlConstants.CERTIFICATE_ELEMENT)) {
|
||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
keyStore.setCertificateAlias(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.ALIAS_ATTR));
|
||||
if (keyStore.getCertificateAlias() == null) {
|
||||
throw new ParsingException("KeyStore Certificate element must have the alias attribute set");
|
||||
|
||||
}
|
||||
} else if (tag.equals(ConfigXmlConstants.PRIVATE_KEY_ELEMENT)) {
|
||||
StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
|
||||
keyStore.setPrivateKeyAlias(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.ALIAS_ATTR));
|
||||
if (keyStore.getPrivateKeyAlias() == null) {
|
||||
throw new ParsingException("KeyStore PrivateKey element must have the alias attribute set");
|
||||
|
||||
}
|
||||
keyStore.setPrivateKeyPassword(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.PASSWORD_ATTR));
|
||||
if (keyStore.getPrivateKeyPassword() == null) {
|
||||
throw new ParsingException("KeyStore PrivateKey element must have the password attribute set");
|
||||
|
||||
}
|
||||
} else {
|
||||
StaxParserUtil.bypassElementBlock(xmlEventReader, tag);
|
||||
}
|
||||
|
||||
}
|
||||
return keyStore;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(QName qname) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
-85
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.adapters.saml.config.parsers;
|
||||
|
||||
import org.keycloak.saml.common.ErrorCodes;
|
||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||
import org.keycloak.saml.common.parsers.AbstractParser;
|
||||
import org.keycloak.saml.common.parsers.StaxParser;
|
||||
import org.keycloak.saml.common.util.StaxParserUtil;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.events.StartElement;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hmlnarik
|
||||
*/
|
||||
public class KeycloakSamlAdapterParser extends AbstractParser {
|
||||
|
||||
private interface ParserFactory {
|
||||
public StaxParser create();
|
||||
}
|
||||
private static final Map<QName, ParserFactory> PARSERS = new HashMap<QName, ParserFactory>();
|
||||
|
||||
// No-namespace variant
|
||||
private static final QName ALTERNATE_KEYCLOAK_SAML_ADAPTER_V1 = new QName(KeycloakSamlAdapterV1QNames.KEYCLOAK_SAML_ADAPTER.getQName().getLocalPart());
|
||||
|
||||
static {
|
||||
PARSERS.put(KeycloakSamlAdapterV1QNames.KEYCLOAK_SAML_ADAPTER.getQName(), new ParserFactory() { @Override public StaxParser create() { return KeycloakSamlAdapterV1Parser.getInstance(); }});
|
||||
PARSERS.put(ALTERNATE_KEYCLOAK_SAML_ADAPTER_V1, new ParserFactory() { @Override public StaxParser create() { return KeycloakSamlAdapterV1Parser.getInstance(); }});
|
||||
}
|
||||
|
||||
private static final KeycloakSamlAdapterParser INSTANCE = new KeycloakSamlAdapterParser();
|
||||
|
||||
public static KeycloakSamlAdapterParser getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
protected KeycloakSamlAdapterParser() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @see {@link org.keycloak.saml.common.parsers.ParserNamespaceSupport#parse(XMLEventReader)}
|
||||
*/
|
||||
@Override
|
||||
public Object parse(XMLEventReader xmlEventReader) throws ParsingException {
|
||||
while (xmlEventReader.hasNext()) {
|
||||
XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader);
|
||||
|
||||
if (xmlEvent instanceof StartElement) {
|
||||
StartElement startElement = (StartElement) xmlEvent;
|
||||
final QName name = startElement.getName();
|
||||
|
||||
ParserFactory pf = PARSERS.get(name);
|
||||
if (pf == null) {
|
||||
throw logger.parserException(new RuntimeException(ErrorCodes.UNKNOWN_START_ELEMENT + name + "::location="
|
||||
+ startElement.getLocation()));
|
||||
}
|
||||
|
||||
return pf.create().parse(xmlEventReader);
|
||||
}
|
||||
|
||||
StaxParserUtil.getNextEvent(xmlEventReader);
|
||||
}
|
||||
|
||||
throw new RuntimeException(ErrorCodes.FAILED_PARSING + "SAML Parsing has failed");
|
||||
}
|
||||
}
|
||||
Loaded 100 of 4716 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user