Merge pull request #2617 from pedroigor/KEYCLOAK-2753

[KEYCLOAK-2753] - Fine-grained Authorization Services
This commit is contained in:
Stian Thorgersen 2016-06-17 13:40:15 +02:00 committed by GitHub
commit 3c0f7e2ee2
387 changed files with 27499 additions and 96 deletions

View file

@ -65,6 +65,11 @@
<artifactId>keycloak-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-client</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>

View file

@ -18,10 +18,12 @@
package org.keycloak.adapters;
import org.jboss.logging.Logger;
import org.keycloak.AuthorizationContext;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.authorization.PolicyEnforcer;
import org.keycloak.common.util.UriUtils;
import org.keycloak.constants.AdapterConstants;
import org.keycloak.representations.AccessToken;
import org.keycloak.common.util.UriUtils;
import java.io.IOException;
import java.util.Set;
@ -55,6 +57,9 @@ public class AuthenticatedActionsHandler {
queryBearerToken();
return true;
}
if (!isAuthorized()) {
return true;
}
return false;
}
@ -124,4 +129,24 @@ public class AuthenticatedActionsHandler {
}
return false;
}
private boolean isAuthorized() {
PolicyEnforcer policyEnforcer = this.deployment.getPolicyEnforcer();
if (policyEnforcer == null) {
log.debugv("Policy enforcement is disabled.");
return true;
}
try {
OIDCHttpFacade facade = (OIDCHttpFacade) this.facade;
AuthorizationContext authorizationContext = policyEnforcer.enforce(facade);
RefreshableKeycloakSecurityContext session = (RefreshableKeycloakSecurityContext) facade.getSecurityContext();
session.setAuthorizationContext(authorizationContext);
return authorizationContext.isGranted();
} catch (Exception e) {
throw new RuntimeException("Failed to enforce policy decisions.", e);
}
}
}

View file

@ -20,6 +20,7 @@ package org.keycloak.adapters;
import org.apache.http.client.HttpClient;
import org.jboss.logging.Logger;
import org.keycloak.adapters.authentication.ClientCredentialsProvider;
import org.keycloak.adapters.authorization.PolicyEnforcer;
import org.keycloak.constants.ServiceUrlConstants;
import org.keycloak.common.enums.RelativeUrlsUsed;
import org.keycloak.common.enums.SslRequired;
@ -78,6 +79,7 @@ public class KeycloakDeployment {
protected volatile int notBefore;
protected int tokenMinimumTimeToLive;
private PolicyEnforcer policyEnforcer;
public KeycloakDeployment() {
}
@ -366,4 +368,12 @@ public class KeycloakDeployment {
public void setTokenMinimumTimeToLive(final int tokenMinimumTimeToLive) {
this.tokenMinimumTimeToLive = tokenMinimumTimeToLive;
}
public void setPolicyEnforcer(PolicyEnforcer policyEnforcer) {
this.policyEnforcer = policyEnforcer;
}
public PolicyEnforcer getPolicyEnforcer() {
return policyEnforcer;
}
}

View file

@ -21,10 +21,12 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.jboss.logging.Logger;
import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
import org.keycloak.adapters.authorization.PolicyEnforcer;
import org.keycloak.common.enums.SslRequired;
import org.keycloak.common.util.PemUtils;
import org.keycloak.enums.TokenStore;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.keycloak.common.util.PemUtils;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
import org.keycloak.util.SystemPropertiesJsonParserFactory;
import java.io.IOException;
@ -110,6 +112,12 @@ public class KeycloakDeploymentBuilder {
deployment.setTurnOffChangeSessionIdOnLogin(adapterConfig.getTurnOffChangeSessionIdOnLogin());
}
PolicyEnforcerConfig policyEnforcerConfig = adapterConfig.getPolicyEnforcerConfig();
if (policyEnforcerConfig != null) {
deployment.setPolicyEnforcer(new PolicyEnforcer(deployment, adapterConfig));
}
log.debug("Use authServerUrl: " + deployment.getAuthServerBaseUrl() + ", tokenUrl: " + deployment.getTokenUrl() + ", relativeUrls: " + deployment.getRelativeUrls());
return deployment;
}

View file

@ -18,6 +18,7 @@
package org.keycloak.adapters;
import org.jboss.logging.Logger;
import org.keycloak.AuthorizationContext;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.RSATokenVerifier;
import org.keycloak.common.VerificationException;
@ -157,4 +158,8 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext
tokenStore.refreshCallback(this);
return true;
}
public void setAuthorizationContext(AuthorizationContext authorizationContext) {
this.authorizationContext = authorizationContext;
}
}

View file

