Compare commits

...
57 Commits
Author SHA1 Message Date
keycloak-bot 5f0ff23332 Set version to 4.0.0.Final 2018-06-13 18:53:04 +00:00
Hynek Mlnarik 9dc5709ce7 KEYCLOAK-7593 Setters for httpContext 2018-06-13 16:32:39 +02:00
vramik ccb09fbf45 KEYCLOAK-7616 fix NPE for UserStorageConsentTest 2018-06-13 15:53:41 +02:00
Hynek Mlnarik fb883254f6 KEYCLOAK-7434 2018-06-13 14:31:44 +02:00
vramik 5f1f3dff5e KEYCLOAK-7094 Support redirect to external logout page for elytron adapter 2018-06-13 12:50:38 +02:00
Pedro Igor dd93de75d9 [KEYCLOAK-7579] - Fixing test to use client scopes instead of old scope param required (#5259) 2018-06-12 15:44:03 -03:00
Stefan Guilhen d897159560 [KEYCLOAK-7598] - Set CIP config when defining paths in policy enforcer config (#5264) 2018-06-12 11:24:17 -03:00
Vlasta Ramik 182c975e01 KEYCLOAK-7597 fix logger classes (#5263) 2018-06-12 11:02:04 -03:00
vramik f19a324030 KEYCLOAK-7587 Some system properties are not included 2018-06-12 11:42:10 +02:00
vramik 9cf965a157 Ignore non-related failing ClientInitiatedAccountLinkTest#testErrorConditions 2018-06-11 13:46:59 +02:00
vramik 9e42be09d7 KEYCLOAK-7517 - adapter tests - EAP6 provider 2018-06-11 13:46:59 +02:00
vramik 7d466be94e KEYCLOAK-6541 rename AppServerContainerSPI to AppServerContainerProvider 2018-06-11 13:46:59 +02:00
vramik a5c0cbc3b4 KEYCLOAK-7473 app-server-eap provider 2018-06-11 13:46:59 +02:00
vramik bb5dc4c473 KEYCLOAK-6745 Adapter tests - remove abstract adapter test classes 2018-06-11 13:46:59 +02:00
vramik 132386f64d KEYCLOAK-6541 app server wildfly provider 2018-06-11 13:46:59 +02:00
vramik b0c89d739b KEYCLOAK-6541 app server undertow support 2018-06-11 13:46:59 +02:00
vramik 6a07a7ed2c KEYCLOAK-6541 base changes 2018-06-11 13:46:59 +02:00
vramik f293ab86c3 KEYCLOAK-7267 change a way how to install adapters in testsuite from online to offline scripts 2018-06-11 13:46:59 +02:00
Pedro Igor db60abc604 [KEYCLOAK-7543] - Policy enforcer should not delegate decisions when using UMA (#5252) 2018-06-11 08:17:40 -03:00
Lorent Lempereur f55c93a1e4 Javascript Adapter - Add 'cordovaOptions' to the Typescript definition of KeycloakLoginOptions (#5250) 2018-06-11 08:21:04 +02:00
Grzegorz Grzybek 08296bd3ce [KEYCLOAK-7508] Fix a typo: resouces -> resources (#5243) 2018-06-11 08:18:32 +02:00
Grzegorz Grzybek fca6da3a5a KEYCLOAK-7523 better context path detection in PathBasedKeycloakConfigResolver 2018-06-08 21:32:14 +02:00
Marek Posoldaandvramik 49407c2e4f KEYCLOAK-6630 Client scopes initial support (#5076)
* KEYCLOAK-6630 KEYCLOAK-349 Client Scopes

Co-authored-by: vramik <vramik@redhat.com>

* KEYCLOAK-6630 Change some clientTemplate occurences to clientScope
2018-06-08 15:38:38 +02:00
Vlasta Ramik 4d1474afe0 KEYCLOAK-7549 Update artifactId according to latest Fuse7 build (#5253) 2018-06-08 15:15:34 +02:00
Pedro Igor aa128d6c07 Merge pull request #5240 from pedroigor/KEYCLOAK-7353
[KEYCLOAK-7353] Support Policy Management in Protection API
2018-06-07 11:05:49 -03:00
Ola Bergefall c8c76cc03f KEYCLOAK-7316: Default back to false if isPassive is missing in request. 2018-06-07 08:50:32 +02:00
Federico M. Facca 5a9bfea419 [KEYCLOAK-7353] Support Policy Management in Protection API
See https://issues.jboss.org/browse/KEYCLOAK-7353
2018-06-06 19:36:42 -03:00
vramik dffe70e40a KEYCLOAK-7518 DeploymentArchiveProcessor assumes that every archive contains jboss-deployment-structure.xml file 2018-06-06 21:15:39 +02:00
Tomas Kyjovsky 1b4d9a6147 KEYCLOAK-7440 Modcluster configuration for functional cluster test is broken 2018-06-06 20:40:50 +02:00
Stan Silvert b7fb3ec9a9 KEYCLOAK-7513 Minor changes to vertical nav (#5244) 2018-06-06 14:39:00 -04:00
Hynek Mlnarik 7ff18ca14b KEYCLOAK-7331 Fix NPE when SAML Issuer not set in AuthnRequest 2018-06-06 16:21:18 +02:00
Your Name 6052b1546d removed LANG-dependent check #7444 2018-06-06 12:53:58 +02:00
Hynek Mlnarik 5a241392cf KEYCLOAK-7094 Support redirect to external logout page 2018-06-05 14:51:18 +02:00
Takashi Norimatsu c586c63533 KEYCLOAK-6771 Holder of Key mechanism
OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access
Tokens
2018-06-05 08:18:29 +02:00
Pedro Igor f8919f8baa Merge pull request #5211 from pedroigor/KEYCLOAK-7367
[KEYCLOAK-7367] - User-Managed Policy Provider
2018-06-04 09:35:13 -03:00
Stan Silvert f45ed1613e KEYCLOAK-7334: Update vertical na/Integrate patternfly-ng (#5241) 2018-06-04 07:53:37 -04:00
Pedro Igor bc665fdbc3 Merge pull request #5195 from suem/bugfix_FilterSessionStore
NullPointerException in FilterSessionStore when restoring request
2018-06-01 10:51:28 -03:00
Pavel Drozd 6c3e6bc90c KEYCLOAK-7476 - sshLoginTest - changed command result 2018-06-01 10:35:38 +02:00
Stan Silvert cb3b7f3cb2 KEYCLOAK-5934: Disable paste for event filters (#5026) 2018-06-01 10:28:56 +02:00
June Zhang 5e8db32329 Fixes KEYCLOAK-7382 - Application Response HTML Update (#5235) 2018-05-31 13:18:25 -04:00
Jared Blashka 65c39763eb KEYCLOAK-7356 Code to Token flow fails if initial redirect_uri contains a session_state parameter 2018-05-31 08:53:11 +02:00
Martin Kanis f429469fc8 KEYCLOAK-5270 Realm cookie path for IE<=11 users (#5106) 2018-05-31 08:44:34 +02:00
Pedro Igor 6339b62f8d Merge pull request #5219 from tkyjovsk/KEYCLOAK-6759
KEYCLOAK-6759 Create the databases for import during perf tests
2018-05-30 09:51:21 -03:00
Pedro Igor 473e9ab55c Merge pull request #5227 from pedroigor/KEYCLOAK-7449
[KEYCLOAK-7449] - When clicking link or actions the row is expanded
2018-05-29 14:38:23 -03:00
June Zhang 77e503f5ca Fixes KEYCLOAK-7381 Device Activity Response - HTML update (#5230) 2018-05-29 09:30:48 -04:00
Johannes Knutsen c64ecb1ab8 Remove expired objects from cache cluster instead of local only 2018-05-29 10:27:43 +02:00
Rick van den Hof 2e22dcfc47 Add unit tests 2018-05-29 10:03:54 +02:00
Rick van den Hof 16fd6558a6 Enable adding of default groups 2018-05-29 10:03:54 +02:00
Takashi Norimatsu eb97151476 KEYCLOAK-7451 OAuth Authorization Server Metadata for Proof Key for Code Exchange 2018-05-28 22:15:43 +02:00
Tomas Kyjovsky b8adee4004 KEYCLOAK-6759 Create the databases for import during perf tests 2018-05-28 17:52:27 +02:00
Pedro Igor 65f5eacdd4 [KEYCLOAK-7449] - When clicking link or actions the row is expanded 2018-05-25 17:57:03 -03:00
Pedro Igor 2b6597e9f1 [KEYCLOAK-7367] - User-Managed Policy Provider 2018-05-25 16:18:15 -03:00
Hynek Mlnarik 6a2f73df9c KEYCLOAK-7433 Update licenses 2018-05-25 11:27:51 +02:00
Hynek Mlnarik 60a03d0293 KEYCLOAK-7434 Align versions to match EAP 7.1.3 2018-05-25 11:27:51 +02:00
Hynek Mlnarik dd6735285d KEYCLOAK-7438 Don't create symlinks in download-license-files.sh 2018-05-25 09:50:41 +02:00
Stian Thorgersen dbf5c395b0 Bump version to 4.0.0.Final (#5224) 2018-05-24 19:02:30 +02:00
Samuel Ueltschi 3391ec5377 check if content-type is null when restoring request 2018-05-09 12:47:14 +02:00
1045 changed files with 20567 additions and 11680 deletions

No files matched your search

+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -28,6 +28,7 @@ import org.jboss.logging.Logger;
import org.keycloak.AuthorizationContext;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.adapters.spi.HttpFacade.Request;
import org.keycloak.authorization.client.AuthzClient;
import org.keycloak.authorization.client.ClientAuthorizationContext;
@@ -165,7 +166,7 @@ public abstract class AbstractPolicyEnforcer {
policyEnforcer.getPathMatcher().removeFromCache(getPath(request));
}
return hasValidClaims(actualPathConfig, httpFacade, authorization);
return hasValidClaims(actualPathConfig, permission, httpFacade, authorization);
}
}
} else {
@@ -187,35 +188,22 @@ public abstract class AbstractPolicyEnforcer {
return false;
}
private boolean hasValidClaims(PathConfig actualPathConfig, OIDCHttpFacade httpFacade, Authorization authorization) {
Map<String, Map<String, Object>> claimInformationPointConfig = actualPathConfig.getClaimInformationPointConfig();
private boolean hasValidClaims(PathConfig actualPathConfig, Permission permission, OIDCHttpFacade httpFacade, Authorization authorization) {
Map<String, Set<String>> grantedClaims = permission.getClaims();
if (claimInformationPointConfig != null) {
Map<String, List<String>> claims = new HashMap<>();
if (grantedClaims != null) {
Map<String, List<String>> claims = resolveClaims(actualPathConfig, httpFacade);
for (Entry<String, Map<String, Object>> entry : claimInformationPointConfig.entrySet()) {
ClaimInformationPointProviderFactory factory = policyEnforcer.getClaimInformationPointProviderFactories().get(entry.getKey());
if (factory == null) {
throw new RuntimeException("Could not find claim information provider with name [" + entry.getKey() + "]");
}
claims.putAll(factory.create(entry.getValue()).resolve(httpFacade));
if (claims.isEmpty()) {
return false;
}
Map<String, List<String>> grantedClaims = authorization.getClaims();
for (Entry<String, Set<String>> entry : grantedClaims.entrySet()) {
List<String> requestClaims = claims.get(entry.getKey());
if (grantedClaims != null) {
if (claims.isEmpty()) {
if (requestClaims == null || requestClaims.isEmpty() || !entry.getValue().containsAll(requestClaims)) {
return false;
}
for (Entry<String, List<String>> entry : grantedClaims.entrySet()) {
List<String> requestClaims = claims.get(entry.getKey());
if (requestClaims == null || requestClaims.isEmpty() || !entry.getValue().containsAll(requestClaims)) {
return false;
}
}
}
}
@@ -342,4 +330,28 @@ public abstract class AbstractPolicyEnforcer {
private PathConfig getPathConfig(Request request) {
return isDefaultAccessDeniedUri(request) ? null : policyEnforcer.getPathMatcher().matches(getPath(request));
}
protected Map<String, List<String>> resolveClaims(PathConfig pathConfig, OIDCHttpFacade httpFacade) {
Map<String, List<String>> claims = getClaims(getEnforcerConfig().getClaimInformationPointConfig(), httpFacade);
claims.putAll(getClaims(pathConfig.getClaimInformationPointConfig(), httpFacade));
return claims;
}
private Map<String, List<String>> getClaims(Map<String, Map<String, Object>>claimInformationPointConfig, HttpFacade httpFacade) {
Map<String, List<String>> claims = new HashMap<>();
if (claimInformationPointConfig != null) {
for (Entry<String, Map<String, Object>> claimDef : claimInformationPointConfig.entrySet()) {
ClaimInformationPointProviderFactory factory = getPolicyEnforcer().getClaimInformationPointProviderFactories().get(claimDef.getKey());
if (factory != null) {
claims.putAll(factory.create(claimDef.getValue()).resolve(httpFacade));
}
}
}
return claims;
}
}
@@ -22,7 +22,6 @@ 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.KeycloakSecurityContext;
@@ -87,19 +86,6 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
grantedPermissions.add(newPermission);
}
}
Map<String, List<String>> newClaims = newAuthorization.getClaims();
if (newClaims != null) {
Map<String, List<String>> claims = authorization.getClaims();
if (claims == null) {
claims = new HashMap<>();
authorization.setClaims(claims);
}
claims.putAll(newClaims);
}
}
original.setAuthorization(authorization);
@@ -154,7 +140,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
}
private AccessToken requestAuthorizationToken(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, OIDCHttpFacade httpFacade) {
if (getPolicyEnforcer().getDeployment().isBearerOnly() || (isBearerAuthorization(httpFacade) && getEnforcerConfig().getUserManagedAccess() != null)) {
if (getEnforcerConfig().getUserManagedAccess() != null) {
return null;
}
@@ -165,20 +151,15 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
AccessToken accessToken = securityContext.getToken();
AuthorizationRequest authzRequest = new AuthorizationRequest();
if (getEnforcerConfig().getUserManagedAccess() != null) {
String ticket = getPermissionTicket(pathConfig, methodConfig, getAuthzClient(), httpFacade);
authzRequest.setTicket(ticket);
} else {
if (accessToken.getAuthorization() != null) {
authzRequest.addPermission(pathConfig.getId(), methodConfig.getScopes());
}
if (isBearerAuthorization(httpFacade) || accessToken.getAuthorization() != null) {
authzRequest.addPermission(pathConfig.getId(), methodConfig.getScopes());
}
Map<String, List<String>> claims = getClaims(pathConfig, httpFacade);
Map<String, List<String>> claims = resolveClaims(pathConfig, httpFacade);
if (!claims.isEmpty()) {
authzRequest.setClaimTokenFormat("urn:ietf:params:oauth:token-type:jwt");
authzRequest.setClaimToken(Base64.encodeBytes(JsonSerialization.writeValueAsBytes(claims)));
}
if (!claims.isEmpty()) {
authzRequest.setClaimTokenFormat("urn:ietf:params:oauth:token-type:jwt");
authzRequest.setClaimToken(Base64.encodeBytes(JsonSerialization.writeValueAsBytes(claims)));
}
if (accessToken.getAuthorization() != null) {
@@ -186,7 +167,14 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
}
LOGGER.debug("Obtaining authorization for authenticated user.");
AuthorizationResponse authzResponse = getAuthzClient().authorization(accessTokenString).authorize(authzRequest);
AuthorizationResponse authzResponse;
if (isBearerAuthorization(httpFacade)) {
authzRequest.setSubjectToken(accessTokenString);
authzResponse = getAuthzClient().authorization().authorize(authzRequest);
} else {
authzResponse = getAuthzClient().authorization(accessTokenString).authorize(authzRequest);
}
if (authzResponse != null) {
return AdapterRSATokenVerifier.verifyToken(authzResponse.getToken(), deployment);
@@ -200,7 +188,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
return null;
}
private String getPermissionTicket(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, AuthzClient authzClient, HttpFacade httpFacade) {
private String getPermissionTicket(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, AuthzClient authzClient, OIDCHttpFacade httpFacade) {
if (getEnforcerConfig().getUserManagedAccess() != null) {
ProtectionResource protection = authzClient.protection();
PermissionResource permission = protection.permission();
@@ -209,7 +197,7 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
permissionRequest.setResourceId(pathConfig.getId());
permissionRequest.setScopes(new HashSet<>(methodConfig.getScopes()));
Map<String, List<String>> claims = getClaims(pathConfig, httpFacade);
Map<String, List<String>> claims = resolveClaims(pathConfig, httpFacade);
if (!claims.isEmpty()) {
permissionRequest.setClaims(claims);
@@ -221,22 +209,6 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
return null;
}
private Map<String, List<String>> getClaims(PathConfig pathConfig, HttpFacade httpFacade) {
Map<String, List<String>> claims = new HashMap<>();
Map<String, Map<String, Object>> claimInformationPointConfig = pathConfig.getClaimInformationPointConfig();
if (claimInformationPointConfig != null) {
for (Entry<String, Map<String, Object>> claimDef : claimInformationPointConfig.entrySet()) {
ClaimInformationPointProviderFactory factory = getPolicyEnforcer().getClaimInformationPointProviderFactories().get(claimDef.getKey());
if (factory != null) {
claims.putAll(factory.create(claimDef.getValue()).resolve(httpFacade));
}
}
}
return claims;
}
private boolean isBearerAuthorization(OIDCHttpFacade httpFacade) {
List<String> authHeaders = httpFacade.getRequest().getHeaders("Authorization");
if (authHeaders == null || authHeaders.size() == 0) {
@@ -271,7 +271,17 @@ public class PolicyEnforcer {
List<ResourceRepresentation> matchingResources = authzClient.protection().resource().findByMatchingUri(targetUri);
if (!matchingResources.isEmpty()) {
Map<String, Map<String, Object>> cipConfig = null;
if (pathConfig != null) {
cipConfig = pathConfig.getClaimInformationPointConfig();
}
pathConfig = PathConfig.createPathConfig(matchingResources.get(0));
if (cipConfig != null) {
pathConfig.setClaimInformationPointConfig(cipConfig);
}
}
} catch (Exception cause) {
LOGGER.errorf(cause, "Could not lazy load resource with path [" + targetUri + "] from server");
@@ -319,6 +329,7 @@ public class PolicyEnforcer {
config.setMethods(originalConfig.getMethods());
config.setParentConfig(originalConfig);
config.setEnforcementMode(originalConfig.getEnforcementMode());
config.setClaimInformationPointConfig(originalConfig.getClaimInformationPointConfig());
return config;
}
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-as7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-as7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-as7-integration-pom</artifactId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak AS7 / JBoss EAP 6 Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-fuse7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-fuse7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -86,6 +86,9 @@ public class PaxWebIntegrationService {
return httpContext;
}
public void setHttpContext(HttpContext httpContext) {
this.httpContext = httpContext;
}
public void start() {
ServiceTrackerCustomizer trackerCustomizer = new ServiceTrackerCustomizer() {
@@ -115,7 +118,9 @@ public class PaxWebIntegrationService {
protected WebContainer addingWebContainerCallback(ServiceReference webContainerServiceReference) {
WebContainer service = (WebContainer) bundleContext.getService(webContainerServiceReference);
httpContext = service.createDefaultHttpContext();
if (httpContext == null) {
httpContext = service.createDefaultHttpContext();
}
addJettyWebXml(service);
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-fuse7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-fuse7-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -70,6 +70,9 @@ public class PaxWebIntegrationService {
return httpContext;
}
public void setHttpContext(HttpContext httpContext) {
this.httpContext = httpContext;
}
public void start() {
ServiceTrackerCustomizer trackerCustomizer = new ServiceTrackerCustomizer() {
@@ -99,7 +102,9 @@ public class PaxWebIntegrationService {
protected WebContainer addingWebContainerCallback(ServiceReference webContainerServiceReference) {
WebContainer service = (WebContainer) bundleContext.getService(webContainerServiceReference);
httpContext = service.createDefaultHttpContext();
if (httpContext == null) {
httpContext = service.createDefaultHttpContext();
}
if (constraintMappings == null) {
throw new IllegalStateException("constraintMappings was null!");
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak Jetty Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+8
View File
@@ -161,6 +161,14 @@ declare namespace Keycloak {
* the user's profile to a new preferred locale.
*/
kcLocale?: string;
/**
* Specifies arguments that are passed to the Cordova in-app-browser (if applicable).
* Options 'hidden' and 'location' are not affected by these arguments.
* All available options are defined at https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-inappbrowser/.
* Example of use: { zoom: "no", hardwareback: "yes" }
*/
cordovaOptions?: { [optionName: string]: string };
}
type KeycloakPromiseCallback<T> = (result: T) => void;
@@ -250,7 +250,16 @@
baseUrl = kc.endpoints.authorize();
}
var scope = (options && options.scope) ? "openid " + options.scope : "openid";
var scope;
if (options && options.scope) {
if (options.scope.indexOf("openid") != -1) {
scope = options.scope;
} else {
scope = "openid " + options.scope;
}
} else {
scope = "openid";
}
var url = baseUrl
+ '?client_id=' + encodeURIComponent(kc.clientId)
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+7 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -99,6 +99,12 @@
<version>${cxf.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
@@ -25,6 +25,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -34,13 +35,35 @@ public class PathBasedKeycloakConfigResolver implements KeycloakConfigResolver {
@Override
public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {
String path = request.getURI();
String[] urlTokens = path.split("/");
if (urlTokens.length < 4) {
throw new IllegalStateException("Not able to determine the web-context to load the correspondent keycloak.json file");
}
String uri = request.getURI();
String relativePath = request.getRelativePath();
String webContext = null;
if (relativePath == null || !uri.contains(relativePath)) {
String[] urlTokens = uri.split("/");
if (urlTokens.length < 4) {
throw new IllegalStateException("Not able to determine the web-context to load the correspondent keycloak.json file");
}
String webContext = urlTokens[3];
webContext = urlTokens[3];
} else {
URI parsedURI = URI.create(uri);
String path = parsedURI.getPath();
path = path.substring(0, path.indexOf(relativePath));
while (path.startsWith("/")) {
path = path.substring(1);
}
webContext = path;
if ("".equals(webContext)) {
path = relativePath;
while (path.startsWith("/")) {
path = path.substring(1);
}
if (path.contains("/")) {
path = path.substring(0, path.indexOf("/"));
}
webContext = path;
}
}
KeycloakDeployment deployment = cache.get(webContext);
if (null == deployment) {
@@ -54,7 +77,8 @@ public class PathBasedKeycloakConfigResolver implements KeycloakConfigResolver {
keycloakConfig = karafEtc;
}
String absolutePath = keycloakConfig + File.separator + webContext + "-keycloak.json";
String absolutePath = keycloakConfig + File.separator + webContext + ("".equals(webContext) ? "" : "-")
+ "keycloak.json";
InputStream is = null;
try {
is = new FileInputStream(absolutePath);
@@ -0,0 +1,149 @@
/*
* 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.osgi;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.spi.AuthenticationError;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.adapters.spi.LogoutError;
import static org.junit.Assert.assertNotNull;
public class PathBasedKeycloakConfigResolverTest {
@Test
public void relativeURIsAndContexts() throws Exception {
PathBasedKeycloakConfigResolver resolver = new PathBasedKeycloakConfigResolver();
assertNotNull(populate(resolver, "test")
.resolve(new MockRequest("http://localhost/test/a/b/c?d=e", "/a/b/c")));
assertNotNull(populate(resolver, "test")
.resolve(new MockRequest("http://localhost/test/a/b/c?d=e", "/a/b")));
// means default context and actually we use first segment
assertNotNull(populate(resolver, "test")
.resolve(new MockRequest("http://localhost/test/a/b/c?d=e", "/test/a/b/c")));
assertNotNull(populate(resolver, "test/a")
.resolve(new MockRequest("http://localhost/test/a/b/c?d=e", "/b/c")));
assertNotNull(populate(resolver, "")
.resolve(new MockRequest("http://localhost/", "/")));
}
@SuppressWarnings("unchecked")
private PathBasedKeycloakConfigResolver populate(PathBasedKeycloakConfigResolver resolver, String context)
throws Exception {
Field f = PathBasedKeycloakConfigResolver.class.getDeclaredField("cache");
f.setAccessible(true);
Map<String, KeycloakDeployment> cache = (Map<String, KeycloakDeployment>) f.get(resolver);
cache.clear();
cache.put(context, new KeycloakDeployment());
return resolver;
}
private class MockRequest implements OIDCHttpFacade.Request {
private String uri;
private String relativePath;
public MockRequest(String uri, String relativePath) {
this.uri = uri;
this.relativePath = relativePath;
}
@Override
public String getMethod() {
return null;
}
@Override
public String getURI() {
return this.uri;
}
@Override
public String getRelativePath() {
return this.relativePath;
}
@Override
public boolean isSecure() {
return false;
}
@Override
public String getFirstParam(String param) {
return null;
}
@Override
public String getQueryParamValue(String param) {
return null;
}
@Override
public HttpFacade.Cookie getCookie(String cookieName) {
return null;
}
@Override
public String getHeader(String name) {
return null;
}
@Override
public List<String> getHeaders(String name) {
return null;
}
@Override
public InputStream getInputStream() {
return null;
}
@Override
public InputStream getInputStream(boolean buffered) {
return null;
}
@Override
public String getRemoteAddr() {
return null;
}
@Override
public void setError(AuthenticationError error) {
}
@Override
public void setError(LogoutError error) {
}
}
}
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<name>Keycloak OIDC Client Adapter Modules</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.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.Beta3-SNAPSHOT</version>
<version>4.0.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.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<artifactId>spring-boot-container-bundle</artifactId>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak Tomcat Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -22,7 +22,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -46,7 +46,7 @@ import org.wildfly.security.http.Scope;
*/
class KeycloakHttpServerAuthenticationMechanism implements HttpServerAuthenticationMechanism {
static Logger LOGGER = Logger.getLogger(KeycloakHttpServerAuthenticationMechanismFactory.class);
static Logger LOGGER = Logger.getLogger(KeycloakHttpServerAuthenticationMechanism.class);
static final String NAME = "KEYCLOAK";
private final Map<String, ?> properties;
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak WildFly Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-parent</artifactId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.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.Beta3-SNAPSHOT</version>
<version>4.0.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.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<name>Keycloak Adapters</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-saml-eap-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak SAML EAP Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-eap-integration-pom</artifactId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -66,6 +66,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -119,16 +120,27 @@ public abstract class AbstractSamlAuthenticator extends LoginAuthenticator {
tokenStore.logoutAccount();
}
protected void forwardToLogoutPage(Request request, HttpServletResponse response, SamlDeployment deployment) {
RequestDispatcher disp = request.getRequestDispatcher(deployment.getLogoutPage());
//make sure the login page is never cached
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setHeader("Expires", "0");
private static final Pattern PROTOCOL_PATTERN = Pattern.compile("^[a-zA-Z][a-zA-Z0-9+.-]*:");
protected void forwardToLogoutPage(Request request, HttpServletResponse response, SamlDeployment deployment) {
final String location = deployment.getLogoutPage();
try {
disp.forward(request, response);
//make sure the login page is never cached
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setHeader("Expires", "0");
if (location == null) {
log.warn("Logout page not set.");
response.sendError(HttpServletResponse.SC_NOT_FOUND);
} else if (PROTOCOL_PATTERN.matcher(location).find()) {
response.sendRedirect(response.encodeRedirectURL(location));
} else {
RequestDispatcher disp = request.getRequestDispatcher(location);
disp.forward(request, response);
}
} catch (ServletException e) {
throw new RuntimeException(e);
} catch (IOException e) {
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak SAML Jetty Integration</name>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<name>Keycloak SAML Client Adapter Modules</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak SAML Tomcat Integration</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -44,7 +44,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.*;
import java.util.Map;
import java.util.regex.Pattern;
/**
* Keycloak authentication valve
@@ -189,16 +189,27 @@ public abstract class AbstractSamlAuthenticatorValve extends FormAuthenticator i
protected abstract GenericPrincipalFactory createPrincipalFactory();
protected abstract boolean forwardToErrorPageInternal(Request request, HttpServletResponse response, Object loginConfig) throws IOException;
protected void forwardToLogoutPage(Request request, HttpServletResponse response,SamlDeployment deployment) {
RequestDispatcher disp = request.getRequestDispatcher(deployment.getLogoutPage());
//make sure the login page is never cached
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setHeader("Expires", "0");
private static final Pattern PROTOCOL_PATTERN = Pattern.compile("^[a-zA-Z][a-zA-Z0-9+.-]*:");
protected void forwardToLogoutPage(Request request, HttpServletResponse response, SamlDeployment deployment) {
final String location = deployment.getLogoutPage();
try {
disp.forward(request.getRequest(), response);
//make sure the login page is never cached
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setHeader("Expires", "0");
if (location == null) {
log.warn("Logout page not set.");
response.sendError(HttpServletResponse.SC_NOT_FOUND);
} else if (PROTOCOL_PATTERN.matcher(location).find()) {
response.sendRedirect(response.encodeRedirectURL(location));
} else {
RequestDispatcher disp = request.getRequestDispatcher(location);
disp.forward(request.getRequest(), response);
}
} catch (ServletException e) {
throw new RuntimeException(e);
} catch (IOException e) {
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -33,6 +33,9 @@ import org.keycloak.adapters.spi.AuthOutcome;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.adapters.undertow.UndertowHttpFacade;
import org.keycloak.adapters.undertow.UndertowUserSessionManagement;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
/**
* Abstract base class for a Keycloak-enabled Undertow AuthenticationMechanism.
@@ -40,6 +43,9 @@ import org.keycloak.adapters.undertow.UndertowUserSessionManagement;
* @author Stan Silvert ssilvert@redhat.com (C) 2014 Red Hat Inc.
*/
public abstract class AbstractSamlAuthMech implements AuthenticationMechanism {
private static final Logger LOG = Logger.getLogger(AbstractSamlAuthMech.class.getName());
public static final AttachmentKey<AuthChallenge> KEYCLOAK_CHALLENGE_ATTACHMENT_KEY = AttachmentKey.create(AuthChallenge.class);
protected SamlDeploymentContext deploymentContext;
protected UndertowUserSessionManagement sessionManagement;
@@ -68,11 +74,22 @@ public abstract class AbstractSamlAuthMech implements AuthenticationMechanism {
return StatusCodes.TEMPORARY_REDIRECT;
}
private static final Pattern PROTOCOL_PATTERN = Pattern.compile("^[a-zA-Z][a-zA-Z0-9+.-]*:");
static void sendRedirect(final HttpServerExchange exchange, final String location) {
// TODO - String concatenation to construct URLS is extremely error prone - switch to a URI which will better
// handle this.
String loc = exchange.getRequestScheme() + "://" + exchange.getHostAndPort() + location;
exchange.getResponseHeaders().put(Headers.LOCATION, loc);
if (location == null) {
LOG.log(Level.WARNING, "Logout page not set.");
exchange.setStatusCode(StatusCodes.NOT_FOUND);
exchange.endExchange();
return;
}
if (PROTOCOL_PATTERN.matcher(location).find()) {
exchange.getResponseHeaders().put(Headers.LOCATION, location);
} else {
String loc = exchange.getRequestScheme() + "://" + exchange.getHostAndPort() + location;
exchange.getResponseHeaders().put(Headers.LOCATION, loc);
}
}
protected void registerNotifications(final SecurityContext securityContext) {
@@ -142,7 +159,7 @@ public abstract class AbstractSamlAuthMech implements AuthenticationMechanism {
protected void redirectLogout(SamlDeployment deployment, HttpServerExchange exchange) {
String page = deployment.getLogoutPage();
sendRedirect(exchange, page);
exchange.setResponseCode(302);
exchange.setStatusCode(StatusCodes.FOUND);
exchange.endExchange();
}
@@ -113,7 +113,11 @@ public class ServletSamlAuthMech extends AbstractSamlAuthMech {
@Override
protected void redirectLogout(SamlDeployment deployment, HttpServerExchange exchange) {
servePage(exchange, deployment.getLogoutPage());
exchange.getResponseHeaders().add(Headers.CACHE_CONTROL, "no-cache, no-store, must-revalidate");
exchange.getResponseHeaders().add(Headers.PRAGMA, "no-cache");
exchange.getResponseHeaders().add(Headers.EXPIRES, "0");
super.redirectLogout(deployment, exchange);
}
@Override
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -19,6 +19,7 @@ package org.keycloak.adapters.saml.elytron;
import java.net.URI;
import java.util.Map;
import java.util.regex.Pattern;
import javax.security.auth.callback.CallbackHandler;
@@ -39,7 +40,7 @@ import org.wildfly.security.http.Scope;
*/
class KeycloakHttpServerAuthenticationMechanism implements HttpServerAuthenticationMechanism {
static Logger LOGGER = Logger.getLogger(KeycloakHttpServerAuthenticationMechanismFactory.class);
static Logger LOGGER = Logger.getLogger(KeycloakHttpServerAuthenticationMechanism.class);
static final String NAME = "KEYCLOAK-SAML";
private final Map<String, ?> properties;
@@ -142,14 +143,23 @@ class KeycloakHttpServerAuthenticationMechanism implements HttpServerAuthenticat
exchange.getResponse().setStatus(302);
}
private static final Pattern PROTOCOL_PATTERN = Pattern.compile("^[a-zA-Z][a-zA-Z0-9+.-]*:");
static void sendRedirect(final ElytronHttpFacade exchange, final String location) {
// TODO - String concatenation to construct URLS is extremely error prone - switch to a URI which will better
// handle this.
URI uri = exchange.getURI();
String path = uri.getPath();
String relativePath = exchange.getRequest().getRelativePath();
String contextPath = path.substring(0, path.indexOf(relativePath));
String loc = exchange.getURI().getScheme() + "://" + exchange.getURI().getHost() + ":" + exchange.getURI().getPort() + contextPath + location;
exchange.getResponse().setHeader("Location", loc);
if (location == null) {
LOGGER.warn("Logout page not set.");
exchange.getResponse().setStatus(302);
return;
}
if (PROTOCOL_PATTERN.matcher(location).find()) {
exchange.getResponse().setHeader("Location", location);
} else {
URI uri = exchange.getURI();
String path = uri.getPath();
String relativePath = exchange.getRequest().getRelativePath();
String contextPath = path.substring(0, path.indexOf(relativePath));
String loc = exchange.getURI().getScheme() + "://" + exchange.getURI().getHost() + ":" + exchange.getURI().getPort() + contextPath + location;
exchange.getResponse().setHeader("Location", loc);
}
}
}
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<name>Keycloak SAML Wildfly Integration</name>
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.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.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../../pom.xml</relativePath>
</parent>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -20,7 +20,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<name>Keycloak Client Adapter SPI Modules</name>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -111,8 +111,7 @@ public class FilterSessionStore implements AdapterSessionStore {
if (body == null) return new MultivaluedHashMap<String, String>();
String contentType = getContentType();
contentType = contentType.toLowerCase();
if (contentType.startsWith("application/x-www-form-urlencoded")) {
if (contentType != null && contentType.toLowerCase().startsWith("application/x-www-form-urlencoded")) {
ByteArrayInputStream is = new ByteArrayInputStream(body);
try {
parameters = parseForm(is);
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -21,7 +21,7 @@
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -7,7 +7,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-parent</artifactId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
@@ -102,6 +102,9 @@ public class ServerConfiguration {
@JsonProperty("permission_endpoint")
private String permissionEndpoint;
@JsonProperty("policy_endpoint")
private String policyEndpoint;
public String getIssuer() {
return issuer;
@@ -206,4 +209,8 @@ public class ServerConfiguration {
public String getPermissionEndpoint() {
return permissionEndpoint;
}
public String getPolicyEndpoint() {
return policyEndpoint;
}
}
@@ -0,0 +1,187 @@
/*
* 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.authorization.client.resource;
import java.util.List;
import java.util.concurrent.Callable;
import com.fasterxml.jackson.core.type.TypeReference;
import org.keycloak.authorization.client.representation.ServerConfiguration;
import org.keycloak.authorization.client.util.Http;
import org.keycloak.authorization.client.util.Throwables;
import org.keycloak.authorization.client.util.TokenCallable;
import org.keycloak.representations.idm.authorization.UmaPermissionRepresentation;
import org.keycloak.util.JsonSerialization;
/**
* An entry point for managing user-managed permissions for a particular resource
*
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class PolicyResource {
private String resourceId;
private final Http http;
private final ServerConfiguration serverConfiguration;
private final TokenCallable pat;
public PolicyResource(String resourceId, Http http, ServerConfiguration serverConfiguration, TokenCallable pat) {
this.resourceId = resourceId;
this.http = http;
this.serverConfiguration = serverConfiguration;
this.pat = pat;
}
/**
* Creates a new user-managed permission as represented by the given {@code permission}.
*
* @param permission the permission to create
* @return if successful, the permission created
*/
public UmaPermissionRepresentation create(final UmaPermissionRepresentation permission) {
if (permission == null) {
throw new IllegalArgumentException("Permission must not be null");
}
Callable<UmaPermissionRepresentation> callable = new Callable<UmaPermissionRepresentation>() {
@Override
public UmaPermissionRepresentation call() throws Exception {
return http.<UmaPermissionRepresentation>post(serverConfiguration.getPolicyEndpoint() + "/" + resourceId)
.authorizationBearer(pat.call())
.json(JsonSerialization.writeValueAsBytes(permission))
.response().json(UmaPermissionRepresentation.class).execute();
}
};
try {
return callable.call();
} catch (Exception cause) {
return Throwables.retryAndWrapExceptionIfNecessary(callable, pat, "Error creating policy for resurce [" + resourceId + "]", cause);
}
}
/**
* Updates an existing user-managed permission
*
* @param permission the permission to update
*/
public void update(final UmaPermissionRepresentation permission) {
if (permission == null) {
throw new IllegalArgumentException("Permission must not be null");
}
if (permission.getId() == null) {
throw new IllegalArgumentException("Permission id must not be null");
}
Callable<Void> callable = new Callable<Void>() {
@Override
public Void call() throws Exception {
http.<Void>put(serverConfiguration.getPolicyEndpoint() + "/"+ permission.getId())
.authorizationBearer(pat.call())
.json(JsonSerialization.writeValueAsBytes(permission)).execute();
return null;
}
};
try {
callable.call();
} catch (Exception cause) {
Throwables.retryAndWrapExceptionIfNecessary(callable, pat, "Error updating policy for resurce [" + resourceId + "]", cause);
}
}
/**
* Deletes an existing user-managed permission
*
* @param id the permission id
*/
public void delete(final String id) {
Callable<Void> callable = new Callable<Void>() {
@Override
public Void call() {
http.<UmaPermissionRepresentation>delete(serverConfiguration.getPolicyEndpoint() + "/" + id)
.authorizationBearer(pat.call())
.response().execute();
return null;
}
};
try {
callable.call();
} catch (Exception cause) {
Throwables.retryAndWrapExceptionIfNecessary(callable, pat, "Error updating policy for resurce [" + resourceId + "]", cause);
}
}
/**
* Queries the server for permission matching the given parameters.
*
* @param id the permission id
* @param name the name of the permission
* @param scope the scope associated with the permission
* @param firstResult the position of the first resource to retrieve
* @param maxResult the maximum number of resources to retrieve
* @return the permissions matching the given parameters
*/
public List<UmaPermissionRepresentation> find(final String name,
final String scope,
final Integer firstResult,
final Integer maxResult) {
Callable<List<UmaPermissionRepresentation>> callable = new Callable<List<UmaPermissionRepresentation>>() {
@Override
public List<UmaPermissionRepresentation> call() {
return http.<List<UmaPermissionRepresentation>>get(serverConfiguration.getPolicyEndpoint())
.authorizationBearer(pat.call())
.param("name", name)
.param("resource", resourceId)
.param("scope", scope)
.param("first", firstResult == null ? null : firstResult.toString())
.param("max", maxResult == null ? null : maxResult.toString())
.response().json(new TypeReference<List<UmaPermissionRepresentation>>(){}).execute();
}
};
try {
return callable.call();
} catch (Exception cause) {
return Throwables.retryAndWrapExceptionIfNecessary(callable, pat, "Error querying policies for resource [" + resourceId + "]", cause);
}
}
/**
* Queries the server for a permission with the given {@code id}.
*
* @param id the permission id
* @return the permission with the given id
*/
public UmaPermissionRepresentation findById(final String id) {
if (id == null) {
throw new IllegalArgumentException("Permission id must not be null");
}
Callable<UmaPermissionRepresentation> callable = new Callable<UmaPermissionRepresentation>() {
@Override
public UmaPermissionRepresentation call() {
return http.<UmaPermissionRepresentation>get(serverConfiguration.getPolicyEndpoint() + "/" + id)
.authorizationBearer(pat.call())
.response().json(UmaPermissionRepresentation.class).execute();
}
};
try {
return callable.call();
} catch (Exception cause) {
return Throwables.retryAndWrapExceptionIfNecessary(callable, pat, "Error creating policy for resurce [" + resourceId + "]", cause);
}
}
}
@@ -64,6 +64,10 @@ public class ProtectionResource {
return new PermissionResource(http, serverConfiguration, pat);
}
public PolicyResource policy(String resourceId) {
return new PolicyResource(resourceId, http, serverConfiguration, pat);
}
/**
* Introspects the given <code>rpt</code> using the token introspection endpoint.
*
@@ -83,6 +83,7 @@ public class HttpMethodAuthenticator<R> {
method.param("rpt", request.getRpt());
method.param("scope", request.getScope());
method.param("audience", request.getAudience());
method.param("subject_token", request.getSubjectToken());
if (permissions != null) {
for (ResourcePermission permission : permissions.getResources()) {
+1 -1
View File
@@ -25,7 +25,7 @@
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-provider-parent</artifactId>
<version>4.0.0.Beta3-SNAPSHOT</version>
<version>4.0.0.Final</version>
<relativePath>../pom.xml</relativePath>
</parent>
@@ -73,7 +73,7 @@ public class AggregatePolicyProviderFactory implements PolicyProviderFactory<Agg
}
@Override
public AggregatePolicyRepresentation toRepresentation(Policy policy) {
public AggregatePolicyRepresentation toRepresentation(Policy policy, AuthorizationProvider authorization) {
return new AggregatePolicyRepresentation();
}
@@ -1,6 +1,6 @@
package org.keycloak.authorization.policy.provider.client;
import java.util.function.Function;
import java.util.function.BiFunction;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy;
@@ -13,15 +13,15 @@ import org.keycloak.representations.idm.authorization.ClientPolicyRepresentation
public class ClientPolicyProvider implements PolicyProvider {
private final Function<Policy, ClientPolicyRepresentation> representationFunction;
private final BiFunction<Policy, AuthorizationProvider, ClientPolicyRepresentation> representationFunction;
public ClientPolicyProvider(Function<Policy, ClientPolicyRepresentation> representationFunction) {
public ClientPolicyProvider(BiFunction<Policy, AuthorizationProvider, ClientPolicyRepresentation> representationFunction) {
this.representationFunction = representationFunction;
}
@Override
public void evaluate(Evaluation evaluation) {
ClientPolicyRepresentation representation = representationFunction.apply(evaluation.getPolicy());
ClientPolicyRepresentation representation = representationFunction.apply(evaluation.getPolicy(), evaluation.getAuthorizationProvider());
AuthorizationProvider authorizationProvider = evaluation.getAuthorizationProvider();
RealmModel realm = authorizationProvider.getKeycloakSession().getContext().getRealm();
EvaluationContext context = evaluation.getContext();
@@ -30,7 +30,7 @@ import org.keycloak.util.JsonSerialization;
public class ClientPolicyProviderFactory implements PolicyProviderFactory<ClientPolicyRepresentation> {
private ClientPolicyProvider provider = new ClientPolicyProvider(policy -> toRepresentation(policy));
private ClientPolicyProvider provider = new ClientPolicyProvider(this::toRepresentation);
@Override
public String getName() {
@@ -48,7 +48,7 @@ public class ClientPolicyProviderFactory implements PolicyProviderFactory<Client
}
@Override
public ClientPolicyRepresentation toRepresentation(Policy policy) {
public ClientPolicyRepresentation toRepresentation(Policy policy, AuthorizationProvider authorization) {
ClientPolicyRepresentation representation = new ClientPolicyRepresentation();
representation.setClients(new HashSet<>(Arrays.asList(getClients(policy))));
return representation;
@@ -75,12 +75,12 @@ public class ClientPolicyProviderFactory implements PolicyProviderFactory<Client
}
@Override
public void onExport(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorizationProvider) {
ClientPolicyRepresentation userRep = toRepresentation(policy);
public void onExport(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
ClientPolicyRepresentation userRep = toRepresentation(policy, authorization);
Map<String, String> config = new HashMap<>();
try {
RealmModel realm = authorizationProvider.getRealm();
RealmModel realm = authorization.getRealm();
config.put("clients", JsonSerialization.writeValueAsString(userRep.getClients().stream().map(id -> realm.getClientById(id).getClientId()).collect(Collectors.toList())));
} catch (IOException cause) {
throw new RuntimeException("Failed to export user policy [" + policy.getName() + "]", cause);
@@ -18,9 +18,12 @@ package org.keycloak.authorization.policy.provider.group;
import static org.keycloak.models.utils.ModelToRepresentation.buildGroupPath;
import java.util.function.Function;
import java.util.List;
import java.util.function.BiFunction;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.attribute.Attributes;
import org.keycloak.authorization.attribute.Attributes.Entry;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.policy.evaluation.Evaluation;
import org.keycloak.authorization.policy.provider.PolicyProvider;
@@ -33,20 +36,22 @@ import org.keycloak.representations.idm.authorization.GroupPolicyRepresentation;
*/
public class GroupPolicyProvider implements PolicyProvider {
private final Function<Policy, GroupPolicyRepresentation> representationFunction;
private final BiFunction<Policy, AuthorizationProvider, GroupPolicyRepresentation> representationFunction;
public GroupPolicyProvider(Function<Policy, GroupPolicyRepresentation> representationFunction) {
public GroupPolicyProvider(BiFunction<Policy, AuthorizationProvider, GroupPolicyRepresentation> representationFunction) {
this.representationFunction = representationFunction;
}
@Override
public void evaluate(Evaluation evaluation) {
GroupPolicyRepresentation policy = representationFunction.apply(evaluation.getPolicy());
RealmModel realm = evaluation.getAuthorizationProvider().getRealm();
AuthorizationProvider authorizationProvider = evaluation.getAuthorizationProvider();
GroupPolicyRepresentation policy = representationFunction.apply(evaluation.getPolicy(), authorizationProvider);
RealmModel realm = authorizationProvider.getRealm();
Attributes.Entry groupsClaim = evaluation.getContext().getIdentity().getAttributes().getValue(policy.getGroupsClaim());
if (groupsClaim == null || groupsClaim.isEmpty()) {
return;
List<String> userGroups = evaluation.getRealm().getUserGroups(evaluation.getContext().getIdentity().getId());
groupsClaim = new Entry(policy.getGroupsClaim(), userGroups);
}
for (GroupPolicyRepresentation.GroupDefinition definition : policy.getGroups()) {
@@ -43,7 +43,7 @@ import org.keycloak.util.JsonSerialization;
*/
public class GroupPolicyProviderFactory implements PolicyProviderFactory<GroupPolicyRepresentation> {
private GroupPolicyProvider provider = new GroupPolicyProvider(policy -> toRepresentation(policy));
private GroupPolicyProvider provider = new GroupPolicyProvider(this::toRepresentation);
@Override
public String getId() {
@@ -71,7 +71,7 @@ public class GroupPolicyProviderFactory implements PolicyProviderFactory<GroupPo
}
@Override
public GroupPolicyRepresentation toRepresentation(Policy policy) {
public GroupPolicyRepresentation toRepresentation(Policy policy, AuthorizationProvider authorization) {
GroupPolicyRepresentation representation = new GroupPolicyRepresentation();
representation.setGroupsClaim(policy.getConfig().get("groupsClaim"));
@@ -109,19 +109,24 @@ public class GroupPolicyProviderFactory implements PolicyProviderFactory<GroupPo
}
@Override
public void onExport(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorizationProvider) {
public void onExport(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
Map<String, String> config = new HashMap<>();
GroupPolicyRepresentation groupPolicy = toRepresentation(policy);
GroupPolicyRepresentation groupPolicy = toRepresentation(policy, authorization);
Set<GroupPolicyRepresentation.GroupDefinition> groups = groupPolicy.getGroups();
for (GroupPolicyRepresentation.GroupDefinition definition: groups) {
GroupModel group = authorizationProvider.getRealm().getGroupById(definition.getId());
GroupModel group = authorization.getRealm().getGroupById(definition.getId());
definition.setId(null);
definition.setPath(ModelToRepresentation.buildGroupPath(group));
}
try {
config.put("groupsClaim", groupPolicy.getGroupsClaim());
String groupsClaim = groupPolicy.getGroupsClaim();
if (groupsClaim != null) {
config.put("groupsClaim", groupsClaim);
}
config.put("groups", JsonSerialization.writeValueAsString(groups));
} catch (IOException cause) {
throw new RuntimeException("Failed to export group policy [" + policy.getName() + "]", cause);
@@ -147,17 +152,15 @@ public class GroupPolicyProviderFactory implements PolicyProviderFactory<GroupPo
}
private void updatePolicy(Policy policy, String groupsClaim, Set<GroupPolicyRepresentation.GroupDefinition> groups, AuthorizationProvider authorization) {
if (groupsClaim == null) {
throw new RuntimeException("Group claims property not provided");
}
if (groups == null || groups.isEmpty()) {
throw new RuntimeException("You must provide at least one group");
}
Map<String, String> config = new HashMap<>(policy.getConfig());
config.put("groupsClaim", groupsClaim);
if (groupsClaim != null) {
config.put("groupsClaim", groupsClaim);
}
List<GroupModel> topLevelGroups = authorization.getRealm().getTopLevelGroups();
Loaded 100 of 1045 files, more files were not shown because too many files have changed in this diff. Show more