@ -0,0 +1,243 @@
/*
* 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.authorization;
import org.jboss.logging.Logger;
import org.keycloak.AuthorizationContext;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.adapters.spi.HttpFacade.Request;
import org.keycloak.adapters.spi.HttpFacade.Response;
import org.keycloak.authorization.client.AuthzClient;
import org.keycloak.authorization.client.representation.ResourceRepresentation;
import org.keycloak.authorization.client.resource.ProtectedResource;
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.PathConfig;
import org.keycloak.representations.authorization.Permission;
import java.net.URI;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public abstract class AbstractPolicyEnforcer {
private static Logger LOGGER = Logger.getLogger(AbstractPolicyEnforcer.class);
private final PolicyEnforcerConfig enforcerConfig;
private final PolicyEnforcer policyEnforcer;
private List<PathConfig> paths;
private AuthzClient authzClient;
private PathMatcher pathMatcher;
public AbstractPolicyEnforcer(PolicyEnforcer policyEnforcer) {
this.policyEnforcer = policyEnforcer;
this.enforcerConfig = policyEnforcer.getEnforcerConfig();
this.authzClient = policyEnforcer.getClient();
this.pathMatcher = new PathMatcher();
this.paths = policyEnforcer.getPaths();
}
public AuthorizationContext authorize(OIDCHttpFacade httpFacade) {
EnforcementMode enforcementMode = this.enforcerConfig.getEnforcementMode();
if (EnforcementMode.DISABLED.equals(enforcementMode)) {
return createEmptyAuthorizationContext(true);
}
AccessToken accessToken = httpFacade.getSecurityContext().getToken();
Request request = httpFacade.getRequest();
Response response = httpFacade.getResponse();
String pathInfo = URI.create(request.getURI()).getPath().substring(1);
String path = pathInfo.substring(pathInfo.indexOf('/'), pathInfo.length());
PathConfig pathConfig = this.pathMatcher.matches(path, this.paths);
LOGGER.debugf("Checking permissions for path [%s] with config [%s].", request.getURI(), pathConfig);
if (pathConfig == null) {
if (EnforcementMode.PERMISSIVE.equals(enforcementMode)) {
return createAuthorizationContext(accessToken);
}
LOGGER.debugf("Could not find a configuration for path [%s]", path);
response.sendError(403, "Could not find a configuration for path [" + path + "].");
return createEmptyAuthorizationContext(false);
}
PathConfig actualPathConfig = resolvePathConfig(pathConfig, request);
Set<String> requiredScopes = getRequiredScopes(actualPathConfig, request);
if (isAuthorized(actualPathConfig, requiredScopes, accessToken, httpFacade)) {
try {
return createAuthorizationContext(accessToken);
} catch (Exception e) {
throw new RuntimeException("Error processing path [" + actualPathConfig.getPath() + "].", e);
}
}
if (!challenge(actualPathConfig, requiredScopes, httpFacade)) {
LOGGER.debugf("Sending challenge to the client. Path [%s]", pathConfig);
response.sendError(403, "Authorization failed.");
}
return createEmptyAuthorizationContext(false);
}
protected abstract boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade);
protected boolean isAuthorized(PathConfig actualPathConfig, Set<String> requiredScopes, AccessToken accessToken, OIDCHttpFacade httpFacade) {
Request request = httpFacade.getRequest();
PolicyEnforcerConfig enforcerConfig = getEnforcerConfig();
String accessDeniedPath = enforcerConfig.getAccessDeniedPath();
if (accessDeniedPath != null) {
if (request.getURI().contains(accessDeniedPath)) {
return true;
}
}
AccessToken.Authorization authorization = accessToken.getAuthorization();
if (authorization == null) {
return false;
}
List<Permission> permissions = authorization.getPermissions();
for (Permission permission : permissions) {
Set<String> allowedScopes = permission.getScopes();
if (permission.getResourceSetId() != null) {
if (permission.getResourceSetId().equals(actualPathConfig.getId())) {
if (((allowedScopes == null || allowedScopes.isEmpty()) && requiredScopes.isEmpty()) || allowedScopes.containsAll(requiredScopes)) {
LOGGER.debugf("Authorization GRANTED for path [%s]. Permissions [%s].", actualPathConfig, permissions);
if (request.getMethod().equalsIgnoreCase("DELETE") && actualPathConfig.isInstance()) {
this.paths.remove(actualPathConfig);
}
return true;
}
}
} else {
if ((allowedScopes.isEmpty() && requiredScopes.isEmpty()) || allowedScopes.containsAll(requiredScopes)) {
LOGGER.debugf("Authorization GRANTED for path [%s]. Permissions [%s].", actualPathConfig, permissions);
return true;
}
}
}
LOGGER.debugf("Authorization FAILED for path [%s]. No enough permissions [%s].", actualPathConfig, permissions);
return false;
}
protected AuthzClient getAuthzClient() {
return this.authzClient;
}
protected PolicyEnforcerConfig getEnforcerConfig() {
return enforcerConfig;
}
protected PolicyEnforcer getPolicyEnforcer() {
return policyEnforcer;
}
private AuthorizationContext createEmptyAuthorizationContext(final boolean granted) {
return new AuthorizationContext() {
@Override
public boolean hasPermission(String resourceName, String scopeName) {
return granted;
}
@Override
public boolean hasResourcePermission(String resourceName) {
return granted;
}
@Override
public boolean hasScopePermission(String scopeName) {
return granted;
}
@Override
public List<Permission> getPermissions() {
return Collections.EMPTY_LIST;
}
@Override
public boolean isGranted() {
return granted;
}
};
}
private PathConfig resolvePathConfig(PathConfig originalConfig, Request request) {
if (originalConfig.hasPattern()) {
String pathInfo = URI.create(request.getURI()).getPath().substring(1);
String path = pathInfo.substring(pathInfo.indexOf('/'), pathInfo.length());
ProtectedResource resource = this.authzClient.protection().resource();
Set<String> search = resource.findByFilter("uri=" + path);
if (!search.isEmpty()) {
// resource does exist on the server, cache it
ResourceRepresentation targetResource = resource.findById(search.iterator().next()).getResourceDescription();
PathConfig config = new PathConfig();
config.setId(targetResource.getId());
config.setName(targetResource.getName());
config.setType(targetResource.getType());
config.setPath(targetResource.getUri());
config.setScopes(originalConfig.getScopes());
config.setMethods(originalConfig.getMethods());
config.setInstance(true);
this.paths.add(config);
return config;
}
}
return originalConfig;
}
private Set<String> getRequiredScopes(PathConfig pathConfig, Request request) {
Set<String> requiredScopes = new HashSet<>();
requiredScopes.addAll(pathConfig.getScopes());
String method = request.getMethod();
for (PolicyEnforcerConfig.MethodConfig methodConfig : pathConfig.getMethods()) {
if (methodConfig.getMethod().equals(method)) {
requiredScopes.addAll(methodConfig.getScopes());
}
}
return requiredScopes;
}
private AuthorizationContext createAuthorizationContext(AccessToken accessToken) {
return new AuthorizationContext(accessToken, this.paths);
}
}

View file

@ -0,0 +1,80 @@
/*
* 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.authorization;
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.PathConfig;
import java.util.List;
import java.util.Set;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class BearerTokenPolicyEnforcer extends AbstractPolicyEnforcer {
private static Logger LOGGER = Logger.getLogger(BearerTokenPolicyEnforcer.class);
public BearerTokenPolicyEnforcer(PolicyEnforcer enforcer) {
super(enforcer);
}
@Override
protected boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
if (getEnforcerConfig().getUmaProtocolConfig() != null) {
challengeUmaAuthentication(pathConfig, requiredScopes, facade);
} else {
challengeEntitlementAuthentication(facade);
}
return true;
}
private void challengeEntitlementAuthentication(OIDCHttpFacade facade) {
HttpFacade.Response response = facade.getResponse();
AuthzClient authzClient = getAuthzClient();
String clientId = authzClient.getConfiguration().getClientId();
String authorizationServerUri = authzClient.getServerConfiguration().getIssuer().toString() + "/authz/entitlement";
response.setStatus(401);
response.setHeader("WWW-Authenticate", "KC_ETT realm=\"" + clientId + "\",as_uri=\"" + authorizationServerUri + "\"");
}
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().getClientId();
String authorizationServerUri = authzClient.getServerConfiguration().getIssuer().toString() + "/authz/authorize";
response.setStatus(401);
response.setHeader("WWW-Authenticate", "UMA realm=\"" + clientId + "\",as_uri=\"" + authorizationServerUri + "\",ticket=\"" + ticket + "\"");
}
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();
}
}

View file

@ -0,0 +1,119 @@
/*
* 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.authorization;
import org.jboss.logging.Logger;
import org.keycloak.RSATokenVerifier;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.OIDCHttpFacade;
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.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.PathConfig;
import java.util.Set;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
private static Logger LOGGER = Logger.getLogger(KeycloakAdapterPolicyEnforcer.class);
public KeycloakAdapterPolicyEnforcer(PolicyEnforcer policyEnforcer) {
super(policyEnforcer);
}
@Override
protected boolean isAuthorized(PathConfig pathConfig, Set<String> requiredScopes, AccessToken accessToken, OIDCHttpFacade httpFacade) {
int retry = 2;
AccessToken original = accessToken;
while (retry >= 0) {
if (super.isAuthorized(pathConfig, requiredScopes, accessToken, httpFacade)) {
original.setAuthorization(accessToken.getAuthorization());
return true;
}
accessToken = requestAuthorizationToken(pathConfig, requiredScopes, httpFacade);
if (accessToken == null) {
return false;
}
retry--;
}
return false;
}
@Override
protected boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
String accessDeniedPath = getEnforcerConfig().getAccessDeniedPath();
HttpFacade.Response response = facade.getResponse();
if (accessDeniedPath != null) {
response.setStatus(302);
response.setHeader("Location", accessDeniedPath);
} else {
response.sendError(403);
}
return true;
}
private AccessToken requestAuthorizationToken(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade httpFacade) {
try {
String accessToken = httpFacade.getSecurityContext().getTokenString();
AuthzClient authzClient = getAuthzClient();
KeycloakDeployment deployment = getPolicyEnforcer().getDeployment();
if (getEnforcerConfig().getUmaProtocolConfig() != null) {
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 RSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment.getRealmKey(), deployment.getRealmInfoUrl());
}
return null;
} else {
LOGGER.debug("Obtaining entitlements for authenticated user.");
EntitlementResponse authzResponse = authzClient.entitlement(accessToken).getAll(authzClient.getConfiguration().getClientId());
return RSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment.getRealmKey(), deployment.getRealmInfoUrl());
}
} catch (AuthorizationDeniedException e) {
return null;
} catch (Exception e) {
throw new RuntimeException("Unexpected error during authorization request.", e);
}
}
}

View file

@ -0,0 +1,103 @@
/*
* 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.authorization;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
import java.util.List;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
class PathMatcher {
private static final String ANY_RESOURCE_PATTERN = "/*";
PathConfig matches(final String requestedUri, List<PathConfig> paths) {
PathConfig actualConfig = null;
for (PathConfig entry : paths) {
String protectedUri = entry.getPath();
String selectedUri = null;
if (protectedUri.equals(ANY_RESOURCE_PATTERN) && actualConfig == null) {
selectedUri = protectedUri;
}
int suffixIndex = protectedUri.indexOf(ANY_RESOURCE_PATTERN + ".");
if (suffixIndex != -1) {
String protectedSuffix = protectedUri.substring(suffixIndex + ANY_RESOURCE_PATTERN.length());
if (requestedUri.endsWith(protectedSuffix)) {
selectedUri = protectedUri;
}
}
if (protectedUri.equals(requestedUri)) {
selectedUri = protectedUri;
}
if (protectedUri.endsWith(ANY_RESOURCE_PATTERN)) {
String formattedPattern = removeWildCardsFromUri(protectedUri);
if (!formattedPattern.equals("/") && requestedUri.startsWith(formattedPattern)) {
selectedUri = protectedUri;
}
if (!formattedPattern.equals("/") && formattedPattern.endsWith("/") && formattedPattern.substring(0, formattedPattern.length() - 1).equals(requestedUri)) {
selectedUri = protectedUri;
}
}
int startRegex = protectedUri.indexOf('{');
if (startRegex != -1) {
String prefix = protectedUri.substring(0, startRegex);
if (requestedUri.startsWith(prefix)) {
selectedUri = protectedUri;
}
}
if (selectedUri != null) {
selectedUri = protectedUri;
}
if (selectedUri != null) {
if (actualConfig == null) {
actualConfig = entry;
} else {
if (actualConfig.equals(ANY_RESOURCE_PATTERN)) {
actualConfig = entry;
}
if (protectedUri.startsWith(removeWildCardsFromUri(actualConfig.getPath()))) {
actualConfig = entry;
}
}
}
}
return actualConfig;
}
private String removeWildCardsFromUri(String protectedUri) {
return protectedUri.replaceAll("/[*]", "/");
}
}

View file

@ -0,0 +1,205 @@
/*
* 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.authorization;
import org.jboss.logging.Logger;
import org.keycloak.AuthorizationContext;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.authorization.client.AuthzClient;
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;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
import org.keycloak.representations.authorization.Permission;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class PolicyEnforcer {
private static Logger LOGGER = Logger.getLogger(PolicyEnforcer.class);
private final KeycloakDeployment deployment;
private final PathMatcher pathMatcher;
private final AuthzClient authzClient;
private final PolicyEnforcerConfig enforcerConfig;
private final List<PathConfig> paths;
public PolicyEnforcer(KeycloakDeployment deployment, AdapterConfig adapterConfig) {
this.deployment = deployment;
this.enforcerConfig = adapterConfig.getPolicyEnforcerConfig();
this.authzClient = AuthzClient.create(new Configuration(adapterConfig.getAuthServerUrl(), adapterConfig.getRealm(), adapterConfig.getResource(), adapterConfig.getCredentials(), deployment.getClient()));
this.pathMatcher = new PathMatcher();
this.paths = configurePaths(this.authzClient.protection().resource(), this.enforcerConfig);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Initialization complete. Path configurations:");
for (PathConfig pathConfig : this.paths) {
LOGGER.debug(pathConfig);
}
}
}
public AuthorizationContext enforce(OIDCHttpFacade facade) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debugv("Policy enforcement is enable. Enforcing policy decisions for path [{0}].", facade.getRequest().getURI());
}
AuthorizationContext context;
if (deployment.isBearerOnly()) {
context = new BearerTokenPolicyEnforcer(this).authorize(facade);
} else {
context = new KeycloakAdapterPolicyEnforcer(this).authorize(facade);
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debugv("Policy enforcement result for path [{0}] is : {1}", facade.getRequest().getURI(), context.isGranted() ? "GRANTED" : "DENIED");
LOGGER.debugv("Returning authorization context with permissions:");
for (Permission permission : context.getPermissions()) {
LOGGER.debug(permission);
}
}
return context;
}
PolicyEnforcerConfig getEnforcerConfig() {
return enforcerConfig;
}
AuthzClient getClient() {
return authzClient;
}
List<PathConfig> getPaths() {
return paths;
}
KeycloakDeployment getDeployment() {
return deployment;
}
private List<PathConfig> configurePaths(ProtectedResource protectedResource, PolicyEnforcerConfig enforcerConfig) {
if (enforcerConfig.getPaths().isEmpty()) {
LOGGER.info("No path provided in configuration.");
return configureAllPathsForResourceServer(protectedResource);
} else {
LOGGER.info("Paths provided in configuration.");
return configureDefinedPaths(protectedResource, enforcerConfig);
}
}
private List<PathConfig> configureDefinedPaths(ProtectedResource protectedResource, PolicyEnforcerConfig enforcerConfig) {
List<PathConfig> paths = new ArrayList<>();
for (PathConfig pathConfig : enforcerConfig.getPaths()) {
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);
search = protectedResource.findByFilter("name=" + resourceName);
} else {
LOGGER.debugf("Trying to find resource with uri [%s] for path [%s].", path, path);
search = protectedResource.findByFilter("uri=" + path);
}
if (search.isEmpty()) {
if (enforcerConfig.isCreateResources()) {
LOGGER.debugf("Creating resource on server for path [%s].", pathConfig);
ResourceRepresentation resource = new ResourceRepresentation();
resource.setName(resourceName);
resource.setType(pathConfig.getType());
resource.setUri(path);
HashSet<ScopeRepresentation> scopes = new HashSet<>();
for (String scopeName : pathConfig.getScopes()) {
ScopeRepresentation scope = new ScopeRepresentation();
scope.setName(scopeName);
scopes.add(scope);
}
resource.setScopes(scopes);
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(search.iterator().next());
}
paths.add(pathConfig);
}
return paths;
}
private List<PathConfig> configureAllPathsForResourceServer(ProtectedResource protectedResource) {
LOGGER.info("Querying the server for all resources associated with this application.");
List<PathConfig> paths = new ArrayList<>();
for (String id : protectedResource.findAll()) {
RegistrationResponse response = protectedResource.findById(id);
ResourceRepresentation resourceDescription = response.getResourceDescription();
if (resourceDescription.getUri() != null) {
paths.add(createPathConfig(resourceDescription));
}
}
return paths;
}
private PathConfig createPathConfig(ResourceRepresentation resourceDescription) {
PathConfig pathConfig = new PathConfig();
pathConfig.setId(resourceDescription.getId());
pathConfig.setName(resourceDescription.getName());
pathConfig.setPath(resourceDescription.getUri());
List<String> scopeNames = new ArrayList<>();
for (ScopeRepresentation scope : resourceDescription.getScopes()) {
scopeNames.add(scope.getName());
}
pathConfig.setScopes(scopeNames);
pathConfig.setType(resourceDescription.getType());
return pathConfig;
}
}

View file

@ -17,16 +17,16 @@
package org.keycloak.adapters.undertow;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.AttachmentKey;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.OIDCHttpFacade;
import static org.keycloak.adapters.undertow.OIDCUndertowHttpFacade.KEYCLOAK_SECURITY_CONTEXT_KEY;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class OIDCServletUndertowHttpFacade extends ServletHttpFacade implements OIDCHttpFacade {
public static final AttachmentKey<KeycloakSecurityContext> KEYCLOAK_SECURITY_CONTEXT_KEY = AttachmentKey.create(KeycloakSecurityContext.class);
public OIDCServletUndertowHttpFacade(HttpServerExchange exchange) {
super(exchange);

53
authz/client/pom.xml Normal file
View file

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-parent</artifactId>
<version>2.0.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>keycloak-authz-client</artifactId>
<packaging>jar</packaging>
<name>KeyCloak Authz: Client API</name>
<description>KeyCloak AuthZ: Client API</description>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>${jboss.logging.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,29 @@
/*
* 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.authorization.client;
import org.keycloak.authorization.client.util.HttpResponseException;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class AuthorizationDeniedException extends RuntimeException {
public AuthorizationDeniedException(Throwable cause) {
super(cause);
}
}

View file

@ -0,0 +1,131 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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;
import org.keycloak.authorization.client.representation.ServerConfiguration;
import org.keycloak.authorization.client.resource.AuthorizationResource;
import org.keycloak.authorization.client.resource.EntitlementResource;
import org.keycloak.authorization.client.resource.ProtectionResource;
import org.keycloak.authorization.client.util.Http;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.util.JsonSerialization;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
/**
* <p>This is class serves as an entry point for clients looking for access to Keycloak Authorization Services.
*
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class AuthzClient {
private final Http http;
public static AuthzClient create() {
InputStream configStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("keycloak.json");
if (configStream == null) {
throw new RuntimeException("Could not find any keycloak.json file in classpath.");
}
try {
return create(JsonSerialization.readValue(configStream, Configuration.class));
} catch (IOException e) {
throw new RuntimeException("Could not parse configuration.", e);
}
}
public static AuthzClient create(Configuration configuration) {
return new AuthzClient(configuration);
}
private final ServerConfiguration serverConfiguration;
private final Configuration deployment;
private AuthzClient(Configuration configuration) {
if (configuration == null) {
throw new IllegalArgumentException("Client configuration can not be null.");
}
String configurationUrl = configuration.getAuthServerUrl();
if (configurationUrl == null) {
throw new IllegalArgumentException("Configuration URL can not be null.");
}
configurationUrl += "/realms/" + configuration.getRealm() + "/.well-known/uma-configuration";
this.http = new Http(configuration);
try {
this.serverConfiguration = this.http.<ServerConfiguration>get(URI.create(configurationUrl))
.response().json(ServerConfiguration.class)
.execute();
} catch (Exception e) {
throw new RuntimeException("Could not obtain configuration from server [" + configurationUrl + "].", e);
}
this.http.setServerConfiguration(this.serverConfiguration);
this.deployment = configuration;
}
public ProtectionResource protection() {
return new ProtectionResource(this.http, obtainAccessToken().getToken());
}
public AuthorizationResource authorization(String accesstoken) {
return new AuthorizationResource(this.http, accesstoken);
}
public AuthorizationResource authorization(String userName, String password) {
return new AuthorizationResource(this.http, obtainAccessToken(userName, password).getToken());
}
public EntitlementResource entitlement(String eat) {
return new EntitlementResource(this.http, eat);
}
public AccessTokenResponse obtainAccessToken() {
return this.http.<AccessTokenResponse>post(this.serverConfiguration.getTokenEndpoint())
.authentication()
.oauth2ClientCredentials()
.response()
.json(AccessTokenResponse.class)
.execute();
}
public AccessTokenResponse obtainAccessToken(String userName, String password) {
return this.http.<AccessTokenResponse>post(this.serverConfiguration.getTokenEndpoint())
.authentication()
.oauth2ResourceOwnerPassword(userName, password)
.response()
.json(AccessTokenResponse.class)
.execute();
}
public ServerConfiguration getServerConfiguration() {
return this.serverConfiguration;
}
public Configuration getConfiguration() {
return this.deployment;
}
}

View file

@ -0,0 +1,27 @@
/*
* 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.authorization.client;
import java.util.HashMap;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public interface ClientAuthenticator {
void configureClientCredentials(HashMap<String, String> requestParams, HashMap<String, String> requestHeaders);
}

View file

@ -0,0 +1,102 @@
/*
* 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.authorization.client;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClients;
import org.keycloak.util.BasicAuthHelper;
import java.util.HashMap;
import java.util.Map;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class Configuration {
@JsonIgnore
private HttpClient httpClient;
@JsonProperty("auth-server-url")
protected String authServerUrl;
@JsonProperty("realm")
protected String realm;
@JsonProperty("resource")
protected String clientId;
@JsonProperty("credentials")
protected Map<String, Object> clientCredentials = new HashMap<>();
public Configuration() {
}
public Configuration(String authServerUrl, String realm, String clientId, Map<String, Object> clientCredentials, HttpClient httpClient) {
this.authServerUrl = authServerUrl;
this.realm = realm;
this.clientId = clientId;
this.clientCredentials = clientCredentials;
this.httpClient = httpClient;
}
@JsonIgnore
private ClientAuthenticator clientAuthenticator = new ClientAuthenticator() {
@Override
public void configureClientCredentials(HashMap<String, String> requestParams, HashMap<String, String> requestHeaders) {
String secret = (String) clientCredentials.get("secret");
if (secret == null) {
throw new RuntimeException("Client secret not provided.");
}
requestHeaders.put("Authorization", BasicAuthHelper.createHeader(clientId, secret));
}
};
public HttpClient getHttpClient() {
if (this.httpClient == null) {
this.httpClient = HttpClients.createDefault();
}
return httpClient;
}
public String getClientId() {
return clientId;
}
public String getAuthServerUrl() {
return authServerUrl;
}
public ClientAuthenticator getClientAuthenticator() {
return this.clientAuthenticator;
}
public Map<String, Object> getClientCredentials() {
return clientCredentials;
}
public String getRealm() {
return realm;
}
}

View file

@ -0,0 +1,48 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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.representation;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class AuthorizationRequest {
private String ticket;
private String rpt;
public AuthorizationRequest(String ticket, String rpt) {
this.ticket = ticket;
this.rpt = rpt;
}
public AuthorizationRequest(String ticket) {
this(ticket, null);
}
public AuthorizationRequest() {
this(null, null);
}
public String getTicket() {
return this.ticket;
}
public String getRpt() {
return this.rpt;
}
}

View file

@ -0,0 +1,42 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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.representation;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class AuthorizationResponse {
private String rpt;
public AuthorizationResponse(String rpt) {
this.rpt = rpt;
}
public AuthorizationResponse() {
this(null);
}
public String getRpt() {
return this.rpt;
}
public void setRpt(final String rpt) {
this.rpt = rpt;
}
}

View file

@ -0,0 +1,34 @@
package org.keycloak.authorization.client.representation;
import java.util.ArrayList;
import java.util.List;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class EntitlementRequest {
private String rpt;
private List<PermissionRequest> permissions = new ArrayList<>();
public List<PermissionRequest> getPermissions() {
return permissions;
}
public String getRpt() {
return rpt;
}
public void setRpt(String rpt) {
this.rpt = rpt;
}
public void setPermissions(List<PermissionRequest> permissions) {
this.permissions = permissions;
}
public void addPermission(PermissionRequest request) {
getPermissions().add(request);
}
}

View file

@ -0,0 +1,42 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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.representation;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class EntitlementResponse {
private String rpt;
public EntitlementResponse(String rpt) {
this.rpt = rpt;
}
public EntitlementResponse() {
this(null);
}
public String getRpt() {
return this.rpt;
}
public void setRpt(final String rpt) {
this.rpt = rpt;
}
}

View file

@ -0,0 +1,60 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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.representation;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class ErrorResponse {
private String error;
@JsonProperty("error_description")
private String description;
@JsonProperty("error_uri")
private String uri;
public ErrorResponse(final String error, final String description, final String uri) {
this.error = error;
this.description = description;
this.uri = uri;
}
public ErrorResponse(final String error) {
this(error, null, null);
}
public ErrorResponse() {
this(null, null, null);
}
public String getError() {
return this.error;
}
public String getDescription() {
return this.description;
}
public String getUri() {
return this.uri;
}
}

View file

@ -0,0 +1,62 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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.representation;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class PermissionRequest {
@JsonProperty("resource_set_id")
private String resourceSetId;
@JsonProperty("resource_set_name")
private String resourceSetName;
private Set<String> scopes;
public String getResourceSetId() {
return this.resourceSetId;
}
public void setResourceSetId(String resourceSetId) {
this.resourceSetId = resourceSetId;
}
public Set<String> getScopes() {
return this.scopes;
}
public void setScopes(Set<String> scopes) {
this.scopes = scopes;
}
public String getResourceSetName() {
return this.resourceSetName;
}
public void setResourceSetName(String resourceSetName) {
this.resourceSetName = resourceSetName;
}
}

View file

@ -0,0 +1,38 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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.representation;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class PermissionResponse {
private final String ticket;
public PermissionResponse(String ticket) {
this.ticket = ticket;
}
public PermissionResponse() {
this(null);
}
public String getTicket() {
return this.ticket;
}
}

View file

@ -0,0 +1,49 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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.representation;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class RegistrationResponse {
private final ResourceRepresentation resourceDescription;
public RegistrationResponse(ResourceRepresentation resourceDescription) {
this.resourceDescription = resourceDescription;
}
public RegistrationResponse() {
this(null);
}
@JsonUnwrapped
public ResourceRepresentation getResourceDescription() {
return this.resourceDescription;
}
public String getId() {
if (this.resourceDescription != null) {
return this.resourceDescription.getId();
}
return null;
}
}

View file

@ -0,0 +1,184 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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.representation;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.net.URI;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
/**
* <p>One or more resources that the resource server manages as a set of protected resources.
*
* <p>For more details, <a href="https://docs.kantarainitiative.org/uma/draft-oauth-resource-reg.html#rfc.section.2.2">OAuth-resource-reg</a>.
*
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class ResourceRepresentation {
@JsonProperty("_id")
private String id;
private String name;
private String uri;
private String type;
private Set<ScopeRepresentation> scopes;
@JsonProperty("icon_uri")
private String iconUri;
private String owner;
/**
* Creates a new instance.
*
* @param name a human-readable string describing a set of one or more resources
* @param uri a {@link URI} that provides the network location for the resource set being registered
* @param type a string uniquely identifying the semantics of the resource set
* @param scopes the available scopes for this resource set
* @param iconUri a {@link URI} for a graphic icon representing the resource set
*/
public ResourceRepresentation(String name, Set<ScopeRepresentation> scopes, String uri, String type, String iconUri) {
this.name = name;
this.scopes = scopes;
this.uri = uri;
this.type = type;
this.iconUri = iconUri;
}
/**
* Creates a new instance.
*
* @param name a human-readable string describing a set of one or more resources
* @param uri a {@link URI} that provides the network location for the resource set being registered
* @param type a string uniquely identifying the semantics of the resource set
* @param scopes the available scopes for this resource set
*/
public ResourceRepresentation(String name, Set<ScopeRepresentation> scopes, String uri, String type) {
this(name, scopes, uri, type, null);
}
/**
* Creates a new instance.
*
* @param name a human-readable string describing a set of one or more resources
* @param serverUri a {@link URI} that identifies this resource server
* @param scopes the available scopes for this resource set
*/
public ResourceRepresentation(String name, Set<ScopeRepresentation> scopes) {
this(name, scopes, null, null, null);
}
/**
* Creates a new instance.
*
*/
public ResourceRepresentation() {
this(null, null, null, null, null);
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return this.id;
}
public String getName() {
return this.name;
}
public String getUri() {
return this.uri;
}
public String getType() {
return this.type;
}
public Set<ScopeRepresentation> getScopes() {
return Collections.unmodifiableSet(this.scopes);
}
public String getIconUri() {
return this.iconUri;
}
public void setName(String name) {
this.name = name;
}
public void setUri(String uri) {
this.uri = uri;
}
public void setType(String type) {
this.type = type;
}
public void setScopes(Set<ScopeRepresentation> scopes) {
this.scopes = scopes;
}
public void setIconUri(String iconUri) {
this.iconUri = iconUri;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public void addScope(ScopeRepresentation scopeRepresentation) {
if (this.scopes == null) {
this.scopes = new HashSet<>();
}
this.scopes.add(scopeRepresentation);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ResourceRepresentation that = (ResourceRepresentation) o;
return Objects.equals(id, that.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
@Override
public String toString() {
return "ResourceRepresentation{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", uri='" + uri + '\'' +
", type='" + type + '\'' +
", owner='" + owner + '\'' +
", scopes=" + scopes +
'}';
}
}

View file

@ -0,0 +1,98 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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.representation;
import java.net.URI;
import java.util.Objects;
/**
* <p>A bounded extent of access that is possible to perform on a resource set. In authorization policy terminology,
* a scope is one of the potentially many "verbs" that can logically apply to a resource set ("object").
*
* <p>For more details, <a href="https://docs.kantarainitiative.org/uma/draft-oauth-resource-reg.html#rfc.section.2.1">OAuth-resource-reg</a>.
*
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class ScopeRepresentation {
private String id;
private String name;
private String iconUri;
/**
* Creates an instance.
*
* @param name the a human-readable string describing some scope (extent) of access
* @param iconUri a {@link URI} for a graphic icon representing the scope
*/
public ScopeRepresentation(String name, String iconUri) {
this.name = name;
this.iconUri = iconUri;
}
/**
* Creates an instance.
*
* @param name the a human-readable string describing some scope (extent) of access
*/
public ScopeRepresentation(String name) {
this(name, null);
}
/**
* Creates an instance.
*/
public ScopeRepresentation() {
this(null, null);
}
public String getName() {
return this.name;
}
public String getIconUri() {
return this.iconUri;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ScopeRepresentation scope = (ScopeRepresentation) o;
return Objects.equals(getName(), scope.getName());
}
public int hashCode() {
return Objects.hash(getName());
}
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setIconUri(String iconUri) {
this.iconUri = iconUri;
}
}

View file

@ -0,0 +1,235 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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.representation;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.net.URI;
import java.util.Set;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class ServerConfiguration {
private String version;
private URI issuer;
@JsonProperty("pat_profiles_supported")
private Set<String> patProfiles;
@JsonProperty("pat_grant_types_supported")
private Set<String> patGrantTypes;
@JsonProperty("aat_profiles_supported")
private Set<String> aatProfiles;
@JsonProperty("aat_grant_types_supported")
private Set<String> aatGrantTypes;
@JsonProperty("rpt_profiles_supported")
private Set<String> rptProfiles;
@JsonProperty("claim_token_profiles_supported")
private Set<String> claimTokenProfiles;
@JsonProperty("dynamic_client_endpoint")
private URI dynamicClientEndpoint;
@JsonProperty("token_endpoint")
private URI tokenEndpoint;
@JsonProperty("authorization_endpoint")
private URI authorizationEndpoint;
@JsonProperty("requesting_party_claims_endpoint")
private URI requestingPartyClaimsEndpoint;
@JsonProperty("resource_set_registration_endpoint")
private URI resourceSetRegistrationEndpoint;
@JsonProperty("introspection_endpoint")
private URI introspectionEndpoint;
@JsonProperty("permission_registration_endpoint")
private URI permissionRegistrationEndpoint;
@JsonProperty("rpt_endpoint")
private URI rptEndpoint;
/**
* Non-standard, Keycloak specific configuration options
*/
private String realm;
private String realmPublicKey;
private URI serverUrl;
public String getVersion() {
return this.version;
}
void setVersion(final String version) {
this.version = version;
}
public URI getIssuer() {
return this.issuer;
}
void setIssuer(final URI issuer) {
this.issuer = issuer;
}
public Set<String> getPatProfiles() {
return this.patProfiles;
}
void setPatProfiles(final Set<String> patProfiles) {
this.patProfiles = patProfiles;
}
public Set<String> getPatGrantTypes() {
return this.patGrantTypes;
}
void setPatGrantTypes(final Set<String> patGrantTypes) {
this.patGrantTypes = patGrantTypes;
}
public Set<String> getAatProfiles() {
return this.aatProfiles;
}
void setAatProfiles(final Set<String> aatProfiles) {
this.aatProfiles = aatProfiles;
}
public Set<String> getAatGrantTypes() {
return this.aatGrantTypes;
}
void setAatGrantTypes(final Set<String> aatGrantTypes) {
this.aatGrantTypes = aatGrantTypes;
}
public Set<String> getRptProfiles() {
return this.rptProfiles;
}
void setRptProfiles(final Set<String> rptProfiles) {
this.rptProfiles = rptProfiles;
}
public Set<String> getClaimTokenProfiles() {
return this.claimTokenProfiles;
}
void setClaimTokenProfiles(final Set<String> claimTokenProfiles) {
this.claimTokenProfiles = claimTokenProfiles;
}
public URI getDynamicClientEndpoint() {
return this.dynamicClientEndpoint;
}
void setDynamicClientEndpoint(final URI dynamicClientEndpoint) {
this.dynamicClientEndpoint = dynamicClientEndpoint;
}
public URI getTokenEndpoint() {
return this.tokenEndpoint;
}
void setTokenEndpoint(final URI tokenEndpoint) {
this.tokenEndpoint = tokenEndpoint;
}
public URI getAuthorizationEndpoint() {
return this.authorizationEndpoint;
}
void setAuthorizationEndpoint(final URI authorizationEndpoint) {
this.authorizationEndpoint = authorizationEndpoint;
}
public URI getRequestingPartyClaimsEndpoint() {
return this.requestingPartyClaimsEndpoint;
}
void setRequestingPartyClaimsEndpoint(final URI requestingPartyClaimsEndpoint) {
this.requestingPartyClaimsEndpoint = requestingPartyClaimsEndpoint;
}
public URI getResourceSetRegistrationEndpoint() {
return this.resourceSetRegistrationEndpoint;
}
void setResourceSetRegistrationEndpoint(final URI resourceSetRegistrationEndpoint) {
this.resourceSetRegistrationEndpoint = resourceSetRegistrationEndpoint;
}
public URI getIntrospectionEndpoint() {
return this.introspectionEndpoint;
}
void setIntrospectionEndpoint(final URI introspectionEndpoint) {
this.introspectionEndpoint = introspectionEndpoint;
}
public URI getPermissionRegistrationEndpoint() {
return this.permissionRegistrationEndpoint;
}
void setPermissionRegistrationEndpoint(final URI permissionRegistrationEndpoint) {
this.permissionRegistrationEndpoint = permissionRegistrationEndpoint;
}
public URI getRptEndpoint() {
return this.rptEndpoint;
}
void setRptEndpoint(final URI rptEndpoint) {
this.rptEndpoint = rptEndpoint;
}
public String getRealm() {
return this.realm;
}
public void setRealm(final String realm) {
this.realm = realm;
}
public String getRealmPublicKey() {
return this.realmPublicKey;
}
public void setRealmPublicKey(String realmPublicKey) {
this.realmPublicKey = realmPublicKey;
}
public URI getServerUrl() {
return this.serverUrl;
}
public void setServerUrl(URI serverUrl) {
this.serverUrl = serverUrl;
}
}

View file

@ -0,0 +1,43 @@
/*
* 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.authorization.client.representation;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.keycloak.representations.JsonWebToken;
import org.keycloak.representations.authorization.Permission;
import java.util.List;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class TokenIntrospectionResponse extends JsonWebToken {
@JsonProperty
private Boolean active;
private List<Permission> permissions;
public Boolean getActive() {
return this.active;
}
public List<Permission> getPermissions() {
return this.permissions;
}
}

View file

@ -0,0 +1,58 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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 org.keycloak.authorization.client.AuthorizationDeniedException;
import org.keycloak.authorization.client.representation.AuthorizationRequest;
import org.keycloak.authorization.client.representation.AuthorizationResponse;
import org.keycloak.authorization.client.util.Http;
import org.keycloak.authorization.client.util.HttpResponseException;
import org.keycloak.util.JsonSerialization;
import java.io.IOException;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class AuthorizationResource {
private final Http http;
private final String accessToken;
public AuthorizationResource(Http http, String aat) {
this.http = http;
this.accessToken = aat;
}
public AuthorizationResponse authorize(AuthorizationRequest request) {
try {
return this.http.<AuthorizationResponse>post("/authz/authorize")
.authorizationBearer(this.accessToken)
.json(JsonSerialization.writeValueAsBytes(request))
.response().json(AuthorizationResponse.class).execute();
} catch (HttpResponseException e) {
if (403 == e.getStatusCode()) {
throw new AuthorizationDeniedException(e);
}
throw new RuntimeException("Failed to obtain authorization data.", e);
} catch (Exception e) {
throw new RuntimeException("Failed to obtain authorization data.", e);
}
}
}

View file

@ -0,0 +1,54 @@
package org.keycloak.authorization.client.resource;
import org.keycloak.authorization.client.AuthorizationDeniedException;
import org.keycloak.authorization.client.representation.EntitlementRequest;
import org.keycloak.authorization.client.representation.EntitlementResponse;
import org.keycloak.authorization.client.util.Http;
import org.keycloak.authorization.client.util.HttpResponseException;
import org.keycloak.util.JsonSerialization;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class EntitlementResource {
private final Http http;
private final String eat;
public EntitlementResource(Http http, String eat) {
this.http = http;
this.eat = eat;
}
public EntitlementResponse getAll(String resourceServerId) {
try {
return this.http.<EntitlementResponse>get("/authz/entitlement/" + resourceServerId)
.authorizationBearer(this.eat)
.response()
.json(EntitlementResponse.class).execute();
} catch (HttpResponseException e) {
if (403 == e.getStatusCode()) {
throw new AuthorizationDeniedException(e);
}
throw new RuntimeException("Failed to obtain entitlements.", e);
} catch (Exception e) {
throw new RuntimeException("Failed to obtain entitlements.", e);
}
}
public EntitlementResponse get(String resourceServerId, EntitlementRequest request) {
try {
return this.http.<EntitlementResponse>post("/authz/entitlement/" + resourceServerId)
.authorizationBearer(this.eat)
.json(JsonSerialization.writeValueAsBytes(request))
.response().json(EntitlementResponse.class).execute();
} catch (HttpResponseException e) {
if (403 == e.getStatusCode()) {
throw new AuthorizationDeniedException(e);
}
throw new RuntimeException("Failed to obtain entitlements.", e);
} catch (Exception e) {
throw new RuntimeException("Failed to obtain entitlements.", e);
}
}
}

View file

@ -0,0 +1,50 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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 org.keycloak.authorization.client.representation.PermissionRequest;
import org.keycloak.authorization.client.representation.PermissionResponse;
import org.keycloak.authorization.client.util.Http;
import org.keycloak.util.JsonSerialization;
import java.io.IOException;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class PermissionResource {
private final Http http;
private final String pat;
public PermissionResource(Http http, String pat) {
this.http = http;
this.pat = pat;
}
public PermissionResponse forResource(PermissionRequest request) {
try {
return this.http.<PermissionResponse>post("/authz/protection/permission")
.authorizationBearer(this.pat)
.json(JsonSerialization.writeValueAsBytes(request))
.response().json(PermissionResponse.class).execute();
} catch (IOException e) {
throw new RuntimeException("Error obtaining permission ticket.", e);
}
}
}

View file

@ -0,0 +1,91 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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 org.keycloak.authorization.client.representation.RegistrationResponse;
import org.keycloak.authorization.client.representation.ResourceRepresentation;
import org.keycloak.authorization.client.util.Http;
import org.keycloak.util.JsonSerialization;
import java.util.Set;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class ProtectedResource {
private final Http http;
private final String pat;
public ProtectedResource(Http http, String pat) {
this.http = http;
this.pat = pat;
}
public RegistrationResponse create(ResourceRepresentation resource) {
try {
return this.http.<RegistrationResponse>post("/authz/protection/resource_set")
.authorizationBearer(this.pat)
.json(JsonSerialization.writeValueAsBytes(resource))
.response().json(RegistrationResponse.class).execute();
} catch (Exception e) {
throw new RuntimeException("Could not create resource.", e);
}
}
public RegistrationResponse findById(String id) {
try {
return this.http.<RegistrationResponse>get("/authz/protection/resource_set/" + id)
.authorizationBearer(this.pat)
.response().json(RegistrationResponse.class).execute();
} catch (Exception e) {
throw new RuntimeException("Could not find resource.", e);
}
}
public Set<String> findByFilter(String filter) {
try {
return this.http.<Set>get("/authz/protection/resource_set")
.authorizationBearer(this.pat)
.param("filter", filter)
.response().json(Set.class).execute();
} catch (Exception e) {
throw new RuntimeException("Could not find resource.", e);
}
}
public Set<String> findAll() {
try {
return this.http.<Set>get("/authz/protection/resource_set")
.authorizationBearer(this.pat)
.response().json(Set.class).execute();
} catch (Exception e) {
throw new RuntimeException("Could not find resource.", e);
}
}
public void delete(String id) {
try {
this.http.delete("/authz/protection/resource_set/" + id)
.authorizationBearer(this.pat)
.execute();
} catch (Exception e) {
throw new RuntimeException("Could not delete resource.", e);
}
}
}

View file

@ -0,0 +1,57 @@
/*
* 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.authorization.client.resource;
import org.keycloak.authorization.client.representation.TokenIntrospectionResponse;
import org.keycloak.authorization.client.util.Http;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class ProtectionResource {
private final String pat;
private final Http http;
public ProtectionResource(Http http, String pat) {
if (pat == null) {
throw new RuntimeException("No access token was provided when creating client for Protection API.");
}
this.http = http;
this.pat = pat;
}
public ProtectedResource resource() {
return new ProtectedResource(http, pat);
}
public PermissionResource permission() {
return new PermissionResource(http, pat);
}
public TokenIntrospectionResponse introspectRequestingPartyToken(String rpt) {
return this.http.<TokenIntrospectionResponse>post("/protocol/openid-connect/token/introspect")
.authentication()
.oauth2ClientCredentials()
.form()
.param("token_type_hint", "requesting_party_token")
.param("token", rpt)
.response().json(TokenIntrospectionResponse.class).execute();
}
}

View file

@ -0,0 +1,65 @@
/*
* 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.authorization.client.util;
import org.apache.http.client.methods.RequestBuilder;
import org.keycloak.authorization.client.Configuration;
import org.keycloak.authorization.client.representation.ServerConfiguration;
import java.net.URI;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class Http {
private final Configuration configuration;
private ServerConfiguration serverConfiguration;
public Http(Configuration configuration) {
this.configuration = configuration;
}
public <R> HttpMethod<R> get(String path) {
return method(RequestBuilder.get(this.serverConfiguration.getIssuer() + path));
}
public <R> HttpMethod<R> get(URI path) {
return method(RequestBuilder.get(path));
}
public <R> HttpMethod<R> post(URI path) {
return method(RequestBuilder.post(path));
}
public <R> HttpMethod<R> post(String path) {
return method(RequestBuilder.post(this.serverConfiguration.getIssuer() + path));
}
public <R> HttpMethod<R> delete(String path) {
return method(RequestBuilder.delete(this.serverConfiguration.getIssuer() + path));
}
private <R> HttpMethod<R> method(RequestBuilder builder) {
return new HttpMethod(this.configuration, builder);
}
public void setServerConfiguration(ServerConfiguration serverConfiguration) {
this.serverConfiguration = serverConfiguration;
}
}

View file

@ -0,0 +1,158 @@
/*
* 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.authorization.client.util;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.keycloak.authorization.client.Configuration;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class HttpMethod<R> {
private final HttpClient httpClient;
private final RequestBuilder builder;
protected final Configuration configuration;
protected final HashMap<String, String> headers;
protected final HashMap<String, String> params;
private HttpMethodResponse<R> response;
public HttpMethod(Configuration configuration, RequestBuilder builder) {
this(configuration, builder, new HashMap<>(), new HashMap<>());
}
public HttpMethod(Configuration configuration, RequestBuilder builder, HashMap<String, String> params, HashMap<String, String> headers) {
this.configuration = configuration;
this.httpClient = configuration.getHttpClient();
this.builder = builder;
this.params = params;
this.headers = headers;
}
public void execute() {
execute(new HttpResponseProcessor<R>() {
@Override
public R process(byte[] entity) {
return null;
}
});
}
public R execute(HttpResponseProcessor<R> responseProcessor) {
byte[] bytes = null;
try {
for (Map.Entry<String, String> header : this.headers.entrySet()) {
this.builder.setHeader(header.getKey(), header.getValue());
}
preExecute(this.builder);
HttpResponse response = this.httpClient.execute(this.builder.build());
HttpEntity entity = response.getEntity();
if (entity != null) {
bytes = EntityUtils.toByteArray(entity);
}
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
if (statusCode < 200 || statusCode >= 300) {
throw new HttpResponseException(statusCode, statusLine.getReasonPhrase(), bytes);
}
if (bytes == null) {
return null;
}
return responseProcessor.process(bytes);
} catch (HttpResponseException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("Error executing http method [" + builder + "]. Response : " + new String(bytes), e);
}
}
protected void preExecute(RequestBuilder builder) {
for (Map.Entry<String, String> param : params.entrySet()) {
builder.addParameter(param.getKey(), param.getValue());
}
}
public HttpMethod<R> authorizationBearer(String bearer) {
this.builder.addHeader("Authorization", "Bearer " + bearer);
return this;
}
public HttpMethodResponse<R> response() {
this.response = new HttpMethodResponse(this);
return this.response;
}
public HttpMethodAuthenticator<R> authentication() {
return new HttpMethodAuthenticator<R>(this);
}
public HttpMethod<R> param(String name, String value) {
this.params.put(name, value);
return this;
}
public HttpMethod<R> json(byte[] entity) {
this.builder.addHeader("Content-Type", "application/json");
this.builder.setEntity(new ByteArrayEntity(entity));
return this;
}
public HttpMethod<R> form() {
return new HttpMethod<R>(this.configuration, this.builder, this.params, this.headers) {
@Override
protected void preExecute(RequestBuilder builder) {
if (params != null) {
List<NameValuePair> formparams = new ArrayList<>();
for (Map.Entry<String, String> param : params.entrySet()) {
formparams.add(new BasicNameValuePair(param.getKey(), param.getValue()));
}
try {
builder.setEntity(new UrlEncodedFormEntity(formparams, "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Error creating form parameters");
}
}
}
};
}
}

View file

@ -0,0 +1,50 @@
/*
* 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.authorization.client.util;
import org.keycloak.OAuth2Constants;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class HttpMethodAuthenticator<R> {
private final HttpMethod<R> method;
public HttpMethodAuthenticator(HttpMethod<R> method) {
this.method = method;
}
public HttpMethod<R> oauth2ClientCredentials() {
this.method.params.put(OAuth2Constants.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS);
configureClientCredentials();
return this.method;
}
public HttpMethod<R> oauth2ResourceOwnerPassword(String userName, String password) {
this.method.params.put(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD);
this.method.params.put("username", userName);
this.method.params.put("password", password);
configureClientCredentials();
return this.method;
}
private void configureClientCredentials() {
this.method.configuration.getClientAuthenticator().configureClientCredentials(this.method.params, this.method.headers);
}
}

View file

@ -0,0 +1,61 @@
/*
* 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.authorization.client.util;
import org.keycloak.util.JsonSerialization;
import java.io.IOException;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class HttpMethodResponse<R> {
private final HttpMethod<R> method;
public HttpMethodResponse(HttpMethod method) {
this.method = method;
}
public R execute() {
return this.method.execute(new HttpResponseProcessor<R>() {
@Override
public R process(byte[] entity) {
return null;
}
});
}
public HttpMethodResponse<R> json(Class<R> responseType) {
return new HttpMethodResponse<R>(this.method) {
@Override
public R execute() {
return method.execute(new HttpResponseProcessor<R>() {
@Override
public R process(byte[] entity) {
try {
return JsonSerialization.readValue(entity, responseType);
} catch (IOException e) {
throw new RuntimeException("Error parsing JSON response.", e);
}
}
});
}
};
}
}

View file

@ -0,0 +1,46 @@
/*
* 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.authorization.client.util;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class HttpResponseException extends RuntimeException {
private final int statusCode;
private final String reasonPhrase;
private final byte[] bytes;
public HttpResponseException(int statusCode, String reasonPhrase, byte[] bytes) {
this.statusCode = statusCode;
this.reasonPhrase = reasonPhrase;
this.bytes = bytes;
}
public int getStatusCode() {
return statusCode;
}
public String getReasonPhrase() {
return reasonPhrase;
}
public byte[] getBytes() {
return bytes;
}
}

View file

@ -0,0 +1,26 @@
/*
* 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.authorization.client.util;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public interface HttpResponseProcessor<R> {
R process(byte[] entity);
}

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-provider-parent</artifactId>
<version>2.0.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>keycloak-authz-policy-aggregate</artifactId>
<packaging>jar</packaging>
<name>KeyCloak AuthZ: Aggregate Policy Provider</name>
<description>KeyCloak AuthZ: Aggregate Policy Provider</description>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,69 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.authorization.policy.provider.time;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
import java.util.ArrayList;
import java.util.List;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class AggregatePolicyAdminResource implements PolicyProviderAdminService {
private final ResourceServer resourceServer;
public AggregatePolicyAdminResource(ResourceServer resourceServer) {
this.resourceServer = resourceServer;
}
@Override
public void onCreate(Policy policy) {
verifyCircularReference(policy, new ArrayList<>());
}
@Override
public void onUpdate(Policy policy) {
verifyCircularReference(policy, new ArrayList<>());
}
private void verifyCircularReference(Policy policy, List<String> ids) {
if (!policy.getType().equals("aggregate")) {
return;
}
if (ids.contains(policy.getId())) {
throw new RuntimeException("Circular reference found [" + policy.getName() + "].");
}
ids.add(policy.getId());
for (Policy associated : policy.getAssociatedPolicies()) {
verifyCircularReference(associated, ids);
}
}
@Override
public void onRemove(Policy policy) {
}
}

View file

@ -0,0 +1,75 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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.policy.provider.time;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.policy.evaluation.DecisionResultCollector;
import org.keycloak.authorization.policy.evaluation.Evaluation;
import org.keycloak.authorization.policy.evaluation.DefaultEvaluation;
import org.keycloak.authorization.policy.evaluation.Result;
import org.keycloak.authorization.policy.provider.PolicyProvider;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import java.util.List;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class AggregatePolicyProvider implements PolicyProvider {
private final Policy policy;
private final AuthorizationProvider authorization;
public AggregatePolicyProvider(Policy policy, AuthorizationProvider authorization) {
this.policy = policy;
this.authorization = authorization;
}
@Override
public void evaluate(Evaluation evaluation) {
//TODO: need to detect deep recursions
DecisionResultCollector decision = new DecisionResultCollector() {
@Override
protected void onComplete(List<Result> results) {
if (results.isEmpty()) {
evaluation.deny();
} else {
Result result = results.iterator().next();
if (Effect.PERMIT.equals(result.getEffect())) {
evaluation.grant();
}
}
}
};
this.policy.getAssociatedPolicies().forEach(associatedPolicy -> {
PolicyProviderFactory providerFactory = authorization.getProviderFactory(associatedPolicy.getType());
PolicyProvider policyProvider = providerFactory.create(associatedPolicy, authorization);
policyProvider.evaluate(new DefaultEvaluation(evaluation.getPermission(), evaluation.getContext(), policy, associatedPolicy, decision));
});
decision.onComplete();
}
@Override
public void close() {
}
}

View file

@ -0,0 +1,62 @@
package org.keycloak.authorization.policy.provider.time;
import org.keycloak.Config;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.policy.provider.PolicyProvider;
import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class AggregatePolicyProviderFactory implements PolicyProviderFactory {
@Override
public String getName() {
return "Aggregated";
}
@Override
public String getGroup() {
return "Others";
}
@Override
public PolicyProvider create(Policy policy, AuthorizationProvider authorization) {
return new AggregatePolicyProvider(policy, authorization);
}
@Override
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
return new AggregatePolicyAdminResource(resourceServer);
}
@Override
public PolicyProvider create(KeycloakSession session) {
return null;
}
@Override
public void init(Config.Scope config) {
}
@Override
public void postInit(KeycloakSessionFactory factory) {
}
@Override
public void close() {
}
@Override
public String getId() {
return "aggregate";
}
}

View file

@ -0,0 +1,19 @@
#
# JBoss, Home of Professional Open Source.
# Copyright 2016 Red Hat, Inc., and individual contributors
# as indicated by the @author tags.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
org.keycloak.authorization.policy.provider.time.AggregatePolicyProviderFactory

View file

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-provider-parent</artifactId>
<version>2.0.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>keycloak-authz-policy-drools</artifactId>
<packaging>jar</packaging>
<name>KeyCloak AuthZ: Drools Policy Provider</name>
<description>KeyCloak AuthZ: Drools Policy Provider</description>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-services</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.ws.rs</groupId>
<artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,71 @@
package org.keycloak.authorization.policy.provider.drools;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.policy.evaluation.Evaluation;
import org.kie.api.KieServices;
import org.kie.api.builder.KieScanner;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import java.util.concurrent.TimeUnit;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
class DroolsPolicy {
private static final int SESSION_POOL_SIZE = 10;
private final KieContainer kc;
private final KieScanner kcs;
private final String sessionName;
DroolsPolicy(KieServices ks, Policy associatedPolicy) {
String groupId = associatedPolicy.getConfig().get("mavenArtifactGroupId");
String artifactId = associatedPolicy.getConfig().get("mavenArtifactId");
String version = associatedPolicy.getConfig().get("mavenArtifactVersion");
String scannerPeriod = associatedPolicy.getConfig().get("scannerPeriod");
String scannerPeriodUnit = associatedPolicy.getConfig().get("scannerPeriodUnit");
this.sessionName = associatedPolicy.getConfig().get("sessionName");
this.kc = ks.newKieContainer(ks.newReleaseId(groupId, artifactId, version));
this.kcs = ks.newKieScanner(this.kc);
this.kcs.start(toMillis(scannerPeriod, scannerPeriodUnit));
KieSession session = this.kc.newKieSession(this.sessionName);
if (session == null) {
throw new RuntimeException("Could not obtain session with name [" + this.sessionName + "].");
}
session.dispose();
}
void evaluate(Evaluation evaluation) {
KieSession session = this.kc.newKieSession(this.sessionName);
session.insert(evaluation);
session.fireAllRules();
session.dispose();
}
void dispose() {
this.kcs.stop();
}
private long toMillis(final String scannerPeriod, final String scannerPeriodUnit) {
switch (scannerPeriodUnit) {
case "Seconds":
return TimeUnit.SECONDS.toMillis(Integer.valueOf(scannerPeriod));
case "Minutes":
return TimeUnit.MINUTES.toMillis(Integer.valueOf(scannerPeriod));
case "Hours":
return TimeUnit.HOURS.toMillis(Integer.valueOf(scannerPeriod));
case "Days":
return TimeUnit.DAYS.toMillis(Integer.valueOf(scannerPeriod));
}
throw new RuntimeException("Invalid time period [" + scannerPeriodUnit + "].");
}
}

View file

@ -0,0 +1,65 @@
package org.keycloak.authorization.policy.provider.drools;
import org.keycloak.authorization.admin.representation.PolicyRepresentation;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
import org.kie.api.runtime.KieContainer;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class DroolsPolicyAdminResource implements PolicyProviderAdminService {
private final ResourceServer resourceServer;
private final DroolsPolicyProviderFactory factory;
public DroolsPolicyAdminResource(ResourceServer resourceServer, DroolsPolicyProviderFactory factory) {
this.resourceServer = resourceServer;
this.factory = factory;
}
@Override
public void onCreate(Policy policy) {
this.factory.update(policy);
}
@Override
public void onUpdate(Policy policy) {
this.factory.update(policy);
}
@Override
public void onRemove(Policy policy) {
this.factory.remove(policy);
}
@Path("/resolveModules")
@POST
@Consumes("application/json")
@Produces("application/json")
public Response resolveModules(PolicyRepresentation policy) {
return Response.ok(getContainer(policy).getKieBaseNames()).build();
}
@Path("/resolveSessions")
@POST
@Consumes("application/json")
@Produces("application/json")
public Response resolveSessions(PolicyRepresentation policy) {
return Response.ok(getContainer(policy).getKieSessionNamesInKieBase(policy.getConfig().get("moduleName"))).build();
}
private KieContainer getContainer(PolicyRepresentation policy) {
String groupId = policy.getConfig().get("mavenArtifactGroupId");
String artifactId = policy.getConfig().get("mavenArtifactId");
String version = policy.getConfig().get("mavenArtifactVersion");
return this.factory.getKieContainer(groupId, artifactId, version);
}
}

View file

@ -0,0 +1,43 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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.policy.provider.drools;
import org.keycloak.authorization.policy.evaluation.Evaluation;
import org.keycloak.authorization.policy.provider.PolicyProvider;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class DroolsPolicyProvider implements PolicyProvider {
private final DroolsPolicy policy;
public DroolsPolicyProvider(DroolsPolicy policy) {
this.policy = policy;
}
@Override
public void evaluate(Evaluation evaluationt) {
this.policy.evaluate(evaluationt);
}
@Override
public void close() {
}
}

View file

@ -0,0 +1,96 @@
package org.keycloak.authorization.policy.provider.drools;
import org.keycloak.Config;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.policy.provider.PolicyProvider;
import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.provider.ProviderFactory;
import org.kie.api.KieServices;
import org.kie.api.KieServices.Factory;
import org.kie.api.runtime.KieContainer;
import java.util.HashMap;
import java.util.Map;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class DroolsPolicyProviderFactory implements PolicyProviderFactory {
private KieServices ks;
private final Map<String, DroolsPolicy> containers = new HashMap<>();
@Override
public String getName() {
return "Drools";
}
@Override
public String getGroup() {
return "Rule Based";
}
@Override
public PolicyProvider create(Policy policy, AuthorizationProvider authorization) {
if (!this.containers.containsKey(policy.getId())) {
update(policy);
}
return new DroolsPolicyProvider(this.containers.get(policy.getId()));
}
@Override
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
return new DroolsPolicyAdminResource(resourceServer, this);
}
@Override
public PolicyProvider create(KeycloakSession session) {
return null;
}
@Override
public void init(Config.Scope config) {
this.ks = Factory.get();
}
@Override
public void postInit(KeycloakSessionFactory factory) {
ProviderFactory<AuthorizationProvider> providerFactory = factory.getProviderFactory(AuthorizationProvider.class);
AuthorizationProvider authorization = providerFactory.create(factory.create());
authorization.getStoreFactory().getPolicyStore().findByType(getId()).forEach(this::update);
}
@Override
public void close() {
this.containers.values().forEach(DroolsPolicy::dispose);
this.containers.clear();
}
@Override
public String getId() {
return "drools";
}
void update(Policy policy) {
remove(policy);
this.containers.put(policy.getId(), new DroolsPolicy(this.ks, policy));
}
void remove(Policy policy) {
DroolsPolicy holder = this.containers.remove(policy.getId());
if (holder != null) {
holder.dispose();
}
}
KieContainer getKieContainer(String groupId, String artifactId, String version) {
return this.ks.newKieContainer(this.ks.newReleaseId(groupId, artifactId, version));
}
}

View file

@ -0,0 +1,19 @@
#
# JBoss, Home of Professional Open Source.
# Copyright 2016 Red Hat, Inc., and individual contributors
# as indicated by the @author tags.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
org.keycloak.authorization.policy.provider.drools.DroolsPolicyProviderFactory

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-provider-parent</artifactId>
<version>2.0.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>keycloak-authz-policy-js</artifactId>
<packaging>jar</packaging>
<name>KeyCloak AuthZ: Javascript-based Policy Provider</name>
<description>KeyCloak AuthZ: Javascript-based Policy Provider</description>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,57 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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.policy.provider.js;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.policy.evaluation.Evaluation;
import org.keycloak.authorization.policy.provider.PolicyProvider;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class JSPolicyProvider implements PolicyProvider {
private final Policy policy;
public JSPolicyProvider(Policy policy) {
this.policy = policy;
}
@Override
public void evaluate(Evaluation evaluation) {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");
engine.put("$evaluation", evaluation);
try {
engine.eval(policy.getConfig().get("code"));
} catch (ScriptException e) {
throw new RuntimeException("Error evaluating JS Policy [" + policy.getName() + "].", e);
}
}
@Override
public void close() {
}
}

View file

@ -0,0 +1,62 @@
package org.keycloak.authorization.policy.provider.js;
import org.keycloak.Config;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.policy.provider.PolicyProvider;
import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class JSPolicyProviderFactory implements PolicyProviderFactory {
@Override
public String getName() {
return "JavaScript";
}
@Override
public String getGroup() {
return "Rule Based";
}
@Override
public PolicyProvider create(Policy policy, AuthorizationProvider authorization) {
return new JSPolicyProvider(policy);
}
@Override
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
return null;
}
@Override
public PolicyProvider create(KeycloakSession session) {
return null;
}
@Override
public void init(Config.Scope config) {
}
@Override
public void postInit(KeycloakSessionFactory factory) {
}
@Override
public void close() {
}
@Override
public String getId() {
return "js";
}
}

View file

@ -0,0 +1,19 @@
#
# JBoss, Home of Professional Open Source.
# Copyright 2016 Red Hat, Inc., and individual contributors
# as indicated by the @author tags.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
org.keycloak.authorization.policy.provider.js.JSPolicyProviderFactory

31
authz/policy/pom.xml Normal file
View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-parent</artifactId>
<version>2.0.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>keycloak-authz-provider-parent</artifactId>
<packaging>pom</packaging>
<name>KeyCloak AuthZ: Provider Parent</name>
<description>KeyCloak AuthZ: Provider Parent</description>
<modules>
<module>user</module>
<module>role</module>
<module>drools</module>
<module>resource</module>
<module>scope</module>
<module>javascript</module>
<module>time</module>
<module>aggregate</module>
</modules>
</project>

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-provider-parent</artifactId>
<version>2.0.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>keycloak-authz-policy-resource</artifactId>
<packaging>jar</packaging>
<name>KeyCloak Authz: Resource Policy Provider</name>
<description>KeyCloak Authz: Resource Policy Provider</description>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,41 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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.policy.provider.resource;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.policy.evaluation.Evaluation;
import org.keycloak.authorization.policy.provider.PolicyProvider;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class ResourcePolicyProvider implements PolicyProvider {
public ResourcePolicyProvider(Policy policy) {
}
@Override
public void evaluate(Evaluation evaluation) {
}
@Override
public void close() {
}
}

View file

@ -0,0 +1,62 @@
package org.keycloak.authorization.policy.provider.resource;
import org.keycloak.Config;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.policy.provider.PolicyProvider;
import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class ResourcePolicyProviderFactory implements PolicyProviderFactory {
@Override
public String getName() {
return "Resource-Based";
}
@Override
public String getGroup() {
return "Permission";
}
@Override
public PolicyProvider create(Policy policy, AuthorizationProvider authorization) {
return new ResourcePolicyProvider(policy);
}
@Override
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
return null;
}
@Override
public PolicyProvider create(KeycloakSession session) {
return null;
}
@Override
public void init(Config.Scope config) {
}
@Override
public void postInit(KeycloakSessionFactory factory) {
}
@Override
public void close() {
}
@Override
public String getId() {
return "resource";
}
}

View file

@ -0,0 +1,19 @@
#
# JBoss, Home of Professional Open Source.
# Copyright 2016 Red Hat, Inc., and individual contributors
# as indicated by the @author tags.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
org.keycloak.authorization.policy.provider.resource.ResourcePolicyProviderFactory

51
authz/policy/role/pom.xml Normal file
View file

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2016 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-provider-parent</artifactId>
<version>2.0.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>keycloak-authz-policy-role</artifactId>
<packaging>jar</packaging>
<name>KeyCloak AuthZ: Role Policy Provider</name>
<description>KeyCloak AuthZ: Role Policy Provider</description>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,75 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.authorization.policy.provider.identity;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.identity.Identity;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.policy.evaluation.Evaluation;
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
import org.keycloak.authorization.policy.provider.PolicyProvider;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import static org.keycloak.authorization.policy.provider.identity.RolePolicyProviderFactory.getRoles;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class RolePolicyProvider implements PolicyProvider {
private final Policy policy;
private final AuthorizationProvider authorization;
public RolePolicyProvider(Policy policy, AuthorizationProvider authorization) {
this.policy = policy;
this.authorization = authorization;
}
public RolePolicyProvider() {
this(null, null);
}
@Override
public void evaluate(Evaluation evaluation) {
EvaluationContext context = evaluation.getContext();
String[] roleIds = getRoles(this.policy);
if (roleIds.length > 0) {
Identity identity = context.getIdentity();
for (String roleId : roleIds) {
RoleModel role = getCurrentRealm().getRoleById(roleId);
if (role != null && identity.hasRole(role.getName())) {
evaluation.grant();
break;
}
}
}
}
private RealmModel getCurrentRealm() {
return this.authorization.getKeycloakSession().getContext().getRealm();
}
@Override
public void close() {
}
}

View file

@ -0,0 +1,132 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.authorization.policy.provider.identity;
import org.keycloak.Config;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.policy.provider.PolicyProvider;
import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RoleContainerModel.RoleRemovedEvent;
import org.keycloak.models.RoleModel;
import org.keycloak.util.JsonSerialization;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class RolePolicyProviderFactory implements PolicyProviderFactory {
@Override
public String getName() {
return "Role-Based";
}
@Override
public String getGroup() {
return "Identity Based";
}
@Override
public PolicyProvider create(Policy policy, AuthorizationProvider authorization) {
return new RolePolicyProvider(policy, authorization);
}
@Override
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
return null;
}
@Override
public PolicyProvider create(KeycloakSession session) {
return new RolePolicyProvider();
}
@Override
public void init(Config.Scope config) {
}
@Override
public void postInit(KeycloakSessionFactory factory) {
factory.register(event -> {
if (event instanceof RoleRemovedEvent) {
KeycloakSession keycloakSession = ((RoleRemovedEvent) event).getKeycloakSession();
AuthorizationProvider provider = keycloakSession.getProvider(AuthorizationProvider.class);
PolicyStore policyStore = provider.getStoreFactory().getPolicyStore();
RoleModel removedRole = ((RoleRemovedEvent) event).getRole();
policyStore.findByType(getId()).forEach(policy -> {
List<String> roles = new ArrayList<>();
for (String roleId : getRoles(policy)) {
if (!roleId.equals(removedRole.getId())) {
roles.add(roleId);
}
}
try {
if (roles.isEmpty()) {
policyStore.findDependentPolicies(policy.getId()).forEach(dependentPolicy -> {
dependentPolicy.removeAssociatedPolicy(policy);
});
policyStore.delete(policy.getId());
} else {
policy.getConfig().put("roles", JsonSerialization.writeValueAsString(roles));
}
} catch (IOException e) {
throw new RuntimeException("Error while synchronizing roles with policy [" + policy.getName() + "].", e);
}
});
}
});
}
@Override
public void close() {
}
@Override
public String getId() {
return "role";
}
static String[] getRoles(Policy policy) {
String roles = policy.getConfig().get("roles");
if (roles != null) {
try {
return JsonSerialization.readValue(roles.getBytes(), String[].class);
} catch (IOException e) {
throw new RuntimeException("Could not parse roles [" + roles + "] from policy config [" + policy.getName() + ".", e);
}
}
return new String[]{};
}
}

View file

@ -0,0 +1,19 @@
#
# JBoss, Home of Professional Open Source.
# Copyright 2016 Red Hat, Inc., and individual contributors
# as indicated by the @author tags.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
org.keycloak.authorization.policy.provider.identity.RolePolicyProviderFactory

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-provider-parent</artifactId>
<version>2.0.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>keycloak-authz-policy-scope</artifactId>
<packaging>jar</packaging>
<name>KeyCloak AuthZ: Scope Policy Provider</name>
<description>KeyCloak AuthZ: Scope Policy Provider</description>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,43 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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.policy.provider.scope;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.policy.evaluation.Evaluation;
import org.keycloak.authorization.policy.provider.PolicyProvider;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class ScopePolicyProvider implements PolicyProvider {
private final Policy policy;
public ScopePolicyProvider(Policy policy) {
this.policy = policy;
}
@Override
public void evaluate(Evaluation evaluation) {
}
@Override
public void close() {
}
}

View file

@ -0,0 +1,62 @@
package org.keycloak.authorization.policy.provider.scope;
import org.keycloak.Config;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.policy.provider.PolicyProvider;
import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class ScopePolicyProviderFactory implements PolicyProviderFactory {
@Override
public String getName() {
return "Scope-Based";
}
@Override
public String getGroup() {
return "Permission";
}
@Override
public PolicyProvider create(Policy policy, AuthorizationProvider authorization) {
return new ScopePolicyProvider(policy);
}
@Override
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
return null;
}
@Override
public PolicyProvider create(KeycloakSession session) {
return null;
}
@Override
public void init(Config.Scope config) {
}
@Override
public void postInit(KeycloakSessionFactory factory) {
}
@Override
public void close() {
}
@Override
public String getId() {
return "scope";
}
}

View file

@ -0,0 +1,19 @@
#
# JBoss, Home of Professional Open Source.
# Copyright 2016 Red Hat, Inc., and individual contributors
# as indicated by the @author tags.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
org.keycloak.authorization.policy.provider.scope.ScopePolicyProviderFactory

32
authz/policy/time/pom.xml Normal file
View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-provider-parent</artifactId>
<version>2.0.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>keycloak-authz-policy-time</artifactId>
<packaging>jar</packaging>
<name>KeyCloak AuthZ: Time-based Policy Provider</name>
<description>KeyCloak AuthZ: Time-based Policy Provider</description>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,64 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.authorization.policy.provider.time;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
import java.text.SimpleDateFormat;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class TimePolicyAdminResource implements PolicyProviderAdminService {
@Override
public void onCreate(Policy policy) {
validateConfig(policy);
}
private void validateConfig(Policy policy) {
String nbf = policy.getConfig().get("nbf");
String noa = policy.getConfig().get("noa");
if (nbf == null && noa == null) {
throw new RuntimeException("You must provide NotBefore, NotOnOrAfter or both.");
}
validateFormat(nbf);
validateFormat(noa);
}
@Override
public void onUpdate(Policy policy) {
validateConfig(policy);
}
@Override
public void onRemove(Policy policy) {
}
private void validateFormat(String date) {
try {
new SimpleDateFormat(TimePolicyProvider.DEFAULT_DATE_PATTERN).parse(TimePolicyProvider.format(date));
} catch (Exception e) {
throw new RuntimeException("Could not parse a date using format [" + date + "]");
}
}
}

View file

@ -0,0 +1,86 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* 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.policy.provider.time;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.policy.evaluation.Evaluation;
import org.keycloak.authorization.policy.provider.PolicyProvider;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class TimePolicyProvider implements PolicyProvider {
static String DEFAULT_DATE_PATTERN = "yyyy-MM-dd hh:mm:ss";
private final Policy policy;
private final SimpleDateFormat dateFormat;
private final Date currentDate;
public TimePolicyProvider(Policy policy) {
this.policy = policy;
this.dateFormat = new SimpleDateFormat(DEFAULT_DATE_PATTERN);
this.currentDate = new Date();
}
@Override
public void evaluate(Evaluation evaluation) {
try {
String notBefore = this.policy.getConfig().get("nbf");
if (notBefore != null) {
if (this.currentDate.before(this.dateFormat.parse(format(notBefore)))) {
evaluation.deny();
return;
}
}
String notOnOrAfter = this.policy.getConfig().get("noa");
if (notOnOrAfter != null) {
if (this.currentDate.after(this.dateFormat.parse(format(notOnOrAfter)))) {
evaluation.deny();
return;
}
}
evaluation.grant();
} catch (Exception e) {
throw new RuntimeException("Could not evaluate time-based policy [" + this.policy.getName() + "].", e);
}
}
static String format(String notBefore) {
String trimmed = notBefore.trim();
if (trimmed.length() == 10) {
notBefore = trimmed + " 00:00:00";
}
return notBefore;
}
@Override
public void close() {
}
}

View file

@ -0,0 +1,62 @@
package org.keycloak.authorization.policy.provider.time;
import org.keycloak.Config;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.policy.provider.PolicyProvider;
import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class TimePolicyProviderFactory implements PolicyProviderFactory {
@Override
public String getName() {
return "Time";
}
@Override
public String getGroup() {
return "Time Based";
}
@Override
public PolicyProvider create(Policy policy, AuthorizationProvider authorization) {
return new TimePolicyProvider(policy);
}
@Override
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
return new TimePolicyAdminResource();
}
@Override
public PolicyProvider create(KeycloakSession session) {
return null;
}
@Override
public void init(Config.Scope config) {
}
@Override
public void postInit(KeycloakSessionFactory factory) {
}
@Override
public void close() {
}
@Override
public String getId() {
return "time";
}
}

View file

@ -0,0 +1,19 @@
#
# JBoss, Home of Professional Open Source.
# Copyright 2016 Red Hat, Inc., and individual contributors
# as indicated by the @author tags.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
org.keycloak.authorization.policy.provider.time.TimePolicyProviderFactory

51
authz/policy/user/pom.xml Normal file
View file

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2016 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-provider-parent</artifactId>
<version>2.0.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>keycloak-authz-policy-user</artifactId>
<packaging>jar</packaging>
<name>KeyCloak AuthZ: User Policy Provider</name>
<description>KeyCloak AuthZ: User Policy Provider</description>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,60 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.authorization.policy.provider.identity;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.policy.evaluation.Evaluation;
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
import org.keycloak.authorization.policy.provider.PolicyProvider;
import org.keycloak.util.JsonSerialization;
import java.io.IOException;
import static org.keycloak.authorization.policy.provider.identity.UserPolicyProviderFactory.getUsers;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class UserPolicyProvider implements PolicyProvider {
private final Policy policy;
public UserPolicyProvider(Policy policy) {
this.policy = policy;
}
@Override
public void evaluate(Evaluation evaluation) {
EvaluationContext context = evaluation.getContext();
String[] userIds = getUsers(this.policy);
if (userIds.length > 0) {
for (String userId : userIds) {
if (context.getIdentity().getId().equals(userId)) {
evaluation.grant();
break;
}
}
}
}
@Override
public void close() {
}
}

View file

@ -0,0 +1,132 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.authorization.policy.provider.identity;
import org.keycloak.Config;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.Policy;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.authorization.policy.provider.PolicyProvider;
import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
import org.keycloak.authorization.store.PolicyStore;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserModel.UserRemovedEvent;
import org.keycloak.util.JsonSerialization;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class UserPolicyProviderFactory implements PolicyProviderFactory {
@Override
public String getName() {
return "User-Based";
}
@Override
public String getGroup() {
return "Identity Based";
}
@Override
public PolicyProvider create(Policy policy, AuthorizationProvider authorization) {
return new UserPolicyProvider(policy);
}
@Override
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
return null;
}
@Override
public PolicyProvider create(KeycloakSession session) {
return null;
}
@Override
public void init(Config.Scope config) {
}
@Override
public void postInit(KeycloakSessionFactory factory) {
factory.register(event -> {
if (event instanceof UserRemovedEvent) {
KeycloakSession keycloakSession = ((UserRemovedEvent) event).getKeycloakSession();
AuthorizationProvider provider = keycloakSession.getProvider(AuthorizationProvider.class);
PolicyStore policyStore = provider.getStoreFactory().getPolicyStore();
UserModel removedUser = ((UserRemovedEvent) event).getUser();
policyStore.findByType(getId()).forEach(policy -> {
List<String> users = new ArrayList<>();
for (String userId : getUsers(policy)) {
if (!userId.equals(removedUser.getId())) {
users.add(userId);
}
}
try {
if (users.isEmpty()) {
policyStore.findDependentPolicies(policy.getId()).forEach(dependentPolicy -> {
dependentPolicy.removeAssociatedPolicy(policy);
});
policyStore.delete(policy.getId());
} else {
policy.getConfig().put("users", JsonSerialization.writeValueAsString(users));
}
} catch (IOException e) {
throw new RuntimeException("Error while synchronizing users with policy [" + policy.getName() + "].", e);
}
});
}
});
}
@Override
public void close() {
}
@Override
public String getId() {
return "user";
}
static String[] getUsers(Policy policy) {
String roles = policy.getConfig().get("users");
if (roles != null) {
try {
return JsonSerialization.readValue(roles.getBytes(), String[].class);
} catch (IOException e) {
throw new RuntimeException("Could not parse roles [" + roles + "] from policy config [" + policy.getName() + ".", e);
}
}
return new String[]{};
}
}

View file

@ -0,0 +1,19 @@
#
# JBoss, Home of Professional Open Source.
# Copyright 2016 Red Hat, Inc., and individual contributors
# as indicated by the @author tags.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
org.keycloak.authorization.policy.provider.identity.UserPolicyProviderFactory

30
authz/pom.xml Normal file
View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-parent</artifactId>
<version>2.0.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>keycloak-authz-parent</artifactId>
<packaging>pom</packaging>
<name>KeyCloak Authz: Parent</name>
<description>KeyCloak AuthZ: Parent</description>
<modules>
<module>policy</module>
<module>client</module>
</modules>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>

View file

@ -0,0 +1,93 @@
/*
* 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;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
import org.keycloak.representations.authorization.Permission;
import java.util.List;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class AuthorizationContext {
private final AccessToken authzToken;
private final List<PathConfig> paths;
private boolean granted;
public AuthorizationContext(AccessToken authzToken, List<PathConfig> paths) {
this.authzToken = authzToken;
this.paths = paths;
this.granted = true;
}
public AuthorizationContext() {
this(null, null);
this.granted = false;
}
public boolean hasPermission(String resourceName, String scopeName) {
for (Permission permission : authzToken.getAuthorization().getPermissions()) {
for (PathConfig pathHolder : this.paths) {
if (pathHolder.getName().equals(resourceName)) {
if (pathHolder.getId().equals(permission.getResourceSetId())) {
if (permission.getScopes().contains(scopeName)) {
return true;
}
}
}
}
}
return false;
}
public boolean hasResourcePermission(String resourceName) {
for (Permission permission : authzToken.getAuthorization().getPermissions()) {
for (PathConfig pathHolder : this.paths) {
if (pathHolder.getName().equals(resourceName)) {
if (pathHolder.getId().equals(permission.getResourceSetId())) {
return true;
}
}
}
}
return false;
}
public boolean hasScopePermission(String scopeName) {
for (Permission permission : authzToken.getAuthorization().getPermissions()) {
if (permission.getScopes().contains(scopeName)) {
return true;
}
}
return false;
}
public List<Permission> getPermissions() {
return this.authzToken.getAuthorization().getPermissions();
}
public boolean isGranted() {
return granted;
}
}

View file

@ -41,6 +41,7 @@ public class KeycloakSecurityContext implements Serializable {
// Don't store parsed tokens into HTTP session
protected transient AccessToken token;
protected transient IDToken idToken;
protected transient AuthorizationContext authorizationContext;
public KeycloakSecurityContext() {
}
@ -60,6 +61,10 @@ public class KeycloakSecurityContext implements Serializable {
return tokenString;
}
public AuthorizationContext getAuthorizationContext() {
return authorizationContext;
}
public IDToken getIdToken() {
return idToken;
}

View file

@ -19,10 +19,12 @@ package org.keycloak.representations;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.keycloak.representations.authorization.Permission;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -81,6 +83,20 @@ public class AccessToken extends IDToken {
}
}
public static class Authorization implements Serializable {
@JsonProperty("permissions")
private List<Permission> permissions;
public List<Permission> getPermissions() {
return permissions;
}
public void setPermissions(List<Permission> permissions) {
this.permissions = permissions;
}
}
@JsonProperty("client_session")
protected String clientSession;
@ -96,6 +112,9 @@ public class AccessToken extends IDToken {
@JsonProperty("resource_access")
protected Map<String, Access> resourceAccess = new HashMap<String, Access>();
@JsonProperty("authorization")
protected Authorization authorization;
public Map<String, Access> getResourceAccess() {
return resourceAccess;
}
@ -219,5 +238,11 @@ public class AccessToken extends IDToken {
return (AccessToken)super.issuedFor(issuedFor);
}
public Authorization getAuthorization() {
return authorization;
}
public void setAuthorization(Authorization authorization) {
this.authorization = authorization;
}
}

View file

@ -36,7 +36,8 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
"client-keystore", "client-keystore-password", "client-key-password",
"always-refresh-token",
"register-node-at-startup", "register-node-period", "token-store", "principal-attribute",
"proxy-url", "turn-off-change-session-id-on-login", "token-minimum-time-to-live"
"proxy-url", "turn-off-change-session-id-on-login", "token-minimum-time-to-live",
"policy-enforcer"
})
public class AdapterConfig extends BaseAdapterConfig {
@ -70,6 +71,8 @@ public class AdapterConfig extends BaseAdapterConfig {
protected Boolean turnOffChangeSessionIdOnLogin;
@JsonProperty("token-minimum-time-to-live")
protected int tokenMinimumTimeToLive = 0;
@JsonProperty("policy-enforcer")
protected PolicyEnforcerConfig policyEnforcerConfig;
/**
* The Proxy url to use for requests to the auth-server, configurable via the adapter config property {@code proxy-url}.
@ -189,6 +192,14 @@ public class AdapterConfig extends BaseAdapterConfig {
this.turnOffChangeSessionIdOnLogin = turnOffChangeSessionIdOnLogin;
}
public PolicyEnforcerConfig getPolicyEnforcerConfig() {
return policyEnforcerConfig;
}
public void setPolicyEnforcerConfig(PolicyEnforcerConfig policyEnforcerConfig) {
this.policyEnforcerConfig = policyEnforcerConfig;
}
public String getProxyUrl() {
return proxyUrl;
}

View file

@ -0,0 +1,209 @@
/*
* 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.representations.adapters.config;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class PolicyEnforcerConfig {
@JsonProperty("create-resources")
private Boolean createResources;
@JsonProperty("enforcement-mode")
private EnforcementMode enforcementMode = EnforcementMode.ENFORCING;
@JsonProperty("user-managed-access")
private UmaProtocolConfig umaProtocolConfig;
@JsonProperty("entitlement")
private EntitlementProtocolConfig entitlementProtocolConfig;
@JsonProperty("paths")
private List<PathConfig> paths = new ArrayList<>();
@JsonProperty("online-introspection")
private Boolean onlineIntrospection;
@JsonProperty("on-deny-redirect-to")
private String accessDeniedPath;
public Boolean isCreateResources() {
return this.createResources;
}
public List<PathConfig> getPaths() {
if (this.paths == null) {
return null;
}
return Collections.unmodifiableList(this.paths);
}
public EnforcementMode getEnforcementMode() {
return this.enforcementMode;
}
public void setEnforcementMode(EnforcementMode enforcementMode) {
this.enforcementMode = enforcementMode;
}
public UmaProtocolConfig getUmaProtocolConfig() {
return this.umaProtocolConfig;
}
public EntitlementProtocolConfig getEntitlementProtocolConfig() {
return this.entitlementProtocolConfig;
}
public Boolean isOnlineIntrospection() {
return onlineIntrospection;
}
public void setPaths(List<PathConfig> paths) {
this.paths = paths;
}
public String getAccessDeniedPath() {
return accessDeniedPath;
}
public static class PathConfig {
private String name;
private String type;
private String path;
private List<MethodConfig> methods = new ArrayList<>();
private List<String> scopes = Collections.emptyList();
private String id;
private boolean instance;
public String getPath() {
return this.path;
}
public void setPath(String path) {
this.path = path;
}
public List<String> getScopes() {
return this.scopes;
}
public void setScopes(List<String> scopes) {
this.scopes = scopes;
}
public List<MethodConfig> getMethods() {
return methods;
}
public void setMethods(List<MethodConfig> methods) {
this.methods = methods;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
@Override
public String toString() {
return "PathConfig{" +
"name='" + name + '\'' +
", type='" + type + '\'' +
", path='" + path + '\'' +
", scopes=" + scopes +
", id='" + id + '\'' +
'}';
}
public boolean hasPattern() {
return getPath().indexOf("{") != -1;
}
public boolean isInstance() {
return instance;
}
public void setInstance(boolean instance) {
this.instance = instance;
}
}
public static class MethodConfig {
private String method;
private List<String> scopes = Collections.emptyList();
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public List<String> getScopes() {
return scopes;
}
public void setScopes(List<String> scopes) {
this.scopes = scopes;
}
}
public enum EnforcementMode {
PERMISSIVE,
ENFORCING,
DISABLED
}
public static class UmaProtocolConfig {
}
public static class EntitlementProtocolConfig {
}
}

View file

@ -0,0 +1,72 @@
/*
* 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.representations.authorization;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Set;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class Permission {
@JsonProperty("resource_set_id")
private String resourceSetId;
@JsonProperty("resource_set_name")
private final String resourceSetName;
private Set<String> scopes;
public Permission() {
this(null, null, null);
}
public Permission(final String resourceSetId, String resourceSetName, final Set<String> scopes) {
this.resourceSetId = resourceSetId;
this.resourceSetName = resourceSetName;
this.scopes = scopes;
}
public String getResourceSetId() {
return this.resourceSetId;
}
public String getResourceSetName() {
return this.resourceSetName;
}
public Set<String> getScopes() {
return this.scopes;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Permission {").append("id=").append(resourceSetId).append(", name=").append(resourceSetName)
.append(", scopes=").append(scopes).append("}");
return builder.toString();
}
public void setScopes(Set<String> scopes) {
this.scopes = scopes;
}
}

View file

@ -47,6 +47,7 @@ public class ClientRepresentation {
protected Boolean implicitFlowEnabled;
protected Boolean directAccessGrantsEnabled;
protected Boolean serviceAccountsEnabled;
protected Boolean authorizationServicesEnabled;
@Deprecated
protected Boolean directGrantsOnly;
protected Boolean publicClient;
@ -239,6 +240,14 @@ public class ClientRepresentation {
this.serviceAccountsEnabled = serviceAccountsEnabled;
}
public Boolean getAuthorizationServicesEnabled() {
return authorizationServicesEnabled;
}
public void setAuthorizationServicesEnabled(Boolean authorizationServicesEnabled) {
this.authorizationServicesEnabled = authorizationServicesEnabled;
}
@Deprecated
public Boolean isDirectGrantsOnly() {
return directGrantsOnly;

View file

@ -85,6 +85,286 @@
</exclusion>
</exclusions>
</dependency>
<!-- Built-in Authorization Policy Providers -->
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-policy-resource</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-policy-scope</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-policy-user</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-policy-role</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-policy-js</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-policy-time</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-policy-aggregate</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Built-in Authorization Drools Policy Provider-->
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-policy-drools</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Drools -->
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-ci</artifactId>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-internal</artifactId>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.aether</groupId>
<artifactId>aether-api</artifactId>
<version>1.0.0.v20140518</version>
</dependency>
<dependency>
<groupId>org.eclipse.aether</groupId>
<artifactId>aether-connector-basic</artifactId>
<version>1.0.0.v20140518</version>
</dependency>
<dependency>
<groupId>org.eclipse.aether</groupId>
<artifactId>aether-spi</artifactId>
<version>1.0.0.v20140518</version>
</dependency>
<dependency>
<groupId>org.eclipse.aether</groupId>
<artifactId>aether-impl</artifactId>
<version>1.0.0.v20140518</version>
</dependency>
<dependency>
<groupId>org.eclipse.aether</groupId>
<artifactId>aether-transport-file</artifactId>
<version>1.0.0.v20140518</version>
</dependency>
<dependency>
<groupId>org.eclipse.aether</groupId>
<artifactId>aether-transport-http</artifactId>
<version>1.0.0.v20140518</version>
</dependency>
<dependency>
<groupId>org.eclipse.aether</groupId>
<artifactId>aether-transport-wagon</artifactId>
<version>1.0.0.v20140518</version>
</dependency>
<dependency>
<groupId>org.eclipse.aether</groupId>
<artifactId>aether-util</artifactId>
<version>1.0.0.v20140518</version>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
<version>1.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-launcher</artifactId>
<version>1.8.2</version>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr-runtime</artifactId>
<version>3.5</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-aether-provider</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-compat</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-model</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-model-builder</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-repository-metadata</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-settings</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-settings-builder</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.mvel</groupId>
<artifactId>mvel2</artifactId>
<version>2.2.4.Final</version>
</dependency>
<dependency>
<groupId>org.eclipse.sisu</groupId>
<artifactId>org.eclipse.sisu.inject</artifactId>
<version>0.0.0.M5</version>
</dependency>
<dependency>
<groupId>org.eclipse.sisu</groupId>
<artifactId>org.eclipse.sisu.plexus</artifactId>
<version>0.0.0.M5</version>
</dependency>
<dependency>
<groupId>org.sonatype.plexus</groupId>
<artifactId>plexus-cipher</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-classworlds</artifactId>
<version>2.5.1</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-component-annotations</artifactId>
<version>1.5.5</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-interpolation</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>org.sonatype.plexus</groupId>
<artifactId>plexus-sec-dispatcher</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
<version>3.0.17</version>
</dependency>
<dependency>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-http</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-http-shared4</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-provider-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.7</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>13.0.1</version>
</dependency>
<dependency>
<groupId>org.eclipse.jdt.core.compiler</groupId>
<artifactId>ecj</artifactId>
<version>4.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.6</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.3.3</version>
</dependency>
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>2.1.2</version>
<exclusions>
<exclusion>
<groupId>bouncycastle</groupId>
<artifactId>bcmail-jdk14</artifactId>
</exclusion>
<exclusion>
<groupId>bouncycastle</groupId>
<artifactId>bcprov-jdk14</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.sonatype.sisu</groupId>
<artifactId>sisu-guice</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>
</project>

View file

@ -38,6 +38,9 @@
<include>org/keycloak/keycloak-wildfly-subsystem/**</include>
<include>org/keycloak/keycloak-adapter-subsystem/**</include>
<include>org/keycloak/keycloak-servlet-oauth-client/**</include>
<!-- Authorization -->
<include>org/keycloak/keycloak-authz-client/**</include>
</includes>
<excludes>
<exclude>**/*.war</exclude>

View file

@ -73,6 +73,10 @@
<maven-resource group="org.keycloak" artifact="keycloak-servlet-oauth-client"/>
</module-def>
<!-- Authorization -->
<module-def name="org.keycloak.keycloak-authz-client">
<maven-resource group="org.keycloak" artifact="keycloak-authz-client"/>
</module-def>
</target>
<target name="clean-target">

View file

@ -82,6 +82,12 @@
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
</dependency>
<!-- Authorization -->
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-client</artifactId>
</dependency>
</dependencies>
<build>

View file

@ -34,6 +34,7 @@
<module name="org.keycloak.keycloak-adapter-spi"/>
<module name="org.keycloak.keycloak-common"/>
<module name="org.keycloak.keycloak-core"/>
<module name="org.keycloak.keycloak-authz-client"/>
</dependencies>
</module>

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2016 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-authz-client">
<resources>
<!-- Insert resources here -->
</resources>
<dependencies>
<module name="org.bouncycastle" />
<module name="javax.api"/>
<module name="javax.activation.api"/>
<module name="sun.jdk" optional="true" />
<module name="javax.ws.rs.api"/>
<module name="org.keycloak.keycloak-core"/>
<module name="org.keycloak.keycloak-common"/>
<module name="org.apache.httpcomponents"/>
<module name="com.fasterxml.jackson.core.jackson-core"/>
<module name="com.fasterxml.jackson.core.jackson-annotations"/>
<module name="com.fasterxml.jackson.core.jackson-databind"/>
<module name="com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider"/>
</dependencies>
</module>

View file

@ -136,6 +136,14 @@
<exclude name="**/*.iml"/>
</fileset>
</copy>
<copy todir="target/examples/authz" overwrite="true">
<fileset dir="../../examples/authz">
<exclude name="**/target/**"/>
<exclude name="**/*.iml"/>
<exclude name="**/*.unconfigured"/>
<exclude name="**/subsystem-config.xml"/>
</fileset>
</copy>
<copy file="../../examples/pom.xml" tofile="target/examples/pom.xml"/>
<copy file="../../examples/README.md" tofile="target/examples/README.md"/>
<move file="target/examples/unconfigured-demo/README.md.unconfigured" tofile="target/examples/unconfigured-demo/README.md"/>

View file

@ -51,6 +51,13 @@
<groupId>org.wildfly</groupId>
<artifactId>wildfly-feature-pack</artifactId>
<type>zip</type>
<!-- Need to exlcude that in order to use the right guava version for drools -->
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

View file

@ -32,6 +32,10 @@
"provider": "jpa"
},
"authorizationPersister": {
"provider": "jpa"
},
"timer": {
"provider": "basic"
},

View file

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2016 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<module xmlns="urn:jboss:module:1.3" name="org.drools">
<resources>
<artifact name="${org.kie:kie-api}"/>
<artifact name="${org.kie:kie-ci}"/>
<artifact name="${org.kie:kie-internal}"/>
<artifact name="${org.drools:drools-core}"/>
<artifact name="${org.drools:drools-compiler}"/>
<artifact name="${org.eclipse.aether:aether-api}"/>
<artifact name="${org.eclipse.aether:aether-connector-basic}"/>
<artifact name="${org.eclipse.aether:aether-spi}"/>
<artifact name="${org.eclipse.aether:aether-impl}"/>
<artifact name="${org.eclipse.aether:aether-transport-file}"/>
<artifact name="${org.eclipse.aether:aether-transport-http}"/>
<artifact name="${org.eclipse.aether:aether-transport-wagon}"/>
<artifact name="${org.eclipse.aether:aether-util}"/>
<artifact name="${org.apache.ant:ant}"/>
<artifact name="${org.apache.ant:ant-launcher}"/>
<artifact name="${org.antlr:antlr-runtime}"/>
<artifact name="${aopalliance:aopalliance}"/>
<artifact name="${org.apache.maven:maven-aether-provider}"/>
<artifact name="${org.apache.maven:maven-artifact}"/>
<artifact name="${org.apache.maven:maven-compat}"/>
<artifact name="${org.apache.maven:maven-core}"/>
<artifact name="${org.apache.maven:maven-model}"/>
<artifact name="${org.apache.maven:maven-model-builder}"/>
<artifact name="${org.apache.maven:maven-plugin-api}"/>
<artifact name="${org.apache.maven:maven-repository-metadata}"/>
<artifact name="${org.apache.maven:maven-settings}"/>
<artifact name="${org.apache.maven:maven-settings-builder}"/>
<artifact name="${org.mvel:mvel2}"/>
<artifact name="${org.eclipse.sisu:org.eclipse.sisu.inject}"/>
<artifact name="${org.eclipse.sisu:org.eclipse.sisu.plexus}"/>
<artifact name="${org.sonatype.plexus:plexus-cipher}"/>
<artifact name="${org.codehaus.plexus:plexus-classworlds}"/>
<artifact name="${org.codehaus.plexus:plexus-component-annotations}"/>
<artifact name="${org.codehaus.plexus:plexus-interpolation}"/>
<artifact name="${org.sonatype.plexus:plexus-sec-dispatcher}"/>
<artifact name="${org.codehaus.plexus:plexus-utils}"/>
<artifact name="${org.apache.maven.wagon:wagon-http}"/>
<artifact name="${org.apache.maven.wagon:wagon-http-shared4}"/>
<artifact name="${org.apache.maven.wagon:wagon-provider-api}"/>
<artifact name="${com.thoughtworks.xstream:xstream}"/>
<artifact name="${com.google.guava:guava}"/>
<artifact name="${org.eclipse.jdt.core.compiler:ecj}"/>
<artifact name="${org.apache.httpcomponents:httpclient}"/>
<artifact name="${org.apache.httpcomponents:httpcore}"/>
<artifact name="${com.lowagie:itext}"/>
<artifact name="${org.sonatype.sisu:sisu-guice}"/>
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.inject.api"/>
<module name="javax.enterprise.api"/>
<module name="org.slf4j"/>
<module name="org.apache.commons.logging"/>
<module name="org.keycloak.keycloak-core"/>
<module name="org.keycloak.keycloak-common"/>
<module name="org.keycloak.keycloak-server-spi"/>
</dependencies>
</module>

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2016 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<module xmlns="urn:jboss:module:1.3" name="org.keycloak.keycloak-authz-policy-drools">
<resources>
<artifact name="${org.keycloak:keycloak-authz-policy-drools}"/>
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.ws.rs.api"/>
<module name="org.keycloak.keycloak-core"/>
<module name="org.keycloak.keycloak-common"/>
<module name="org.keycloak.keycloak-server-spi"/>
<module name="org.keycloak.keycloak-services"/>
<module name="org.drools"/>
</dependencies>
</module>

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2016 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<module xmlns="urn:jboss:module:1.3" name="org.keycloak.keycloak-authz-policy-provider">
<resources>
<artifact name="${org.keycloak:keycloak-authz-policy-aggregate}"/>
<artifact name="${org.keycloak:keycloak-authz-policy-js}"/>
<artifact name="${org.keycloak:keycloak-authz-policy-resource}"/>
<artifact name="${org.keycloak:keycloak-authz-policy-role}"/>
<artifact name="${org.keycloak:keycloak-authz-policy-scope}"/>
<artifact name="${org.keycloak:keycloak-authz-policy-time}"/>
<artifact name="${org.keycloak:keycloak-authz-policy-user}"/>
</resources>
<dependencies>
<module name="javax.api"/>
<module name="javax.ws.rs.api"/>
<module name="org.keycloak.keycloak-core"/>
<module name="org.keycloak.keycloak-common"/>
<module name="org.keycloak.keycloak-server-spi"/>
<module name="org.keycloak.keycloak-services"/>
</dependencies>
</module>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.3" name="org.keycloak.keycloak-authz-server">
<dependencies>
<module name="org.keycloak.keycloak-authz-policy-provider" export="true" services="export"/>
<module name="org.keycloak.keycloak-authz-policy-drools" export="true" services="export"/>
</dependencies>
</module>

View file

@ -45,6 +45,7 @@
<filter>
<filter-name>Keycloak Session Management</filter-name>
<filter-class>org.keycloak.services.filters.KeycloakSessionServletFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>

View file

@ -44,6 +44,9 @@
<module name="org.keycloak.keycloak-services" export="true" services="import"/>
<module name="org.keycloak.keycloak-wildfly-extensions" services="import"/>
<!-- Authorization -->
<module name="org.keycloak.keycloak-authz-server" services="import"/>
<module name="org.freemarker"/>
<module name="javax.ws.rs.api"/>
<module name="javax.mail.api"/>

View file

@ -1 +1 @@
layers=keycloak
layers=keycloak,keycloak-authz

Some files were not shown because too many files have changed in this diff Show more