Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
12cb295a35
227 changed files with 10674 additions and 3378 deletions
|
@ -28,7 +28,6 @@ import org.keycloak.AuthorizationContext;
|
|||
import org.keycloak.KeycloakSecurityContext;
|
||||
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.representations.AccessToken;
|
||||
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
|
||||
|
@ -71,7 +70,6 @@ public abstract class AbstractPolicyEnforcer {
|
|||
|
||||
if (accessToken != null) {
|
||||
Request request = httpFacade.getRequest();
|
||||
Response response = httpFacade.getResponse();
|
||||
String path = getPath(request);
|
||||
PathConfig pathConfig = this.pathMatcher.matches(path, this.paths);
|
||||
|
||||
|
@ -83,7 +81,12 @@ public abstract class AbstractPolicyEnforcer {
|
|||
}
|
||||
|
||||
LOGGER.debugf("Could not find a configuration for path [%s]", path);
|
||||
response.sendError(403, "Could not find a configuration for path [" + path + "].");
|
||||
|
||||
if (isDefaultAccessDeniedUri(request, enforcerConfig)) {
|
||||
return createAuthorizationContext(accessToken);
|
||||
}
|
||||
|
||||
handleAccessDenied(httpFacade);
|
||||
|
||||
return createEmptyAuthorizationContext(false);
|
||||
}
|
||||
|
@ -102,9 +105,11 @@ public abstract class AbstractPolicyEnforcer {
|
|||
}
|
||||
}
|
||||
|
||||
LOGGER.debugf("Sending challenge to the client. Path [%s]", pathConfig);
|
||||
|
||||
if (!challenge(pathConfig, requiredScopes, httpFacade)) {
|
||||
LOGGER.debugf("Sending challenge to the client. Path [%s]", pathConfig);
|
||||
response.sendError(403, "Authorization failed.");
|
||||
LOGGER.debugf("Challenge not sent, sending default forbidden response. Path [%s]", pathConfig);
|
||||
handleAccessDenied(httpFacade);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,6 +170,10 @@ public abstract class AbstractPolicyEnforcer {
|
|||
return false;
|
||||
}
|
||||
|
||||
protected void handleAccessDenied(OIDCHttpFacade httpFacade) {
|
||||
httpFacade.getResponse().sendError(403);
|
||||
}
|
||||
|
||||
private boolean isDefaultAccessDeniedUri(Request request, PolicyEnforcerConfig enforcerConfig) {
|
||||
String accessDeniedPath = enforcerConfig.getOnDenyRedirectTo();
|
||||
|
||||
|
|
|
@ -56,6 +56,9 @@ public class BearerTokenPolicyEnforcer extends AbstractPolicyEnforcer {
|
|||
String authorizationServerUri = authzClient.getServerConfiguration().getIssuer().toString() + "/authz/entitlement";
|
||||
response.setStatus(401);
|
||||
response.setHeader("WWW-Authenticate", "KC_ETT realm=\"" + clientId + "\",as_uri=\"" + authorizationServerUri + "\"");
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Sending Entitlement challenge");
|
||||
}
|
||||
}
|
||||
|
||||
private void challengeUmaAuthentication(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
|
||||
|
@ -66,6 +69,9 @@ public class BearerTokenPolicyEnforcer extends AbstractPolicyEnforcer {
|
|||
String authorizationServerUri = authzClient.getServerConfiguration().getIssuer().toString() + "/authz/authorize";
|
||||
response.setStatus(401);
|
||||
response.setHeader("WWW-Authenticate", "UMA realm=\"" + clientId + "\",as_uri=\"" + authorizationServerUri + "\",ticket=\"" + ticket + "\"");
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Sending UMA challenge");
|
||||
}
|
||||
}
|
||||
|
||||
private String getPermissionTicket(PathConfig pathConfig, Set<String> requiredScopes, AuthzClient authzClient) {
|
||||
|
|
|
@ -83,6 +83,12 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
|||
|
||||
@Override
|
||||
protected boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
|
||||
handleAccessDenied(facade);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleAccessDenied(OIDCHttpFacade facade) {
|
||||
String accessDeniedPath = getEnforcerConfig().getOnDenyRedirectTo();
|
||||
HttpFacade.Response response = facade.getResponse();
|
||||
|
||||
|
@ -92,8 +98,6 @@ public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
|
|||
} else {
|
||||
response.sendError(403);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private AccessToken requestAuthorizationToken(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade httpFacade) {
|
||||
|
|
|
@ -49,7 +49,6 @@ class PathMatcher {
|
|||
|
||||
PathConfig matchingAnyPath = null;
|
||||
PathConfig matchingAnySuffixPath = null;
|
||||
PathConfig matchingPath = null;
|
||||
|
||||
for (PathConfig entry : paths.values()) {
|
||||
String expectedUri = entry.getPath();
|
||||
|
@ -132,58 +131,79 @@ class PathMatcher {
|
|||
return targetUri.startsWith(expectedUri.substring(0, expectedUri.length() - 2));
|
||||
}
|
||||
|
||||
String suffix = "/*.";
|
||||
int suffixIndex = expectedUri.indexOf(suffix);
|
||||
|
||||
if (suffixIndex != -1) {
|
||||
return targetUri.endsWith(expectedUri.substring(suffixIndex + suffix.length() - 1));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public String buildUriFromTemplate(String expectedUri, String targetUri) {
|
||||
int patternStartIndex = expectedUri.indexOf("{");
|
||||
|
||||
if (patternStartIndex >= targetUri.length()) {
|
||||
if (patternStartIndex == -1 || patternStartIndex >= targetUri.length()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (expectedUri.split("/").length > targetUri.split("/").length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
char[] expectedUriChars = expectedUri.toCharArray();
|
||||
char[] matchingUri = Arrays.copyOfRange(expectedUriChars, 0, patternStartIndex);
|
||||
int matchingUriLastIndex = matchingUri.length;
|
||||
String targetUriParams = targetUri.substring(patternStartIndex);
|
||||
|
||||
if (Arrays.equals(matchingUri, Arrays.copyOf(targetUri.toCharArray(), matchingUri.length))) {
|
||||
int matchingLastIndex = matchingUri.length;
|
||||
matchingUri = Arrays.copyOf(matchingUri, targetUri.length()); // +1 so we can add a slash at the end
|
||||
int targetPatternStartIndex = patternStartIndex;
|
||||
matchingUri = Arrays.copyOf(matchingUri, targetUri.length());
|
||||
int paramIndex = 0;
|
||||
|
||||
while (patternStartIndex != -1) {
|
||||
int parameterStartIndex = -1;
|
||||
|
||||
for (int i = targetPatternStartIndex; i < targetUri.length(); i++) {
|
||||
char c = targetUri.charAt(i);
|
||||
|
||||
if (c != '/') {
|
||||
if (parameterStartIndex == -1) {
|
||||
parameterStartIndex = matchingLastIndex;
|
||||
}
|
||||
matchingUri[matchingLastIndex] = c;
|
||||
matchingLastIndex++;
|
||||
}
|
||||
|
||||
if (c == '/' || ((i + 1 == targetUri.length()))) {
|
||||
if (matchingUri[matchingLastIndex - 1] != '/' && matchingLastIndex < matchingUri.length) {
|
||||
matchingUri[matchingLastIndex] = '/';
|
||||
matchingLastIndex++;
|
||||
}
|
||||
|
||||
targetPatternStartIndex = targetUri.indexOf('/', i) + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((patternStartIndex = expectedUri.indexOf('{', patternStartIndex + 1)) == -1) {
|
||||
for (int i = patternStartIndex; i < expectedUriChars.length; i++) {
|
||||
if (matchingUriLastIndex >= matchingUri.length) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((targetPatternStartIndex == 0 || targetPatternStartIndex == targetUri.length()) && parameterStartIndex != -1) {
|
||||
return null;
|
||||
char c = expectedUriChars[i];
|
||||
|
||||
if (c == '{' || c == '*') {
|
||||
String[] params = targetUriParams.split("/");
|
||||
|
||||
for (int k = paramIndex; k <= (c == '*' ? params.length : paramIndex); k++) {
|
||||
if (k == params.length) {
|
||||
break;
|
||||
}
|
||||
|
||||
int paramLength = params[k].length();
|
||||
|
||||
if (matchingUriLastIndex + paramLength > matchingUri.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int j = 0; j < paramLength; j++) {
|
||||
matchingUri[matchingUriLastIndex++] = params[k].charAt(j);
|
||||
}
|
||||
|
||||
if (c == '*' && matchingUriLastIndex < matchingUri.length) {
|
||||
matchingUri[matchingUriLastIndex++] = '/';
|
||||
}
|
||||
}
|
||||
|
||||
i = expectedUri.indexOf('}', i);
|
||||
} else {
|
||||
if (c == '/') {
|
||||
paramIndex++;
|
||||
}
|
||||
matchingUri[matchingUriLastIndex++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingUri[matchingUri.length - 1] == '\u0000') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return String.valueOf(matchingUri);
|
||||
}
|
||||
|
||||
|
|
|
@ -220,7 +220,14 @@ public class PolicyEnforcer {
|
|||
|
||||
pathConfig.setId(resourceDescription.getId());
|
||||
pathConfig.setName(resourceDescription.getName());
|
||||
pathConfig.setPath(resourceDescription.getUri());
|
||||
|
||||
String uri = resourceDescription.getUri();
|
||||
|
||||
if (uri == null || "".equals(uri.trim())) {
|
||||
throw new RuntimeException("Failed to configure paths. Resource [" + resourceDescription.getName() + "] has an invalid or empty URI [" + uri + "].");
|
||||
}
|
||||
|
||||
pathConfig.setPath(uri);
|
||||
|
||||
List<String> scopeNames = new ArrayList<>();
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@
|
|||
processCallback(callback, initPromise);
|
||||
return;
|
||||
} else if (initOptions) {
|
||||
if (initOptions.refreshToken) {
|
||||
if (initOptions.token && initOptions.refreshToken) {
|
||||
setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken);
|
||||
|
||||
if (loginIframe.enable) {
|
||||
|
@ -832,7 +832,7 @@
|
|||
document.body.appendChild(iframe);
|
||||
|
||||
var messageCallback = function(event) {
|
||||
if ((event.origin !== loginIframe.iframeOrigin) || (loginIframe.iframe.contentWindow !== event.source)) {
|
||||
if ((event.origin !== loginIframe.iframeOrigin) || (loginIframe.iframe.contentWindow !== event.source)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1228,7 +1228,7 @@
|
|||
break;
|
||||
default:
|
||||
if (responseMode != 'query' || !handleQueryParam(param, queryParams[param], oauth)) {
|
||||
oauth.newUrl += (oauth.newUrl.indexOf('?') == -1 ? '?' : '&') + param + '=' + queryParams[param];
|
||||
oauth.newUrl += (oauth.newUrl.indexOf('?') == -1 ? '?' : '&') + param + '=' + encodeURIComponent(queryParams[param]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
<!--
|
||||
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
~ and other contributors as indicated by the @author tags.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<script>
|
||||
function getCookie(cname)
|
||||
{
|
||||
var name = cname + "=";
|
||||
var ca = document.cookie.split(';');
|
||||
for(var i=0; i<ca.length; i++)
|
||||
{
|
||||
var c = ca[i].trim();
|
||||
if (c.indexOf(name)==0) return c.substring(name.length,c.length);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function receiveMessage(event)
|
||||
{
|
||||
if (event.origin !== "ORIGIN") {
|
||||
console.log(event.origin + " does not match built origin");
|
||||
return;
|
||||
|
||||
}
|
||||
var data = JSON.parse(event.data);
|
||||
data.loggedIn = false;
|
||||
var cookie = getCookie('KEYCLOAK_SESSION');
|
||||
if (cookie) {
|
||||
data.loggedIn = true;
|
||||
data.session = cookie;
|
||||
}
|
||||
|
||||
event.source.postMessage(JSON.stringify(data),
|
||||
event.origin);
|
||||
}
|
||||
window.addEventListener("message", receiveMessage, false);
|
||||
</script>
|
|
@ -56,7 +56,7 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-jetty92-adapter</artifactId>
|
||||
<artifactId>keycloak-jetty93-adapter</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
|
|
@ -141,10 +141,10 @@ public class KeycloakSpringBootConfiguration {
|
|||
List<io.undertow.servlet.api.SecurityConstraint> undertowSecurityConstraints = new ArrayList<io.undertow.servlet.api.SecurityConstraint>();
|
||||
for (KeycloakSpringBootProperties.SecurityConstraint constraintDefinition : keycloakProperties.getSecurityConstraints()) {
|
||||
|
||||
for (KeycloakSpringBootProperties.SecurityCollection collectionDefinition : constraintDefinition.getSecurityCollections()) {
|
||||
io.undertow.servlet.api.SecurityConstraint undertowSecurityConstraint = new io.undertow.servlet.api.SecurityConstraint();
|
||||
undertowSecurityConstraint.addRolesAllowed(constraintDefinition.getAuthRoles());
|
||||
|
||||
io.undertow.servlet.api.SecurityConstraint undertowSecurityConstraint = new io.undertow.servlet.api.SecurityConstraint();
|
||||
undertowSecurityConstraint.addRolesAllowed(collectionDefinition.getAuthRoles());
|
||||
for (KeycloakSpringBootProperties.SecurityCollection collectionDefinition : constraintDefinition.getSecurityCollections()) {
|
||||
|
||||
WebResourceCollection webResourceCollection = new WebResourceCollection();
|
||||
webResourceCollection.addHttpMethods(collectionDefinition.getMethods());
|
||||
|
@ -153,8 +153,9 @@ public class KeycloakSpringBootConfiguration {
|
|||
|
||||
undertowSecurityConstraint.addWebResourceCollections(webResourceCollection);
|
||||
|
||||
undertowSecurityConstraints.add(undertowSecurityConstraint);
|
||||
}
|
||||
|
||||
undertowSecurityConstraints.add(undertowSecurityConstraint);
|
||||
}
|
||||
return undertowSecurityConstraints;
|
||||
}
|
||||
|
@ -174,42 +175,70 @@ public class KeycloakSpringBootConfiguration {
|
|||
KeycloakJettyAuthenticator keycloakJettyAuthenticator = new KeycloakJettyAuthenticator();
|
||||
keycloakJettyAuthenticator.setConfigResolver(new KeycloakSpringBootConfigResolver());
|
||||
|
||||
/* see org.eclipse.jetty.webapp.StandardDescriptorProcessor#visitSecurityConstraint for an example
|
||||
on how to map servlet spec to Constraints */
|
||||
|
||||
List<ConstraintMapping> jettyConstraintMappings = new ArrayList<ConstraintMapping>();
|
||||
for (KeycloakSpringBootProperties.SecurityConstraint constraintDefinition : keycloakProperties.getSecurityConstraints()) {
|
||||
|
||||
for (KeycloakSpringBootProperties.SecurityCollection securityCollectionDefinition : constraintDefinition
|
||||
.getSecurityCollections()) {
|
||||
|
||||
// securityCollection matches servlet spec's web-resource-collection
|
||||
Constraint jettyConstraint = new Constraint();
|
||||
|
||||
if (constraintDefinition.getAuthRoles().size() > 0) {
|
||||
jettyConstraint.setAuthenticate(true);
|
||||
jettyConstraint.setRoles(constraintDefinition.getAuthRoles().toArray(new String[0]));
|
||||
}
|
||||
|
||||
jettyConstraint.setName(securityCollectionDefinition.getName());
|
||||
jettyConstraint.setAuthenticate(true);
|
||||
|
||||
if (securityCollectionDefinition.getName() != null) {
|
||||
jettyConstraint.setName(securityCollectionDefinition.getName());
|
||||
// according to the servlet spec each security-constraint has at least one URL pattern
|
||||
for(String pattern : securityCollectionDefinition.getPatterns()) {
|
||||
|
||||
/* the following code is asymmetric as Jetty's ConstraintMapping accepts only one allowed HTTP method,
|
||||
but multiple omitted methods. Therefore we add one ConstraintMapping for each allowed
|
||||
mapping but only one mapping in the cases of omitted methods or no methods.
|
||||
*/
|
||||
|
||||
if (securityCollectionDefinition.getMethods().size() > 0) {
|
||||
// according to the servlet spec we have either methods ...
|
||||
for(String method : securityCollectionDefinition.getMethods()) {
|
||||
ConstraintMapping jettyConstraintMapping = new ConstraintMapping();
|
||||
jettyConstraintMappings.add(jettyConstraintMapping);
|
||||
|
||||
jettyConstraintMapping.setConstraint(jettyConstraint);
|
||||
jettyConstraintMapping.setPathSpec(pattern);
|
||||
jettyConstraintMapping.setMethod(method);
|
||||
}
|
||||
} else if (securityCollectionDefinition.getOmittedMethods().size() > 0){
|
||||
// ... omitted methods ...
|
||||
ConstraintMapping jettyConstraintMapping = new ConstraintMapping();
|
||||
jettyConstraintMappings.add(jettyConstraintMapping);
|
||||
|
||||
jettyConstraintMapping.setConstraint(jettyConstraint);
|
||||
jettyConstraintMapping.setPathSpec(pattern);
|
||||
jettyConstraintMapping.setMethodOmissions(
|
||||
securityCollectionDefinition.getOmittedMethods().toArray(new String[0]));
|
||||
} else {
|
||||
// ... or no methods at all
|
||||
ConstraintMapping jettyConstraintMapping = new ConstraintMapping();
|
||||
jettyConstraintMappings.add(jettyConstraintMapping);
|
||||
|
||||
jettyConstraintMapping.setConstraint(jettyConstraint);
|
||||
jettyConstraintMapping.setPathSpec(pattern);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
jettyConstraint.setRoles(securityCollectionDefinition.getAuthRoles().toArray(new String[0]));
|
||||
|
||||
ConstraintMapping jettyConstraintMapping = new ConstraintMapping();
|
||||
if (securityCollectionDefinition.getPatterns().size() > 0) {
|
||||
//First pattern wins
|
||||
jettyConstraintMapping.setPathSpec(securityCollectionDefinition.getPatterns().get(0));
|
||||
jettyConstraintMapping.setConstraint(jettyConstraint);
|
||||
}
|
||||
|
||||
if (securityCollectionDefinition.getMethods().size() > 0) {
|
||||
//First method wins
|
||||
jettyConstraintMapping.setMethod(securityCollectionDefinition.getMethods().get(0));
|
||||
}
|
||||
|
||||
jettyConstraintMapping.setMethodOmissions(
|
||||
securityCollectionDefinition.getOmittedMethods().toArray(new String[0]));
|
||||
|
||||
jettyConstraintMappings.add(jettyConstraintMapping);
|
||||
}
|
||||
}
|
||||
|
||||
WebAppContext webAppContext = server.getBean(WebAppContext.class);
|
||||
//if not found as registered bean let's try the handler
|
||||
if(webAppContext==null){
|
||||
webAppContext = (WebAppContext) server.getHandler();
|
||||
}
|
||||
|
||||
ConstraintSecurityHandler securityHandler = new ConstraintSecurityHandler();
|
||||
securityHandler.setConstraintMappings(jettyConstraintMappings);
|
||||
|
@ -235,12 +264,10 @@ public class KeycloakSpringBootConfiguration {
|
|||
|
||||
Set<String> authRoles = new HashSet<String>();
|
||||
for (KeycloakSpringBootProperties.SecurityConstraint constraint : keycloakProperties.getSecurityConstraints()) {
|
||||
for (KeycloakSpringBootProperties.SecurityCollection collection : constraint.getSecurityCollections()) {
|
||||
for (String authRole : collection.getAuthRoles()) {
|
||||
if (!authRoles.contains(authRole)) {
|
||||
context.addSecurityRole(authRole);
|
||||
authRoles.add(authRole);
|
||||
}
|
||||
for (String authRole : constraint.getAuthRoles()) {
|
||||
if (!authRoles.contains(authRole)) {
|
||||
context.addSecurityRole(authRole);
|
||||
authRoles.add(authRole);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -248,6 +275,10 @@ public class KeycloakSpringBootConfiguration {
|
|||
for (KeycloakSpringBootProperties.SecurityConstraint constraint : keycloakProperties.getSecurityConstraints()) {
|
||||
SecurityConstraint tomcatConstraint = new SecurityConstraint();
|
||||
|
||||
for (String authRole : constraint.getAuthRoles()) {
|
||||
tomcatConstraint.addAuthRole(authRole);
|
||||
}
|
||||
|
||||
for (KeycloakSpringBootProperties.SecurityCollection collection : constraint.getSecurityCollections()) {
|
||||
SecurityCollection tomcatSecCollection = new SecurityCollection();
|
||||
|
||||
|
@ -258,10 +289,6 @@ public class KeycloakSpringBootConfiguration {
|
|||
tomcatSecCollection.setDescription(collection.getDescription());
|
||||
}
|
||||
|
||||
for (String authRole : collection.getAuthRoles()) {
|
||||
tomcatConstraint.addAuthRole(authRole);
|
||||
}
|
||||
|
||||
for (String pattern : collection.getPatterns()) {
|
||||
tomcatSecCollection.addPattern(pattern);
|
||||
}
|
||||
|
|
|
@ -43,12 +43,20 @@ public class KeycloakSpringBootProperties extends AdapterConfig {
|
|||
*/
|
||||
private List<SecurityConstraint> securityConstraints = new ArrayList<SecurityConstraint>();
|
||||
|
||||
/**
|
||||
* This matches security-constraint of the servlet spec
|
||||
*/
|
||||
@ConfigurationProperties()
|
||||
public static class SecurityConstraint {
|
||||
/**
|
||||
* A list of security collections
|
||||
*/
|
||||
private List<SecurityCollection> securityCollections = new ArrayList<SecurityCollection>();
|
||||
private List<String> authRoles = new ArrayList<String>();
|
||||
|
||||
public List<String> getAuthRoles() {
|
||||
return authRoles;
|
||||
}
|
||||
|
||||
public List<SecurityCollection> getSecurityCollections() {
|
||||
return securityCollections;
|
||||
|
@ -57,7 +65,16 @@ public class KeycloakSpringBootProperties extends AdapterConfig {
|
|||
public void setSecurityCollections(List<SecurityCollection> securityCollections) {
|
||||
this.securityCollections = securityCollections;
|
||||
}
|
||||
|
||||
public void setAuthRoles(List<String> authRoles) {
|
||||
this.authRoles = authRoles;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This matches web-resource-collection of the servlet spec
|
||||
*/
|
||||
@ConfigurationProperties()
|
||||
public static class SecurityCollection {
|
||||
/**
|
||||
|
@ -68,10 +85,6 @@ public class KeycloakSpringBootProperties extends AdapterConfig {
|
|||
* The description of your security collection
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* A list of roles that applies for this security collection
|
||||
*/
|
||||
private List<String> authRoles = new ArrayList<String>();
|
||||
/**
|
||||
* A list of URL patterns that should match to apply the security collection
|
||||
*/
|
||||
|
@ -85,10 +98,6 @@ public class KeycloakSpringBootProperties extends AdapterConfig {
|
|||
*/
|
||||
private List<String> omittedMethods = new ArrayList<String>();
|
||||
|
||||
public List<String> getAuthRoles() {
|
||||
return authRoles;
|
||||
}
|
||||
|
||||
public List<String> getPatterns() {
|
||||
return patterns;
|
||||
}
|
||||
|
@ -117,10 +126,6 @@ public class KeycloakSpringBootProperties extends AdapterConfig {
|
|||
this.description = description;
|
||||
}
|
||||
|
||||
public void setAuthRoles(List<String> authRoles) {
|
||||
this.authRoles = authRoles;
|
||||
}
|
||||
|
||||
public void setPatterns(List<String> patterns) {
|
||||
this.patterns = patterns;
|
||||
}
|
||||
|
|
|
@ -167,7 +167,12 @@ public class SharedAttributeDefinitons {
|
|||
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||
.build();
|
||||
|
||||
|
||||
protected static final SimpleAttributeDefinition AUTODETECT_BEARER_ONLY =
|
||||
new SimpleAttributeDefinitionBuilder("autodetect-bearer-only", ModelType.BOOLEAN, true)
|
||||
.setXmlName("autodetect-bearer-only")
|
||||
.setAllowExpression(true)
|
||||
.setDefaultValue(new ModelNode(false))
|
||||
.build();
|
||||
|
||||
protected static final List<SimpleAttributeDefinition> ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
|
||||
static {
|
||||
|
@ -193,6 +198,7 @@ public class SharedAttributeDefinitons {
|
|||
ATTRIBUTES.add(REGISTER_NODE_PERIOD);
|
||||
ATTRIBUTES.add(TOKEN_STORE);
|
||||
ATTRIBUTES.add(PRINCIPAL_ATTRIBUTE);
|
||||
ATTRIBUTES.add(AUTODETECT_BEARER_ONLY);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -46,7 +46,7 @@ keycloak.realm.register-node-at-startup=Cluster setting
|
|||
keycloak.realm.register-node-period=how often to re-register node
|
||||
keycloak.realm.token-store=cookie or session storage for auth session data
|
||||
keycloak.realm.principal-attribute=token attribute to use to set Principal name
|
||||
|
||||
keycloak.realm.autodetect-bearer-only=autodetect bearer-only requests
|
||||
|
||||
keycloak.secure-deployment=A deployment secured by Keycloak
|
||||
keycloak.secure-deployment.add=Add a deployment to be secured by Keycloak
|
||||
|
@ -83,6 +83,7 @@ keycloak.secure-deployment.principal-attribute=token attribute to use to set Pri
|
|||
keycloak.secure-deployment.turn-off-change-session-id-on-login=The session id is changed by default on a successful login. Change this to true if you want to turn this off
|
||||
keycloak.secure-deployment.token-minimum-time-to-live=The adapter will refresh the token if the current token is expired OR will expire in 'token-minimum-time-to-live' seconds or less
|
||||
keycloak.secure-deployment.min-time-between-jwks-requests=If adapter recognize token signed by unknown public key, it will try to download new public key from keycloak server. However it won't try to download if already tried it in less than 'min-time-between-jwks-requests' seconds
|
||||
keycloak.secure-deployment.autodetect-bearer-only=autodetect bearer-only requests
|
||||
|
||||
keycloak.secure-deployment.credential=Credential value
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
<xs:element name="register-node-period" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="token-store" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="principal-attribute" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="autodetect-bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:all>
|
||||
<xs:attribute name="name" type="xs:string" use="required">
|
||||
<xs:annotation>
|
||||
|
@ -107,6 +108,7 @@
|
|||
<xs:element name="turn-off-change-session-id-on-login" type="xs:boolean" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="token-minimum-time-to-live" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="min-time-between-jwks-requests" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="autodetect-bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:all>
|
||||
<xs:attribute name="name" type="xs:string" use="required">
|
||||
<xs:annotation>
|
||||
|
|
|
@ -166,6 +166,12 @@ public class SharedAttributeDefinitons {
|
|||
.setAllowExpression(true)
|
||||
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
|
||||
.build();
|
||||
protected static final SimpleAttributeDefinition AUTODETECT_BEARER_ONLY =
|
||||
new SimpleAttributeDefinitionBuilder("autodetect-bearer-only", ModelType.BOOLEAN, true)
|
||||
.setXmlName("autodetect-bearer-only")
|
||||
.setAllowExpression(true)
|
||||
.setDefaultValue(new ModelNode(false))
|
||||
.build();
|
||||
|
||||
|
||||
|
||||
|
@ -193,6 +199,7 @@ public class SharedAttributeDefinitons {
|
|||
ATTRIBUTES.add(REGISTER_NODE_PERIOD);
|
||||
ATTRIBUTES.add(TOKEN_STORE);
|
||||
ATTRIBUTES.add(PRINCIPAL_ATTRIBUTE);
|
||||
ATTRIBUTES.add(AUTODETECT_BEARER_ONLY);
|
||||
}
|
||||
|
||||
private static boolean isSet(ModelNode attributes, SimpleAttributeDefinition def) {
|
||||
|
|
|
@ -46,7 +46,7 @@ keycloak.realm.register-node-at-startup=Cluster setting
|
|||
keycloak.realm.register-node-period=how often to re-register node
|
||||
keycloak.realm.token-store=cookie or session storage for auth session data
|
||||
keycloak.realm.principal-attribute=token attribute to use to set Principal name
|
||||
|
||||
keycloak.realm.autodetect-bearer-only=autodetect bearer-only requests
|
||||
|
||||
keycloak.secure-deployment=A deployment secured by Keycloak
|
||||
keycloak.secure-deployment.add=Add a deployment to be secured by Keycloak
|
||||
|
@ -67,6 +67,7 @@ keycloak.secure-deployment.bearer-only=Bearer Token Auth only
|
|||
keycloak.secure-deployment.enable-basic-auth=Enable Basic Authentication
|
||||
keycloak.secure-deployment.public-client=Public client
|
||||
keycloak.secure-deployment.enable-cors=Enable Keycloak CORS support
|
||||
keycloak.secure-deployment.autodetect-bearer-only=autodetect bearer-only requests
|
||||
keycloak.secure-deployment.client-keystore=n/a
|
||||
keycloak.secure-deployment.client-keystore-password=n/a
|
||||
keycloak.secure-deployment.client-key-password=n/a
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
<xs:element name="register-node-period" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="token-store" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="principal-attribute" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="autodetect-bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:all>
|
||||
<xs:attribute name="name" type="xs:string" use="required">
|
||||
<xs:annotation>
|
||||
|
@ -107,6 +108,7 @@
|
|||
<xs:element name="turn-off-change-session-id-on-login" type="xs:boolean" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="token-minimum-time-to-live" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="min-time-between-jwks-requests" type="xs:integer" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="autodetect-bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:all>
|
||||
<xs:attribute name="name" type="xs:string" use="required">
|
||||
<xs:annotation>
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.keycloak.authorization.policy.provider.aggregated;
|
||||
|
||||
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) {
|
||||
|
||||
}
|
||||
}
|
|
@ -17,19 +17,24 @@
|
|||
*/
|
||||
package org.keycloak.authorization.policy.provider.aggregated;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
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.representations.idm.authorization.PolicyRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class AggregatePolicyProviderFactory implements PolicyProviderFactory {
|
||||
public class AggregatePolicyProviderFactory implements PolicyProviderFactory<PolicyRepresentation> {
|
||||
|
||||
private AggregatePolicyProvider provider = new AggregatePolicyProvider();
|
||||
|
||||
|
@ -49,8 +54,8 @@ public class AggregatePolicyProviderFactory implements PolicyProviderFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
|
||||
return new AggregatePolicyAdminResource(resourceServer);
|
||||
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer, AuthorizationProvider authorization) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -58,6 +63,37 @@ public class AggregatePolicyProviderFactory implements PolicyProviderFactory {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
|
||||
verifyCircularReference(policy, new ArrayList<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
|
||||
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, AuthorizationProvider authorization) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ public class ClientPolicyProviderFactory implements PolicyProviderFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
|
||||
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer, AuthorizationProvider authorization) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -78,9 +78,6 @@ public class ClientPolicyProviderFactory implements PolicyProviderFactory {
|
|||
|
||||
try {
|
||||
if (clients.isEmpty()) {
|
||||
policyStore.findDependentPolicies(policy.getId(), resourceServer.getId()).forEach(dependentPolicy -> {
|
||||
dependentPolicy.removeAssociatedPolicy(policy);
|
||||
});
|
||||
policyStore.delete(policy.getId());
|
||||
} else {
|
||||
policy.getConfig().put("clients", JsonSerialization.writeValueAsString(clients));
|
||||
|
|
|
@ -42,7 +42,7 @@ public class JSPolicyProviderFactory implements PolicyProviderFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
|
||||
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer, AuthorizationProvider authorization) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
package org.keycloak.authorization.policy.provider.resource;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
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.representations.idm.authorization.ResourcePermissionRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class ResourcePolicyProviderFactory implements PolicyProviderFactory {
|
||||
public class ResourcePolicyProviderFactory implements PolicyProviderFactory<ResourcePermissionRepresentation> {
|
||||
|
||||
private ResourcePolicyProvider provider = new ResourcePolicyProvider();
|
||||
|
||||
|
@ -32,8 +34,14 @@ public class ResourcePolicyProviderFactory implements PolicyProviderFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
|
||||
return null;
|
||||
public Class<ResourcePermissionRepresentation> getRepresentationType() {
|
||||
return ResourcePermissionRepresentation.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourcePermissionRepresentation toRepresentation(Policy policy, ResourcePermissionRepresentation representation) {
|
||||
representation.setResourceType(policy.getConfig().get("defaultResourceType"));
|
||||
return representation;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -41,6 +49,39 @@ public class ResourcePolicyProviderFactory implements PolicyProviderFactory {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Policy policy, ResourcePermissionRepresentation representation, AuthorizationProvider authorization) {
|
||||
updateResourceType(policy, representation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(Policy policy, ResourcePermissionRepresentation representation, AuthorizationProvider authorization) {
|
||||
updateResourceType(policy, representation);
|
||||
}
|
||||
|
||||
private void updateResourceType(Policy policy, ResourcePermissionRepresentation representation) {
|
||||
if (representation != null) {
|
||||
//TODO: remove this check once we migrate to new API
|
||||
if (ResourcePermissionRepresentation.class.equals(representation.getClass())) {
|
||||
ResourcePermissionRepresentation resourcePermission = ResourcePermissionRepresentation.class.cast(representation);
|
||||
Map<String, String> config = policy.getConfig();
|
||||
|
||||
config.compute("defaultResourceType", (key, value) -> {
|
||||
String resourceType = resourcePermission.getResourceType();
|
||||
return resourceType != null ? resourcePermission.getResourceType() : null;
|
||||
});
|
||||
|
||||
policy.setConfig(config);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(Policy policy, AuthorizationProvider authorization) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
|
||||
|
|
|
@ -35,19 +35,23 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.RoleContainerModel;
|
||||
import org.keycloak.models.RoleContainerModel.RoleRemovedEvent;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class RolePolicyProviderFactory implements PolicyProviderFactory {
|
||||
public class RolePolicyProviderFactory implements PolicyProviderFactory<RolePolicyRepresentation> {
|
||||
|
||||
private RolePolicyProvider provider = new RolePolicyProvider();
|
||||
|
||||
|
@ -67,7 +71,7 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
|
||||
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer, AuthorizationProvider authorization) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -76,6 +80,107 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory {
|
|||
return new RolePolicyProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RolePolicyRepresentation toRepresentation(Policy policy, RolePolicyRepresentation representation) {
|
||||
try {
|
||||
representation.setRoles(JsonSerialization.readValue(policy.getConfig().get("roles"), Set.class));
|
||||
} catch (IOException cause) {
|
||||
throw new RuntimeException("Failed to deserialize roles", cause);
|
||||
}
|
||||
return representation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<RolePolicyRepresentation> getRepresentationType() {
|
||||
return RolePolicyRepresentation.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Policy policy, RolePolicyRepresentation representation, AuthorizationProvider authorization) {
|
||||
updateRoles(policy, representation, authorization);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(Policy policy, RolePolicyRepresentation representation, AuthorizationProvider authorization) {
|
||||
updateRoles(policy, representation, authorization);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onImport(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
|
||||
try {
|
||||
updateRoles(policy, authorization, new HashSet<>(Arrays.asList(JsonSerialization.readValue(representation.getConfig().get("roles"), RolePolicyRepresentation.RoleDefinition[].class))));
|
||||
} catch (IOException cause) {
|
||||
throw new RuntimeException("Failed to deserialize roles during import", cause);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateRoles(Policy policy, RolePolicyRepresentation representation, AuthorizationProvider authorization) {
|
||||
updateRoles(policy, authorization, representation.getRoles());
|
||||
}
|
||||
|
||||
private void updateRoles(Policy policy, AuthorizationProvider authorization, Set<RolePolicyRepresentation.RoleDefinition> roles) {
|
||||
try {
|
||||
RealmModel realm = authorization.getRealm();
|
||||
Set<RolePolicyRepresentation.RoleDefinition> updatedRoles = new HashSet<>();
|
||||
|
||||
if (roles != null) {
|
||||
for (RolePolicyRepresentation.RoleDefinition definition : roles) {
|
||||
String roleName = definition.getId();
|
||||
String clientId = null;
|
||||
int clientIdSeparator = roleName.indexOf("/");
|
||||
|
||||
if (clientIdSeparator != -1) {
|
||||
clientId = roleName.substring(0, clientIdSeparator);
|
||||
roleName = roleName.substring(clientIdSeparator + 1);
|
||||
}
|
||||
|
||||
RoleModel role;
|
||||
|
||||
if (clientId == null) {
|
||||
role = realm.getRole(roleName);
|
||||
|
||||
if (role == null) {
|
||||
role = realm.getRoleById(roleName);
|
||||
}
|
||||
} else {
|
||||
ClientModel client = realm.getClientByClientId(clientId);
|
||||
|
||||
if (client == null) {
|
||||
throw new RuntimeException("Client with id [" + clientId + "] not found.");
|
||||
}
|
||||
|
||||
role = client.getRole(roleName);
|
||||
}
|
||||
|
||||
// fallback to find any client role with the given name
|
||||
if (role == null) {
|
||||
String finalRoleName = roleName;
|
||||
role = realm.getClients().stream().map(clientModel -> clientModel.getRole(finalRoleName)).filter(roleModel -> roleModel != null)
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
if (role == null) {
|
||||
throw new RuntimeException("Error while importing configuration. Role [" + roleName + "] could not be found.");
|
||||
}
|
||||
|
||||
definition.setId(role.getId());
|
||||
|
||||
updatedRoles.add(definition);
|
||||
}
|
||||
try {
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error while updating policy [" + policy.getName() + "].", e);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String> config = policy.getConfig();
|
||||
config.put("roles", JsonSerialization.writeValueAsString(updatedRoles));
|
||||
policy.setConfig(config);
|
||||
} catch (IOException cause) {
|
||||
throw new RuntimeException("Failed to deserialize roles", cause);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
|
||||
|
@ -125,12 +230,6 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory {
|
|||
|
||||
try {
|
||||
if (roles.isEmpty()) {
|
||||
policyStore.findDependentPolicies(policy.getId(), resourceServer.getId()).forEach(dependentPolicy -> {
|
||||
dependentPolicy.removeAssociatedPolicy(policy);
|
||||
if (dependentPolicy.getAssociatedPolicies().isEmpty()) {
|
||||
policyStore.delete(dependentPolicy.getId());
|
||||
}
|
||||
});
|
||||
policyStore.delete(policy.getId());
|
||||
} else {
|
||||
Map<String, String> config = policy.getConfig();
|
||||
|
|
|
@ -2,17 +2,17 @@ package org.keycloak.authorization.policy.provider.scope;
|
|||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
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.representations.idm.authorization.ScopePermissionRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class ScopePolicyProviderFactory implements PolicyProviderFactory {
|
||||
public class ScopePolicyProviderFactory implements PolicyProviderFactory<ScopePermissionRepresentation> {
|
||||
|
||||
private ScopePolicyProvider provider = new ScopePolicyProvider();
|
||||
|
||||
|
@ -32,13 +32,18 @@ public class ScopePolicyProviderFactory implements PolicyProviderFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
|
||||
public PolicyProvider create(KeycloakSession session) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolicyProvider create(KeycloakSession session) {
|
||||
return null;
|
||||
public Class<ScopePermissionRepresentation> getRepresentationType() {
|
||||
return ScopePermissionRepresentation.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScopePermissionRepresentation toRepresentation(Policy policy, ScopePermissionRepresentation representation) {
|
||||
return representation;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,45 +18,11 @@
|
|||
|
||||
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) {
|
||||
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 + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
package org.keycloak.authorization.policy.provider.time;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
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.representations.idm.authorization.PolicyRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class TimePolicyProviderFactory implements PolicyProviderFactory {
|
||||
public class TimePolicyProviderFactory implements PolicyProviderFactory<PolicyRepresentation> {
|
||||
|
||||
private TimePolicyProvider provider = new TimePolicyProvider();
|
||||
|
||||
|
@ -32,7 +36,7 @@ public class TimePolicyProviderFactory implements PolicyProviderFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
|
||||
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer, AuthorizationProvider authorization) {
|
||||
return new TimePolicyAdminResource();
|
||||
}
|
||||
|
||||
|
@ -41,6 +45,38 @@ public class TimePolicyProviderFactory implements PolicyProviderFactory {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
|
||||
validateConfig(policy);
|
||||
}
|
||||
|
||||
private void validateConfig(Policy policy) {
|
||||
String nbf = policy.getConfig().get("nbf");
|
||||
String noa = policy.getConfig().get("noa");
|
||||
|
||||
if (nbf != null && noa != null) {
|
||||
validateFormat(nbf);
|
||||
validateFormat(noa);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
|
||||
validateConfig(policy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(Policy policy, AuthorizationProvider authorization) {
|
||||
}
|
||||
|
||||
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 + "]");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
|
||||
|
|
|
@ -20,14 +20,16 @@ package org.keycloak.authorization.policy.provider.user;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
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.authorization.store.ResourceServerStore;
|
||||
|
@ -37,12 +39,15 @@ import org.keycloak.models.KeycloakSessionFactory;
|
|||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserModel.UserRemovedEvent;
|
||||
import org.keycloak.models.UserProvider;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class UserPolicyProviderFactory implements PolicyProviderFactory {
|
||||
public class UserPolicyProviderFactory implements PolicyProviderFactory<UserPolicyRepresentation> {
|
||||
|
||||
private UserPolicyProvider provider = new UserPolicyProvider();
|
||||
|
||||
|
@ -62,13 +67,86 @@ public class UserPolicyProviderFactory implements PolicyProviderFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
|
||||
public PolicyProvider create(KeycloakSession session) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolicyProvider create(KeycloakSession session) {
|
||||
return null;
|
||||
public UserPolicyRepresentation toRepresentation(Policy policy, UserPolicyRepresentation representation) {
|
||||
try {
|
||||
representation.setUsers(JsonSerialization.readValue(policy.getConfig().get("users"), Set.class));
|
||||
} catch (IOException cause) {
|
||||
throw new RuntimeException("Failed to deserialize roles", cause);
|
||||
}
|
||||
return representation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<UserPolicyRepresentation> getRepresentationType() {
|
||||
return UserPolicyRepresentation.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Policy policy, UserPolicyRepresentation representation, AuthorizationProvider authorization) {
|
||||
updateUsers(policy, representation, authorization);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(Policy policy, UserPolicyRepresentation representation, AuthorizationProvider authorization) {
|
||||
updateUsers(policy, representation, authorization);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onImport(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
|
||||
try {
|
||||
updateUsers(policy, authorization, JsonSerialization.readValue(representation.getConfig().get("users"), Set.class));
|
||||
} catch (IOException cause) {
|
||||
throw new RuntimeException("Failed to deserialize users during import", cause);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateUsers(Policy policy, UserPolicyRepresentation representation, AuthorizationProvider authorization) {
|
||||
updateUsers(policy, authorization, representation.getUsers());
|
||||
}
|
||||
|
||||
private void updateUsers(Policy policy, AuthorizationProvider authorization, Set<String> users) {
|
||||
try {
|
||||
KeycloakSession session = authorization.getKeycloakSession();
|
||||
RealmModel realm = authorization.getRealm();
|
||||
UserProvider userProvider = session.users();
|
||||
Set<String> updatedUsers = new HashSet<>();
|
||||
|
||||
if (users != null) {
|
||||
try {
|
||||
for (String userId : users) {
|
||||
UserModel user = null;
|
||||
|
||||
try {
|
||||
user = userProvider.getUserByUsername(userId, realm);
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
|
||||
if (user == null) {
|
||||
user = userProvider.getUserById(userId, realm);
|
||||
}
|
||||
|
||||
if (user == null) {
|
||||
throw new RuntimeException("Error while importing configuration. User [" + userId + "] could not be found.");
|
||||
}
|
||||
|
||||
updatedUsers.add(user.getId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error while updating policy [" + policy.getName() + "].", e);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String> config = policy.getConfig();
|
||||
config.put("users", JsonSerialization.writeValueAsString(updatedUsers));
|
||||
policy.setConfig(config);
|
||||
} catch (IOException cause) {
|
||||
throw new RuntimeException("Failed to deserialize roles", cause);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -102,12 +180,6 @@ public class UserPolicyProviderFactory implements PolicyProviderFactory {
|
|||
|
||||
try {
|
||||
if (users.isEmpty()) {
|
||||
policyStore.findDependentPolicies(policy.getId(), resourceServer.getId()).forEach(dependentPolicy -> {
|
||||
dependentPolicy.removeAssociatedPolicy(policy);
|
||||
if (dependentPolicy.getAssociatedPolicies().isEmpty()) {
|
||||
policyStore.delete(dependentPolicy.getId());
|
||||
}
|
||||
});
|
||||
policyStore.delete(policy.getId());
|
||||
} else {
|
||||
policy.getConfig().put("users", JsonSerialization.writeValueAsString(users));
|
||||
|
@ -133,16 +205,16 @@ public class UserPolicyProviderFactory implements PolicyProviderFactory {
|
|||
}
|
||||
|
||||
static String[] getUsers(Policy policy) {
|
||||
String roles = policy.getConfig().get("users");
|
||||
String users = policy.getConfig().get("users");
|
||||
|
||||
if (roles != null) {
|
||||
if (users != null) {
|
||||
try {
|
||||
return JsonSerialization.readValue(roles.getBytes(), String[].class);
|
||||
return JsonSerialization.readValue(users.getBytes(), String[].class);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Could not parse roles [" + roles + "] from policy config [" + policy.getName() + ".", e);
|
||||
throw new RuntimeException("Could not parse users [" + users + "] from policy config [" + policy.getName() + ".", e);
|
||||
}
|
||||
}
|
||||
|
||||
return new String[]{};
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
*/
|
||||
package org.keycloak.authorization.policy.provider.drools;
|
||||
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.kie.api.runtime.KieContainer;
|
||||
|
@ -33,29 +31,12 @@ import javax.ws.rs.core.Response;
|
|||
*/
|
||||
public class DroolsPolicyAdminResource implements PolicyProviderAdminService {
|
||||
|
||||
private final ResourceServer resourceServer;
|
||||
private final DroolsPolicyProviderFactory factory;
|
||||
|
||||
public DroolsPolicyAdminResource(ResourceServer resourceServer, DroolsPolicyProviderFactory factory) {
|
||||
this.resourceServer = resourceServer;
|
||||
public DroolsPolicyAdminResource(DroolsPolicyProviderFactory factory) {
|
||||
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")
|
||||
|
|
|
@ -13,6 +13,8 @@ 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.representations.idm.authorization.AbstractPolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.kie.api.KieServices;
|
||||
import org.kie.api.KieServices.Factory;
|
||||
import org.kie.api.runtime.KieContainer;
|
||||
|
@ -49,8 +51,8 @@ public class DroolsPolicyProviderFactory implements PolicyProviderFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
|
||||
return new DroolsPolicyAdminResource(resourceServer, this);
|
||||
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer, AuthorizationProvider authorization) {
|
||||
return new DroolsPolicyAdminResource(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -58,6 +60,26 @@ public class DroolsPolicyProviderFactory implements PolicyProviderFactory {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Policy policy, AbstractPolicyRepresentation representation, AuthorizationProvider authorization) {
|
||||
update(policy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(Policy policy, AbstractPolicyRepresentation representation, AuthorizationProvider authorization) {
|
||||
update(policy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onImport(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
|
||||
update(policy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(Policy policy, AuthorizationProvider authorization) {
|
||||
remove(policy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
this.ks = Factory.get();
|
||||
|
|
|
@ -53,7 +53,6 @@ public final class StreamUtil {
|
|||
* @param charset Charset used to decode the input stream
|
||||
* @return String representation of the input stream contents decoded using given charset
|
||||
* @throws IOException
|
||||
* @deprecated Use {@link #readString(java.io.InputStream, java.nio.charset.Charset)} variant.
|
||||
*/
|
||||
public static String readString(InputStream in, Charset charset) throws IOException
|
||||
{
|
||||
|
|
|
@ -22,6 +22,7 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Common Adapter configuration
|
||||
|
@ -58,7 +59,7 @@ public class BaseAdapterConfig extends BaseRealmConfig {
|
|||
@JsonProperty("public-client")
|
||||
protected boolean publicClient;
|
||||
@JsonProperty("credentials")
|
||||
protected Map<String, Object> credentials = new HashMap<>();
|
||||
protected Map<String, Object> credentials = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
|
||||
public boolean isUseResourceRoleMappings() {
|
||||
|
|
|
@ -196,10 +196,12 @@ public class PolicyEnforcerConfig {
|
|||
'}';
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public boolean hasPattern() {
|
||||
return getPath().indexOf("{") != -1;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public boolean isInstance() {
|
||||
return this.parentConfig != null;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* 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.idm.authorization;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class AbstractPolicyRepresentation {
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
private String description;
|
||||
private String type;
|
||||
private Set<String> policies;
|
||||
private Set<String> resources;
|
||||
private Set<String> scopes;
|
||||
private Logic logic = Logic.POSITIVE;
|
||||
private DecisionStrategy decisionStrategy = DecisionStrategy.UNANIMOUS;
|
||||
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public DecisionStrategy getDecisionStrategy() {
|
||||
return this.decisionStrategy;
|
||||
}
|
||||
|
||||
public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
|
||||
this.decisionStrategy = decisionStrategy;
|
||||
}
|
||||
|
||||
public Logic getLogic() {
|
||||
return logic;
|
||||
}
|
||||
|
||||
public void setLogic(Logic logic) {
|
||||
this.logic = logic;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Set<String> getPolicies() {
|
||||
return policies;
|
||||
}
|
||||
|
||||
public void addPolicy(String... id) {
|
||||
if (this.policies == null) {
|
||||
this.policies = new HashSet<>();
|
||||
}
|
||||
this.policies.addAll(Arrays.asList(id));
|
||||
}
|
||||
|
||||
public Set<String> getResources() {
|
||||
return resources;
|
||||
}
|
||||
|
||||
public void addResource(String id) {
|
||||
if (this.resources == null) {
|
||||
this.resources = new HashSet<>();
|
||||
}
|
||||
this.resources.add(id);
|
||||
}
|
||||
|
||||
public Set<String> getScopes() {
|
||||
return scopes;
|
||||
}
|
||||
|
||||
public void addScope(String... id) {
|
||||
if (this.scopes == null) {
|
||||
this.scopes = new HashSet<>();
|
||||
}
|
||||
this.scopes.addAll(Arrays.asList(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final AbstractPolicyRepresentation policy = (AbstractPolicyRepresentation) o;
|
||||
return Objects.equals(getId(), policy.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getId());
|
||||
}
|
||||
}
|
|
@ -18,53 +18,14 @@ package org.keycloak.representations.idm.authorization;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class PolicyRepresentation {
|
||||
public class PolicyRepresentation extends AbstractPolicyRepresentation {
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
private String description;
|
||||
private String type;
|
||||
private Logic logic = Logic.POSITIVE;
|
||||
private DecisionStrategy decisionStrategy = DecisionStrategy.UNANIMOUS;
|
||||
private Map<String, String> config = new HashMap();
|
||||
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public DecisionStrategy getDecisionStrategy() {
|
||||
return this.decisionStrategy;
|
||||
}
|
||||
|
||||
public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
|
||||
this.decisionStrategy = decisionStrategy;
|
||||
}
|
||||
|
||||
public Logic getLogic() {
|
||||
return logic;
|
||||
}
|
||||
|
||||
public void setLogic(Logic logic) {
|
||||
this.logic = logic;
|
||||
}
|
||||
|
||||
public Map<String, String> getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
@ -72,33 +33,4 @@ public class PolicyRepresentation {
|
|||
public void setConfig(Map<String, String> config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final PolicyRepresentation policy = (PolicyRepresentation) o;
|
||||
return Objects.equals(getId(), policy.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getId());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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.idm.authorization;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class ResourcePermissionRepresentation extends AbstractPolicyRepresentation {
|
||||
|
||||
private String resourceType;
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "resource";
|
||||
}
|
||||
|
||||
public void setResourceType(String resourceType) {
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
public String getResourceType() {
|
||||
return resourceType;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* 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.idm.authorization;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class RolePolicyRepresentation extends AbstractPolicyRepresentation {
|
||||
|
||||
private Set<RoleDefinition> roles;
|
||||
|
||||
public Set<RoleDefinition> getRoles() {
|
||||
return roles;
|
||||
}
|
||||
|
||||
public void setRoles(Set<RoleDefinition> roles) {
|
||||
this.roles = roles;
|
||||
}
|
||||
|
||||
public void addRole(String name, boolean required) {
|
||||
if (roles == null) {
|
||||
roles = new HashSet<>();
|
||||
}
|
||||
roles.add(new RoleDefinition(name, required));
|
||||
}
|
||||
|
||||
public void addRole(String name) {
|
||||
addRole(name, false);
|
||||
}
|
||||
|
||||
public void addClientRole(String clientId, String name) {
|
||||
addRole(clientId + "/" +name, false);
|
||||
}
|
||||
|
||||
public void addClientRole(String clientId, String name, boolean required) {
|
||||
addRole(clientId + "/" + name, required);
|
||||
}
|
||||
|
||||
public static class RoleDefinition {
|
||||
|
||||
private String id;
|
||||
private boolean required;
|
||||
|
||||
public RoleDefinition() {
|
||||
this(null, false);
|
||||
}
|
||||
|
||||
public RoleDefinition(String id, boolean required) {
|
||||
this.id = id;
|
||||
this.required = required;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public boolean isRequired() {
|
||||
return required;
|
||||
}
|
||||
|
||||
public void setRequired(boolean required) {
|
||||
this.required = required;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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.idm.authorization;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class ScopePermissionRepresentation extends AbstractPolicyRepresentation {
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "scope";
|
||||
}
|
||||
}
|
|
@ -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.representations.idm.authorization;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class UserPolicyRepresentation extends AbstractPolicyRepresentation {
|
||||
|
||||
private Set<String> users;
|
||||
|
||||
public Set<String> getUsers() {
|
||||
return users;
|
||||
}
|
||||
|
||||
public void setUsers(Set<String> users) {
|
||||
this.users= users;
|
||||
}
|
||||
|
||||
public void addUser(String name) {
|
||||
if (users == null) {
|
||||
users = new HashSet<>();
|
||||
}
|
||||
users.add(name);
|
||||
}
|
||||
}
|
|
@ -206,7 +206,6 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
|
@ -223,12 +222,10 @@
|
|||
<outputDirectory>target</outputDirectory>
|
||||
<workDirectory>target/assembly/work</workDirectory>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<tarLongFileMode>gnu</tarLongFileMode>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
<plugin>
|
||||
<groupId>org.wildfly.build</groupId>
|
||||
<artifactId>wildfly-feature-pack-build-maven-plugin</artifactId>
|
||||
<version>${wildfly.build-tools.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>feature-pack-build</id>
|
||||
|
@ -111,7 +112,6 @@
|
|||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<outputDirectory>target/</outputDirectory>
|
||||
<workDirectory>target/assembly/work</workDirectory>
|
||||
<tarLongFileMode>gnu</tarLongFileMode>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
|
|
@ -28,6 +28,43 @@
|
|||
<fileSet>
|
||||
<directory>target/${project.build.finalName}</directory>
|
||||
<outputDirectory/>
|
||||
<excludes>
|
||||
<exclude>configuration/**</exclude>
|
||||
</excludes>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/unpacked-themes/theme</directory>
|
||||
<outputDirectory>content/themes</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>src/main/resources/identity/module</directory>
|
||||
<includes>
|
||||
<include>**/**</include>
|
||||
</includes>
|
||||
<outputDirectory>modules/system/layers/keycloak/org/jboss/as/product/${product.slot}</outputDirectory>
|
||||
<filtered>true</filtered>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>src/main/resources/identity</directory>
|
||||
<includes>
|
||||
<include>product.conf</include>
|
||||
</includes>
|
||||
<outputDirectory>content/bin</outputDirectory>
|
||||
<filtered>true</filtered>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${configDir}</directory>
|
||||
<includes>
|
||||
<include>**/**</include>
|
||||
</includes>
|
||||
<outputDirectory>configuration</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>../../../</directory>
|
||||
<includes>
|
||||
<include>License.html</include>
|
||||
</includes>
|
||||
<outputDirectory>content</outputDirectory>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
</assembly>
|
|
@ -74,126 +74,6 @@
|
|||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-configuration</id>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>target/resources/configuration</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources/configuration</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-modules</id>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>target/resources/modules</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources/modules</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-content</id>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>target/resources/content</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources/content</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-identity</id>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>target/resources/content/bin</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources/identity</directory>
|
||||
<includes>
|
||||
<include>**/product.conf</include>
|
||||
</includes>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-identity-module</id>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>target/resources/modules/system/layers/keycloak/org/jboss/as/product/${product.slot}</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources/identity/module</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-themes</id>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>target/resources/content/themes</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>target/unpacked-themes/theme</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-license</id>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>target/resources/content</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>../../../</directory>
|
||||
<includes>
|
||||
<include>License.html</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.wildfly.build</groupId>
|
||||
<artifactId>wildfly-feature-pack-build-maven-plugin</artifactId>
|
||||
|
@ -206,11 +86,11 @@
|
|||
<phase>compile</phase>
|
||||
<configuration>
|
||||
<config-file>feature-pack-build.xml</config-file>
|
||||
<resources-dir>target/resources</resources-dir>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
|
@ -226,11 +106,9 @@
|
|||
<descriptor>assembly.xml</descriptor>
|
||||
</descriptors>
|
||||
<recompressZippedFiles>true</recompressZippedFiles>
|
||||
<finalName>${project.build.finalName}</finalName>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<outputDirectory>target/</outputDirectory>
|
||||
<workDirectory>target/assembly/work</workDirectory>
|
||||
<tarLongFileMode>gnu</tarLongFileMode>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
@ -248,8 +126,9 @@
|
|||
</activation>
|
||||
|
||||
<properties>
|
||||
<build-tools.version>${wildfly.build-tools.version}</build-tools.version>
|
||||
<feature.parent>org.wildfly:wildfly-feature-pack</feature.parent>
|
||||
<xmlns.domain>urn:jboss:domain:4.0</xmlns.domain>
|
||||
<configDir>src/main/resources/configuration</configDir>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@ -266,7 +145,9 @@
|
|||
<id>wf11</id>
|
||||
|
||||
<properties>
|
||||
<xmlns.domain>urn:jboss:domain:5.0</xmlns.domain>
|
||||
<build-tools.version>${wildfly11.build-tools.version}</build-tools.version>
|
||||
<feature.parent>org.wildfly:wildfly-feature-pack</feature.parent>
|
||||
<configDir>src/main/resources-wf11/configuration</configDir>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@ -304,6 +185,7 @@
|
|||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>product</id>
|
||||
<activation>
|
||||
|
@ -313,8 +195,9 @@
|
|||
</activation>
|
||||
|
||||
<properties>
|
||||
<build-tools.version>${eap.build-tools.version}</build-tools.version>
|
||||
<feature.parent>org.jboss.eap:wildfly-feature-pack</feature.parent>
|
||||
<xmlns.domain>urn:jboss:domain:5.0</xmlns.domain>
|
||||
<configDir>src/main/resources-wf11/configuration</configDir>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<!-- See src/resources/configuration/ReadMe.txt for how the configuration assembly works -->
|
||||
<config>
|
||||
<subsystems name="load-balancer">
|
||||
<!-- Each subsystem to be included relative to the src/main/resources directory -->
|
||||
<subsystem>logging.xml</subsystem>
|
||||
<subsystem>io.xml</subsystem>
|
||||
<subsystem supplement="domain">jmx.xml</subsystem>
|
||||
<subsystem>naming.xml</subsystem>
|
||||
<subsystem>remoting.xml</subsystem>
|
||||
<subsystem>request-controller.xml</subsystem>
|
||||
<subsystem>security.xml</subsystem>
|
||||
<subsystem>security-manager.xml</subsystem>
|
||||
</subsystems>
|
||||
<subsystems name="auth-server-standalone">
|
||||
<!-- Each subsystem to be included relative to the src/main/resources directory -->
|
||||
<subsystem>logging.xml</subsystem>
|
||||
<subsystem>bean-validation.xml</subsystem>
|
||||
<subsystem supplement="default">keycloak-datasources.xml</subsystem>
|
||||
<subsystem>ee.xml</subsystem>
|
||||
<subsystem>ejb3.xml</subsystem>
|
||||
<subsystem>io.xml</subsystem>
|
||||
<subsystem>keycloak-infinispan.xml</subsystem>
|
||||
<subsystem>jaxrs.xml</subsystem>
|
||||
<subsystem>jca.xml</subsystem>
|
||||
<subsystem>jdr.xml</subsystem>
|
||||
<subsystem supplement="domain">jmx.xml</subsystem>
|
||||
<subsystem>jpa.xml</subsystem>
|
||||
<subsystem>jsf.xml</subsystem>
|
||||
<subsystem>mail.xml</subsystem>
|
||||
<subsystem>naming.xml</subsystem>
|
||||
<subsystem>remoting.xml</subsystem>
|
||||
<subsystem>request-controller.xml</subsystem>
|
||||
<subsystem>security.xml</subsystem>
|
||||
<subsystem>security-manager.xml</subsystem>
|
||||
<subsystem>transactions.xml</subsystem>
|
||||
<subsystem>undertow.xml</subsystem>
|
||||
<subsystem>keycloak-server.xml</subsystem>
|
||||
</subsystems>
|
||||
|
||||
<subsystems name="auth-server-clustered">
|
||||
<!-- Each subsystem to be included relative to the src/main/resources directory -->
|
||||
<subsystem>logging.xml</subsystem>
|
||||
<subsystem>bean-validation.xml</subsystem>
|
||||
<subsystem supplement="domain">keycloak-datasources.xml</subsystem>
|
||||
<subsystem>ee.xml</subsystem>
|
||||
<subsystem supplement="ha">ejb3.xml</subsystem>
|
||||
<subsystem>io.xml</subsystem>
|
||||
<subsystem supplement="ha">keycloak-infinispan.xml</subsystem>
|
||||
<subsystem>jaxrs.xml</subsystem>
|
||||
<subsystem>jca.xml</subsystem>
|
||||
<subsystem>jdr.xml</subsystem>
|
||||
<subsystem>jgroups.xml</subsystem>
|
||||
<subsystem supplement="domain">jmx.xml</subsystem>
|
||||
<subsystem>jpa.xml</subsystem>
|
||||
<subsystem>jsf.xml</subsystem>
|
||||
<subsystem>mail.xml</subsystem>
|
||||
<subsystem>mod_cluster.xml</subsystem>
|
||||
<subsystem>naming.xml</subsystem>
|
||||
<subsystem>remoting.xml</subsystem>
|
||||
<subsystem>request-controller.xml</subsystem>
|
||||
<subsystem>security.xml</subsystem>
|
||||
<subsystem>security-manager.xml</subsystem>
|
||||
<subsystem>transactions.xml</subsystem>
|
||||
<subsystem supplement="ha">undertow.xml</subsystem>
|
||||
<subsystem>keycloak-server.xml</subsystem>
|
||||
</subsystems>
|
||||
</config>
|
|
@ -0,0 +1,146 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<domain xmlns="urn:jboss:domain:4.0">
|
||||
|
||||
<extensions>
|
||||
<?EXTENSIONS?>
|
||||
</extensions>
|
||||
|
||||
<system-properties>
|
||||
<!-- IPv4 is not required, but setting this helps avoid unintended use of IPv6 -->
|
||||
<property name="java.net.preferIPv4Stack" value="true"/>
|
||||
</system-properties>
|
||||
|
||||
<management>
|
||||
<access-control provider="simple">
|
||||
<role-mapping>
|
||||
<role name="SuperUser">
|
||||
<include>
|
||||
<user name="$local"/>
|
||||
</include>
|
||||
</role>
|
||||
</role-mapping>
|
||||
</access-control>
|
||||
</management>
|
||||
|
||||
<profiles>
|
||||
<!-- Non clustered authentication server profile -->
|
||||
<profile name="auth-server-standalone">
|
||||
<?SUBSYSTEMS socket-binding-group="standard-sockets"?>
|
||||
</profile>
|
||||
<!--
|
||||
Clustering authentication server setup.
|
||||
|
||||
You must configure a remote shared external database like PostgreSQL or MySql if you want this to be
|
||||
able to work on multiple machines.
|
||||
-->
|
||||
<profile name="auth-server-clustered">
|
||||
<?SUBSYSTEMS socket-binding-group="ha-sockets"?>
|
||||
</profile>
|
||||
<!--
|
||||
This is a profile for the built-in Underto Loadbalancer
|
||||
It should be removed in production systems and replaced with a better software or hardware based one
|
||||
-->
|
||||
<profile name="load-balancer">
|
||||
<?SUBSYSTEMS socket-binding-group="load-balancer-sockets"?>
|
||||
<subsystem xmlns="urn:jboss:domain:undertow:3.0">
|
||||
<buffer-cache name="default"/>
|
||||
<server name="default-server">
|
||||
<http-listener name="default" socket-binding="http" redirect-socket="https"/>
|
||||
<host name="default-host" alias="localhost">
|
||||
<location name="/" handler="lb-handler"/>
|
||||
<filter-ref name="server-header"/>
|
||||
<filter-ref name="x-powered-by-header"/>
|
||||
</host>
|
||||
</server>
|
||||
<servlet-container name="default">
|
||||
<jsp-config/>
|
||||
<websockets/>
|
||||
</servlet-container>
|
||||
<handlers>
|
||||
<reverse-proxy name="lb-handler">
|
||||
<host name="host1" outbound-socket-binding="remote-host1" scheme="ajp" path="/" instance-id="myroute1"/>
|
||||
<host name="host2" outbound-socket-binding="remote-host2" scheme="ajp" path="/" instance-id="myroute2"/>
|
||||
</reverse-proxy>
|
||||
</handlers>
|
||||
<filters>
|
||||
<response-header name="server-header" header-name="Server" header-value="WildFly/10"/>
|
||||
<response-header name="x-powered-by-header" header-name="X-Powered-By" header-value="Undertow/1"/>
|
||||
</filters>
|
||||
</subsystem>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<!--
|
||||
Named interfaces that can be referenced elsewhere in the configuration. The configuration
|
||||
for how to associate these logical names with an actual network interface can either
|
||||
be specified here or can be declared on a per-host basis in the equivalent element in host.xml.
|
||||
|
||||
These default configurations require the binding specification to be done in host.xml.
|
||||
-->
|
||||
<interfaces>
|
||||
<interface name="management">
|
||||
<inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
|
||||
</interface>
|
||||
<interface name="public">
|
||||
<inet-address value="${jboss.bind.address:127.0.0.1}"/>
|
||||
</interface>
|
||||
<?INTERFACES?>
|
||||
</interfaces>
|
||||
|
||||
<socket-binding-groups>
|
||||
<socket-binding-group name="standard-sockets" default-interface="public">
|
||||
<?SOCKET-BINDINGS?>
|
||||
</socket-binding-group>
|
||||
<socket-binding-group name="ha-sockets" default-interface="public">
|
||||
<?SOCKET-BINDINGS?>
|
||||
</socket-binding-group>
|
||||
<!-- load-balancer-sockets should be removed in production systems and replaced with a better softare or hardare based one -->
|
||||
<socket-binding-group name="load-balancer-sockets" default-interface="public">
|
||||
<socket-binding name="ajp" port="${jboss.ajp.port:8009}"/>
|
||||
<socket-binding name="http" port="${jboss.http.port:8080}"/>
|
||||
<socket-binding name="https" port="${jboss.https.port:8443}"/>
|
||||
<outbound-socket-binding name="remote-host1">
|
||||
<remote-destination host="localhost" port="8159"/>
|
||||
</outbound-socket-binding>
|
||||
<outbound-socket-binding name="remote-host2">
|
||||
<remote-destination host="localhost" port="8259"/>
|
||||
</outbound-socket-binding>
|
||||
<?SOCKET-BINDINGS?>
|
||||
</socket-binding-group>
|
||||
</socket-binding-groups>
|
||||
|
||||
<server-groups>
|
||||
<!-- load-balancer-group should be removed in production systems and replaced with a better softare or hardare based one -->
|
||||
<server-group name="load-balancer-group" profile="load-balancer">
|
||||
<jvm name="default">
|
||||
<heap size="64m" max-size="512m"/>
|
||||
</jvm>
|
||||
<socket-binding-group ref="load-balancer-sockets"/>
|
||||
</server-group>
|
||||
<server-group name="auth-server-group" profile="auth-server-clustered">
|
||||
<jvm name="default">
|
||||
<heap size="64m" max-size="512m"/>
|
||||
</jvm>
|
||||
<socket-binding-group ref="ha-sockets"/>
|
||||
</server-group>
|
||||
</server-groups>
|
||||
|
||||
</domain>
|
|
@ -0,0 +1,127 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<!--
|
||||
Runs an HTTP Loadbalancer that balances to two separate auth server instances. The first auth server instance
|
||||
is also started by this host controller file. The other instance must be started
|
||||
via host-slave.xml
|
||||
-->
|
||||
<host name="master" xmlns="urn:jboss:domain:4.0">
|
||||
<extensions>
|
||||
<?EXTENSIONS?>
|
||||
</extensions>
|
||||
|
||||
<management>
|
||||
<security-realms>
|
||||
<security-realm name="ManagementRealm">
|
||||
<authentication>
|
||||
<local default-user="$local" skip-group-loading="true"/>
|
||||
<properties path="mgmt-users.properties" relative-to="jboss.domain.config.dir"/>
|
||||
</authentication>
|
||||
<authorization map-groups-to-roles="false">
|
||||
<properties path="mgmt-groups.properties" relative-to="jboss.domain.config.dir"/>
|
||||
</authorization>
|
||||
</security-realm>
|
||||
<security-realm name="ApplicationRealm">
|
||||
<authentication>
|
||||
<local default-user="$local" allowed-users="*" skip-group-loading="true"/>
|
||||
<properties path="application-users.properties" relative-to="jboss.domain.config.dir"/>
|
||||
</authentication>
|
||||
<authorization>
|
||||
<properties path="application-roles.properties" relative-to="jboss.domain.config.dir"/>
|
||||
</authorization>
|
||||
</security-realm>
|
||||
</security-realms>
|
||||
<audit-log>
|
||||
<formatters>
|
||||
<json-formatter name="json-formatter"/>
|
||||
</formatters>
|
||||
<handlers>
|
||||
<file-handler name="host-file" formatter="json-formatter" relative-to="jboss.domain.data.dir" path="audit-log.log"/>
|
||||
<file-handler name="server-file" formatter="json-formatter" relative-to="jboss.server.data.dir" path="audit-log.log"/>
|
||||
</handlers>
|
||||
<logger log-boot="true" log-read-only="false" enabled="false">
|
||||
<handlers>
|
||||
<handler name="host-file"/>
|
||||
</handlers>
|
||||
</logger>
|
||||
<server-logger log-boot="true" log-read-only="false" enabled="false">
|
||||
<handlers>
|
||||
<handler name="server-file"/>
|
||||
</handlers>
|
||||
</server-logger>
|
||||
</audit-log>
|
||||
<management-interfaces>
|
||||
<native-interface security-realm="ManagementRealm">
|
||||
<socket interface="management" port="${jboss.management.native.port:9999}"/>
|
||||
</native-interface>
|
||||
<http-interface security-realm="ManagementRealm" http-upgrade-enabled="true">
|
||||
<socket interface="management" port="${jboss.management.http.port:9990}"/>
|
||||
</http-interface>
|
||||
</management-interfaces>
|
||||
</management>
|
||||
|
||||
<domain-controller>
|
||||
<local/>
|
||||
</domain-controller>
|
||||
|
||||
<interfaces>
|
||||
<interface name="management">
|
||||
<inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
|
||||
</interface>
|
||||
<interface name="public">
|
||||
<inet-address value="${jboss.bind.address:127.0.0.1}"/>
|
||||
</interface>
|
||||
|
||||
<?INTERFACES?>
|
||||
|
||||
</interfaces>
|
||||
|
||||
<jvms>
|
||||
<jvm name="default">
|
||||
<heap size="64m" max-size="256m"/>
|
||||
<jvm-options>
|
||||
<option value="-server"/>
|
||||
</jvm-options>
|
||||
</jvm>
|
||||
</jvms>
|
||||
|
||||
<servers>
|
||||
<!-- load-balancer should be removed in production systems and replaced with a better softare or hardare based one -->
|
||||
<server name="load-balancer" group="load-balancer-group">
|
||||
</server>
|
||||
<server name="server-one" group="auth-server-group" auto-start="true">
|
||||
<!-- Remote JPDA debugging for a specific server
|
||||
<jvm name="default">
|
||||
<jvm-options>
|
||||
<option value="-agentlib:jdwp=transport=dt_socket,address=8787,server=y,suspend=n"/>
|
||||
</jvm-options>
|
||||
</jvm>
|
||||
-->
|
||||
<!-- server-two avoids port conflicts by incrementing the ports in
|
||||
the default socket-group declared in the server-group -->
|
||||
<socket-bindings port-offset="150"/>
|
||||
</server>
|
||||
</servers>
|
||||
|
||||
<profile>
|
||||
<?SUBSYSTEMS socket-binding-group="standard-sockets"?>
|
||||
</profile>
|
||||
|
||||
</host>
|
|
@ -0,0 +1,117 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<host xmlns="urn:jboss:domain:4.0">
|
||||
<extensions>
|
||||
<?EXTENSIONS?>
|
||||
</extensions>
|
||||
|
||||
<management>
|
||||
<security-realms>
|
||||
<security-realm name="ManagementRealm">
|
||||
<server-identities>
|
||||
<!-- Replace this with either a base64 password of your own, or use a vault with a vault expression -->
|
||||
<secret value="c2xhdmVfdXNlcl9wYXNzd29yZA=="/>
|
||||
</server-identities>
|
||||
|
||||
<authentication>
|
||||
<local default-user="$local" skip-group-loading="true"/>
|
||||
<properties path="mgmt-users.properties" relative-to="jboss.domain.config.dir"/>
|
||||
</authentication>
|
||||
<authorization map-groups-to-roles="false">
|
||||
<properties path="mgmt-groups.properties" relative-to="jboss.domain.config.dir"/>
|
||||
</authorization>
|
||||
</security-realm>
|
||||
<security-realm name="ApplicationRealm">
|
||||
<authentication>
|
||||
<local default-user="$local" allowed-users="*" skip-group-loading="true"/>
|
||||
<properties path="application-users.properties" relative-to="jboss.domain.config.dir"/>
|
||||
</authentication>
|
||||
<authorization>
|
||||
<properties path="application-roles.properties" relative-to="jboss.domain.config.dir"/>
|
||||
</authorization>
|
||||
</security-realm>
|
||||
</security-realms>
|
||||
<audit-log>
|
||||
<formatters>
|
||||
<json-formatter name="json-formatter"/>
|
||||
</formatters>
|
||||
<handlers>
|
||||
<file-handler name="host-file" formatter="json-formatter" relative-to="jboss.domain.data.dir" path="audit-log.log"/>
|
||||
<file-handler name="server-file" formatter="json-formatter" relative-to="jboss.server.data.dir" path="audit-log.log"/>
|
||||
</handlers>
|
||||
<logger log-boot="true" log-read-only="false" enabled="false">
|
||||
<handlers>
|
||||
<handler name="host-file"/>
|
||||
</handlers>
|
||||
</logger>
|
||||
<server-logger log-boot="true" log-read-only="false" enabled="false">
|
||||
<handlers>
|
||||
<handler name="server-file"/>
|
||||
</handlers>
|
||||
</server-logger>
|
||||
</audit-log>
|
||||
<management-interfaces>
|
||||
<native-interface security-realm="ManagementRealm">
|
||||
<socket interface="management" port="${jboss.management.native.port:3456}"/>
|
||||
</native-interface>
|
||||
</management-interfaces>
|
||||
</management>
|
||||
|
||||
<domain-controller>
|
||||
<remote security-realm="ManagementRealm">
|
||||
<discovery-options>
|
||||
<static-discovery name="primary" protocol="${jboss.domain.master.protocol:remote}" host="${jboss.domain.master.address:127.0.0.1}" port="${jboss.domain.master.port:9999}"/>
|
||||
</discovery-options>
|
||||
</remote>
|
||||
</domain-controller>
|
||||
|
||||
<interfaces>
|
||||
<interface name="management">
|
||||
<inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
|
||||
</interface>
|
||||
<interface name="public">
|
||||
<inet-address value="${jboss.bind.address:127.0.0.1}"/>
|
||||
</interface>
|
||||
|
||||
<?INTERFACES?>
|
||||
|
||||
</interfaces>
|
||||
|
||||
<jvms>
|
||||
<jvm name="default">
|
||||
<heap size="64m" max-size="256m"/>
|
||||
<jvm-options>
|
||||
<option value="-server"/>
|
||||
</jvm-options>
|
||||
</jvm>
|
||||
</jvms>
|
||||
|
||||
<servers>
|
||||
<server name="server-two" group="auth-server-group" auto-start="true">
|
||||
<!-- server-two avoids port conflicts by incrementing the ports in
|
||||
the default socket-group declared in the server-group -->
|
||||
<socket-bindings port-offset="250"/>
|
||||
</server>
|
||||
</servers>
|
||||
|
||||
<profile>
|
||||
<?SUBSYSTEMS socket-binding-group="standard-sockets"?>
|
||||
</profile>
|
||||
</host>
|
|
@ -0,0 +1,127 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<!--
|
||||
Runs an HTTP Loadbalancer that balances to two separate auth server instances. The first auth server instance
|
||||
is also started by this host controller file. The other instance must be started
|
||||
via host-slave.xml
|
||||
-->
|
||||
|
||||
<host name="master" xmlns="urn:jboss:domain:4.0">
|
||||
<extensions>
|
||||
<?EXTENSIONS?>
|
||||
</extensions>
|
||||
|
||||
<management>
|
||||
<security-realms>
|
||||
<security-realm name="ManagementRealm">
|
||||
<authentication>
|
||||
<local default-user="$local" skip-group-loading="true"/>
|
||||
<properties path="mgmt-users.properties" relative-to="jboss.domain.config.dir"/>
|
||||
</authentication>
|
||||
<authorization map-groups-to-roles="false">
|
||||
<properties path="mgmt-groups.properties" relative-to="jboss.domain.config.dir"/>
|
||||
</authorization>
|
||||
</security-realm>
|
||||
<security-realm name="ApplicationRealm">
|
||||
<authentication>
|
||||
<local default-user="$local" allowed-users="*" skip-group-loading="true"/>
|
||||
<properties path="application-users.properties" relative-to="jboss.domain.config.dir"/>
|
||||
</authentication>
|
||||
<authorization>
|
||||
<properties path="application-roles.properties" relative-to="jboss.domain.config.dir"/>
|
||||
</authorization>
|
||||
</security-realm>
|
||||
</security-realms>
|
||||
<audit-log>
|
||||
<formatters>
|
||||
<json-formatter name="json-formatter"/>
|
||||
</formatters>
|
||||
<handlers>
|
||||
<file-handler name="host-file" formatter="json-formatter" relative-to="jboss.domain.data.dir" path="audit-log.log"/>
|
||||
<file-handler name="server-file" formatter="json-formatter" relative-to="jboss.server.data.dir" path="audit-log.log"/>
|
||||
</handlers>
|
||||
<logger log-boot="true" log-read-only="false" enabled="false">
|
||||
<handlers>
|
||||
<handler name="host-file"/>
|
||||
</handlers>
|
||||
</logger>
|
||||
<server-logger log-boot="true" log-read-only="false" enabled="false">
|
||||
<handlers>
|
||||
<handler name="server-file"/>
|
||||
</handlers>
|
||||
</server-logger>
|
||||
</audit-log>
|
||||
<management-interfaces>
|
||||
<native-interface security-realm="ManagementRealm">
|
||||
<socket interface="management" port="${jboss.management.native.port:9999}"/>
|
||||
</native-interface>
|
||||
<http-interface security-realm="ManagementRealm" http-upgrade-enabled="true">
|
||||
<socket interface="management" port="${jboss.management.http.port:9990}"/>
|
||||
</http-interface>
|
||||
</management-interfaces>
|
||||
</management>
|
||||
|
||||
<domain-controller>
|
||||
<local/>
|
||||
</domain-controller>
|
||||
|
||||
<interfaces>
|
||||
<interface name="management">
|
||||
<inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
|
||||
</interface>
|
||||
<interface name="public">
|
||||
<inet-address value="${jboss.bind.address:127.0.0.1}"/>
|
||||
</interface>
|
||||
|
||||
<?INTERFACES?>
|
||||
|
||||
</interfaces>
|
||||
|
||||
<jvms>
|
||||
<jvm name="default">
|
||||
<heap size="64m" max-size="256m"/>
|
||||
<jvm-options>
|
||||
<option value="-server"/>
|
||||
</jvm-options>
|
||||
</jvm>
|
||||
</jvms>
|
||||
|
||||
<servers>
|
||||
<!-- load-balancer should be removed in production systems and replaced with a better softare or hardare based one -->
|
||||
<server name="load-balancer" group="load-balancer-group">
|
||||
</server>
|
||||
<server name="server-one" group="auth-server-group" auto-start="true">
|
||||
<!-- Remote JPDA debugging for a specific server
|
||||
<jvm name="default">
|
||||
<jvm-options>
|
||||
<option value="-agentlib:jdwp=transport=dt_socket,address=8787,server=y,suspend=n"/>
|
||||
</jvm-options>
|
||||
</jvm>
|
||||
-->
|
||||
<!-- server-two avoids port conflicts by incrementing the ports in
|
||||
the default socket-group declared in the server-group -->
|
||||
<socket-bindings port-offset="150"/>
|
||||
</server>
|
||||
</servers>
|
||||
|
||||
<profile>
|
||||
<?SUBSYSTEMS socket-binding-group="standard-sockets"?>
|
||||
</profile>
|
||||
</host>
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<!-- See src/resources/configuration/ReadMe.txt for how the configuration assembly works -->
|
||||
<config>
|
||||
<subsystems>
|
||||
<subsystem>jmx.xml</subsystem>
|
||||
</subsystems>
|
||||
</config>
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
|
||||
<server xmlns="${xmlns.domain}">
|
||||
<server xmlns="urn:jboss:domain:5.0">
|
||||
|
||||
<extensions>
|
||||
<?EXTENSIONS?>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<domain xmlns="${xmlns.domain}">
|
||||
<domain xmlns="urn:jboss:domain:4.0">
|
||||
|
||||
<extensions>
|
||||
<?EXTENSIONS?>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
is also started by this host controller file. The other instance must be started
|
||||
via host-slave.xml
|
||||
-->
|
||||
<host name="master" xmlns="${xmlns.domain}">
|
||||
<host name="master" xmlns="urn:jboss:domain:4.0">
|
||||
<extensions>
|
||||
<?EXTENSIONS?>
|
||||
</extensions>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<host xmlns="${xmlns.domain}">
|
||||
<host xmlns="urn:jboss:domain:4.0">
|
||||
<extensions>
|
||||
<?EXTENSIONS?>
|
||||
</extensions>
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
via host-slave.xml
|
||||
-->
|
||||
|
||||
<host name="master" xmlns="${xmlns.domain}">
|
||||
<host name="master" xmlns="urn:jboss:domain:4.0">
|
||||
<extensions>
|
||||
<?EXTENSIONS?>
|
||||
</extensions>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<server xmlns="${xmlns.domain}">
|
||||
<server xmlns="urn:jboss:domain:4.0">
|
||||
|
||||
<extensions>
|
||||
<?EXTENSIONS?>
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
<plugin>
|
||||
<groupId>org.wildfly.build</groupId>
|
||||
<artifactId>wildfly-server-provisioning-maven-plugin</artifactId>
|
||||
<version>${build-tools.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>server-provisioning</id>
|
||||
|
@ -74,7 +75,6 @@
|
|||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<outputDirectory>${project.build.directory}</outputDirectory>
|
||||
<workDirectory>${project.build.directory}/assembly/work</workDirectory>
|
||||
<tarLongFileMode>gnu</tarLongFileMode>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
@ -114,6 +114,7 @@
|
|||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<build-tools.version>${wildfly.build-tools.version}</build-tools.version>
|
||||
<assemblyFile>assembly.xml</assemblyFile>
|
||||
</properties>
|
||||
<build>
|
||||
|
@ -121,6 +122,13 @@
|
|||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>wf11</id>
|
||||
<properties>
|
||||
<build-tools.version>${wildfly11.build-tools.version}</build-tools.version>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>product</id>
|
||||
<activation>
|
||||
|
@ -129,6 +137,7 @@
|
|||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<build-tools.version>${eap.build-tools.version}</build-tools.version>
|
||||
<assemblyFile>assembly.xml</assemblyFile>
|
||||
<profileExcludes>%regex[(providers.*)|(docs/contrib.*)|(docs/examples.*)|(docs/schema.*)]</profileExcludes>
|
||||
</properties>
|
||||
|
|
|
@ -138,7 +138,6 @@
|
|||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<outputDirectory>${project.build.directory}</outputDirectory>
|
||||
<workDirectory>${project.build.directory}/assembly/work</workDirectory>
|
||||
<tarLongFileMode>gnu</tarLongFileMode>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.keycloak.admin.client;
|
|||
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
|
||||
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
|
||||
import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
|
||||
import org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider;
|
||||
import org.keycloak.admin.client.resource.BearerAuthFilter;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.admin.client.resource.RealmsResource;
|
||||
|
@ -31,7 +32,6 @@ import javax.net.ssl.HostnameVerifier;
|
|||
import javax.net.ssl.SSLSession;
|
||||
|
||||
import java.net.URI;
|
||||
import java.security.KeyStore;
|
||||
|
||||
import static org.keycloak.OAuth2Constants.PASSWORD;
|
||||
|
||||
|
@ -66,12 +66,20 @@ public class Keycloak {
|
|||
}
|
||||
|
||||
public static Keycloak getInstance(String serverUrl, String realm, String username, String password, String clientId, String clientSecret, SSLContext sslContext) {
|
||||
ResteasyClient client = new ResteasyClientBuilder()
|
||||
return getInstance(serverUrl, realm, username, password, clientId, clientSecret, sslContext, null);
|
||||
}
|
||||
|
||||
public static Keycloak getInstance(String serverUrl, String realm, String username, String password, String clientId, String clientSecret, SSLContext sslContext, ResteasyJackson2Provider customJacksonProvider) {
|
||||
ResteasyClientBuilder clientBuilder = new ResteasyClientBuilder()
|
||||
.sslContext(sslContext)
|
||||
.hostnameVerification(ResteasyClientBuilder.HostnameVerificationPolicy.WILDCARD)
|
||||
.connectionPoolSize(10).build();
|
||||
.connectionPoolSize(10);
|
||||
|
||||
return new Keycloak(serverUrl, realm, username, password, clientId, clientSecret, PASSWORD, client, null);
|
||||
if (customJacksonProvider != null) {
|
||||
clientBuilder.register(customJacksonProvider);
|
||||
}
|
||||
|
||||
return new Keycloak(serverUrl, realm, username, password, clientId, clientSecret, PASSWORD, clientBuilder.build(), null);
|
||||
}
|
||||
|
||||
private static ResteasyClientBuilder newResteasyClientBuilder() {
|
||||
|
|
|
@ -23,6 +23,7 @@ import javax.ws.rs.GET;
|
|||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
|
@ -58,4 +59,7 @@ public interface AuthorizationResource {
|
|||
|
||||
@Path("/policy")
|
||||
PoliciesResource policies();
|
||||
|
||||
@Path("/permission")
|
||||
PermissionsResource permissions();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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.admin.client.resource;
|
||||
|
||||
import javax.ws.rs.Path;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public interface PermissionsResource {
|
||||
|
||||
@Path("resource")
|
||||
ResourcePermissionsResource resource();
|
||||
|
||||
@Path("scope")
|
||||
ScopePermissionsResource scope();
|
||||
}
|
|
@ -28,6 +28,7 @@ import javax.ws.rs.POST;
|
|||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.List;
|
||||
|
@ -45,6 +46,12 @@ public interface PoliciesResource {
|
|||
@Path("{id}")
|
||||
PolicyResource policy(@PathParam("id") String id);
|
||||
|
||||
@Path("/search")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
PolicyRepresentation findByName(@QueryParam("name") String name);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
|
@ -62,4 +69,9 @@ public interface PoliciesResource {
|
|||
@Path("evaluate")
|
||||
PolicyEvaluationResponse evaluate(PolicyEvaluationRequest evaluationRequest);
|
||||
|
||||
@Path("role")
|
||||
RolePoliciesResource roles();
|
||||
|
||||
@Path("user")
|
||||
UserPoliciesResource users();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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.admin.client.resource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public interface ResourcePermissionResource {
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
ResourcePermissionRepresentation toRepresentation();
|
||||
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
void update(ResourcePermissionRepresentation representation);
|
||||
|
||||
@DELETE
|
||||
void remove();
|
||||
|
||||
@Path("/associatedPolicies")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
List<PolicyRepresentation> associatedPolicies();
|
||||
|
||||
@Path("/dependentPolicies")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
List<PolicyRepresentation> dependentPolicies();
|
||||
|
||||
@Path("/resources")
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
@NoCache
|
||||
List<ResourceRepresentation> resources();
|
||||
|
||||
}
|
|
@ -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.admin.client.resource;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public interface ResourcePermissionsResource {
|
||||
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
Response create(ResourcePermissionRepresentation representation);
|
||||
|
||||
@Path("{id}")
|
||||
ResourcePermissionResource findById(@PathParam("id") String id);
|
||||
|
||||
@Path("/search")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
ResourcePermissionRepresentation findByName(@QueryParam("name") String name);
|
||||
}
|
|
@ -25,6 +25,7 @@ import javax.ws.rs.POST;
|
|||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.List;
|
||||
|
@ -46,4 +47,10 @@ public interface ResourceScopesResource {
|
|||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
List<ScopeRepresentation> scopes();
|
||||
|
||||
@Path("/search")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
ScopeRepresentation findByName(@QueryParam("name") String name);
|
||||
}
|
||||
|
|
|
@ -54,6 +54,11 @@ public interface ResourcesResource {
|
|||
@QueryParam("first") Integer firstResult,
|
||||
@QueryParam("max") Integer maxResult);
|
||||
|
||||
@GET
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
List<ResourceRepresentation> findByName(@QueryParam("name") String name);
|
||||
|
||||
@GET
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
|
|
|
@ -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.admin.client.resource;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public interface RolePoliciesResource {
|
||||
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
Response create(RolePolicyRepresentation representation);
|
||||
|
||||
@Path("{id}")
|
||||
RolePolicyResource findById(@PathParam("id") String id);
|
||||
|
||||
@Path("/search")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
RolePolicyRepresentation findByName(@QueryParam("name") String name);
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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.admin.client.resource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public interface RolePolicyResource {
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
RolePolicyRepresentation toRepresentation();
|
||||
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
void update(RolePolicyRepresentation representation);
|
||||
|
||||
@DELETE
|
||||
void remove();
|
||||
|
||||
@Path("/associatedPolicies")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
List<PolicyRepresentation> associatedPolicies();
|
||||
|
||||
@Path("/dependentPolicies")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
List<PolicyRepresentation> dependentPolicies();
|
||||
|
||||
@Path("/resources")
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
@NoCache
|
||||
List<ResourceRepresentation> resources();
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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.admin.client.resource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public interface ScopePermissionResource {
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
ScopePermissionRepresentation toRepresentation();
|
||||
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
void update(ScopePermissionRepresentation representation);
|
||||
|
||||
@DELETE
|
||||
void remove();
|
||||
|
||||
@Path("/associatedPolicies")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
List<PolicyRepresentation> associatedPolicies();
|
||||
|
||||
@Path("/dependentPolicies")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
List<PolicyRepresentation> dependentPolicies();
|
||||
|
||||
@Path("/resources")
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
@NoCache
|
||||
List<ResourceRepresentation> resources();
|
||||
|
||||
@Path("/scopes")
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
@NoCache
|
||||
List<ScopeRepresentation> scopes();
|
||||
}
|
|
@ -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.admin.client.resource;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public interface ScopePermissionsResource {
|
||||
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
Response create(ScopePermissionRepresentation representation);
|
||||
|
||||
@Path("{id}")
|
||||
ScopePermissionResource findById(@PathParam("id") String id);
|
||||
|
||||
@Path("/search")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
ScopePermissionRepresentation findByName(@QueryParam("name") String name);
|
||||
}
|
|
@ -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.admin.client.resource;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public interface UserPoliciesResource {
|
||||
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
Response create(UserPolicyRepresentation representation);
|
||||
|
||||
@Path("{id}")
|
||||
UserPolicyResource findById(@PathParam("id") String id);
|
||||
|
||||
@Path("/search")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
UserPolicyRepresentation findByName(@QueryParam("name") String name);
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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.admin.client.resource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public interface UserPolicyResource {
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
UserPolicyRepresentation toRepresentation();
|
||||
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
void update(UserPolicyRepresentation representation);
|
||||
|
||||
@DELETE
|
||||
void remove();
|
||||
|
||||
@Path("/associatedPolicies")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
List<PolicyRepresentation> associatedPolicies();
|
||||
|
||||
@Path("/dependentPolicies")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
List<PolicyRepresentation> dependentPolicies();
|
||||
|
||||
@Path("/resources")
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
@NoCache
|
||||
List<ResourceRepresentation> resources();
|
||||
|
||||
}
|
|
@ -43,6 +43,8 @@ import java.io.InputStream;
|
|||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.keycloak.test.builders.ClientBuilder.AccessType.PUBLIC;
|
||||
|
||||
public class TestsHelper {
|
||||
|
||||
public static String baseUrl;
|
||||
|
@ -83,7 +85,7 @@ public class TestsHelper {
|
|||
}
|
||||
|
||||
public static String createDirectGrantClient() {
|
||||
return createClient(ClientBuilder.create("test-dga").publicClient(true));
|
||||
return createClient(ClientBuilder.create("test-dga").accessType(PUBLIC));
|
||||
}
|
||||
|
||||
public static void deleteClient(String clientId) {
|
||||
|
|
|
@ -28,6 +28,8 @@ public class ClientBuilder {
|
|||
|
||||
private ClientRepresentation rep;
|
||||
|
||||
public enum AccessType { BEARER_ONLY, PUBLIC, CONFIDENTIAL };
|
||||
|
||||
public static ClientBuilder create(String clientId) {
|
||||
ClientRepresentation rep = new ClientRepresentation();
|
||||
rep.setEnabled(Boolean.TRUE);
|
||||
|
@ -39,9 +41,19 @@ public class ClientBuilder {
|
|||
this.rep = rep;
|
||||
}
|
||||
|
||||
public ClientRepresentation bearerOnly(boolean bearerOnly) {
|
||||
rep.setBearerOnly(bearerOnly);
|
||||
return rep;
|
||||
public ClientRepresentation accessType(AccessType accessType) {
|
||||
switch (accessType) {
|
||||
case BEARER_ONLY:
|
||||
rep.setBearerOnly(true);
|
||||
break;
|
||||
case PUBLIC:
|
||||
rep.setPublicClient(true);
|
||||
break;
|
||||
case CONFIDENTIAL:
|
||||
rep.setPublicClient(false);
|
||||
break;
|
||||
}
|
||||
return defaultSettings();
|
||||
}
|
||||
|
||||
public ClientBuilder rootUrl(String rootUrl) {
|
||||
|
@ -64,9 +76,13 @@ public class ClientBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public ClientRepresentation publicClient(boolean publicClient) {
|
||||
public ClientBuilder secret(String secret) {
|
||||
rep.setSecret(secret);
|
||||
return this;
|
||||
}
|
||||
|
||||
private ClientRepresentation defaultSettings() {
|
||||
rep.setFullScopeAllowed(true);
|
||||
rep.setPublicClient(publicClient);
|
||||
rep.setDirectAccessGrantsEnabled(true);
|
||||
rep.setAdminUrl(rep.getRootUrl());
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.models.authorization.infinispan.InfinispanStoreFactoryProvider.CacheTransaction;
|
||||
import org.keycloak.models.authorization.infinispan.entities.CachedPolicy;
|
||||
import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
|
||||
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.DecisionStrategy;
|
||||
import org.keycloak.representations.idm.authorization.Logic;
|
||||
|
||||
|
@ -53,15 +54,14 @@ public class CachedPolicyStore implements PolicyStore {
|
|||
private static final String POLICY_ID_CACHE_PREFIX = "policy-id-";
|
||||
|
||||
private final Cache<String, Map<String, List<CachedPolicy>>> cache;
|
||||
private final KeycloakSession session;
|
||||
private final CachedStoreFactoryProvider cacheStoreFactory;
|
||||
private final CacheTransaction transaction;
|
||||
private final List<String> cacheKeys;
|
||||
private StoreFactory storeFactory;
|
||||
private final StoreFactory storeFactory;
|
||||
private PolicyStore delegate;
|
||||
private CachedStoreFactoryProvider cachedStoreFactory;
|
||||
|
||||
public CachedPolicyStore(KeycloakSession session, CacheTransaction transaction, StoreFactory storeFactory) {
|
||||
this.session = session;
|
||||
public CachedPolicyStore(KeycloakSession session, CachedStoreFactoryProvider cacheStoreFactory, CacheTransaction transaction, StoreFactory delegate) {
|
||||
this.cacheStoreFactory = cacheStoreFactory;
|
||||
this.transaction = transaction;
|
||||
InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class);
|
||||
this.cache = provider.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME);
|
||||
|
@ -70,12 +70,12 @@ public class CachedPolicyStore implements PolicyStore {
|
|||
cacheKeys.add("findByResourceType");
|
||||
cacheKeys.add("findByScopeIds");
|
||||
cacheKeys.add("findByType");
|
||||
this.storeFactory = storeFactory;
|
||||
this.storeFactory = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy create(String name, String type, ResourceServer resourceServer) {
|
||||
Policy policy = getDelegate().create(name, type, getStoreFactory().getResourceServerStore().findById(resourceServer.getId()));
|
||||
public Policy create(AbstractPolicyRepresentation representation, ResourceServer resourceServer) {
|
||||
Policy policy = getDelegate().create(representation, getStoreFactory().getResourceServerStore().findById(resourceServer.getId()));
|
||||
String id = policy.getId();
|
||||
|
||||
this.transaction.whenRollback(() -> {
|
||||
|
@ -102,6 +102,10 @@ public class CachedPolicyStore implements PolicyStore {
|
|||
|
||||
@Override
|
||||
public Policy findById(String id, String resourceServerId) {
|
||||
if (resourceServerId == null) {
|
||||
return getDelegate().findById(id, null);
|
||||
}
|
||||
|
||||
String cacheKeyForPolicy = getCacheKeyForPolicy(id);
|
||||
List<CachedPolicy> cached = resolveResourceServerCache(resourceServerId).get(cacheKeyForPolicy);
|
||||
|
||||
|
@ -285,6 +289,7 @@ public class CachedPolicyStore implements PolicyStore {
|
|||
public void removeScope(Scope scope) {
|
||||
getDelegateForUpdate().removeScope(getStoreFactory().getScopeStore().findById(scope.getId(), cached.getResourceServerId()));
|
||||
cached.removeScope(scope);
|
||||
scopes.remove(scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -297,6 +302,7 @@ public class CachedPolicyStore implements PolicyStore {
|
|||
public void removeAssociatedPolicy(Policy associatedPolicy) {
|
||||
getDelegateForUpdate().removeAssociatedPolicy(getStoreFactory().getPolicyStore().findById(associatedPolicy.getId(), cached.getResourceServerId()));
|
||||
cached.removeAssociatedPolicy(associatedPolicy);
|
||||
associatedPolicies.remove(associatedPolicy);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -309,6 +315,7 @@ public class CachedPolicyStore implements PolicyStore {
|
|||
public void removeResource(Resource resource) {
|
||||
getDelegateForUpdate().removeResource(getStoreFactory().getResourceStore().findById(resource.getId(), cached.getResourceServerId()));
|
||||
cached.removeResource(resource);
|
||||
resources.remove(resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -401,10 +408,7 @@ public class CachedPolicyStore implements PolicyStore {
|
|||
}
|
||||
|
||||
private CachedStoreFactoryProvider getCachedStoreFactory() {
|
||||
if (cachedStoreFactory == null) {
|
||||
cachedStoreFactory = session.getProvider(CachedStoreFactoryProvider.class);
|
||||
}
|
||||
return cachedStoreFactory;
|
||||
return cacheStoreFactory;
|
||||
}
|
||||
|
||||
private void invalidateCache(String resourceServerId) {
|
||||
|
|
|
@ -41,18 +41,16 @@ public class CachedResourceServerStore implements ResourceServerStore {
|
|||
private static final String RS_ID_CACHE_PREFIX = "rs-id-";
|
||||
private static final String RS_CLIENT_ID_CACHE_PREFIX = "rs-client-id-";
|
||||
|
||||
private final KeycloakSession session;
|
||||
private final CacheTransaction transaction;
|
||||
private StoreFactory storeFactory;
|
||||
private ResourceServerStore delegate;
|
||||
private final Cache<String, Map<String, List<CachedResourceServer>>> cache;
|
||||
|
||||
public CachedResourceServerStore(KeycloakSession session, CacheTransaction transaction, StoreFactory storeFactory) {
|
||||
this.session = session;
|
||||
public CachedResourceServerStore(KeycloakSession session, CacheTransaction transaction, StoreFactory delegate) {
|
||||
this.transaction = transaction;
|
||||
InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class);
|
||||
this.cache = provider.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME);
|
||||
this.storeFactory = storeFactory;
|
||||
this.storeFactory = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,15 +49,15 @@ public class CachedResourceStore implements ResourceStore {
|
|||
private static final String RESOURCE_ID_CACHE_PREFIX = "rsc-id-";
|
||||
private static final String RESOURCE_NAME_CACHE_PREFIX = "rsc-name-";
|
||||
|
||||
private final KeycloakSession session;
|
||||
private final CachedStoreFactoryProvider cacheStoreFactory;
|
||||
private final CacheTransaction transaction;
|
||||
private final List<String> cacheKeys;
|
||||
private StoreFactory storeFactory;
|
||||
private StoreFactory delegateStoreFactory;
|
||||
private ResourceStore delegate;
|
||||
private final Cache<String, Map<String, List<CachedResource>>> cache;
|
||||
|
||||
public CachedResourceStore(KeycloakSession session, CacheTransaction transaction, StoreFactory storeFactory) {
|
||||
this.session = session;
|
||||
public CachedResourceStore(KeycloakSession session, CachedStoreFactoryProvider cacheStoreFactory, CacheTransaction transaction, StoreFactory delegate) {
|
||||
this.cacheStoreFactory = cacheStoreFactory;
|
||||
InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class);
|
||||
this.cache = provider.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME);
|
||||
this.transaction = transaction;
|
||||
|
@ -65,12 +65,12 @@ public class CachedResourceStore implements ResourceStore {
|
|||
cacheKeys.add("findByOwner");
|
||||
cacheKeys.add("findByUri");
|
||||
cacheKeys.add("findByName");
|
||||
this.storeFactory = storeFactory;
|
||||
this.delegateStoreFactory = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource create(String name, ResourceServer resourceServer, String owner) {
|
||||
Resource resource = getDelegate().create(name, getStoreFactory().getResourceServerStore().findById(resourceServer.getId()), owner);
|
||||
Resource resource = getDelegate().create(name, getDelegateStoreFactory().getResourceServerStore().findById(resourceServer.getId()), owner);
|
||||
|
||||
this.transaction.whenRollback(() -> {
|
||||
resolveResourceServerCache(resourceServer.getId()).remove(getCacheKeyForResource(resource.getId()));
|
||||
|
@ -176,14 +176,14 @@ public class CachedResourceStore implements ResourceStore {
|
|||
|
||||
private ResourceStore getDelegate() {
|
||||
if (this.delegate == null) {
|
||||
this.delegate = getStoreFactory().getResourceStore();
|
||||
this.delegate = getDelegateStoreFactory().getResourceStore();
|
||||
}
|
||||
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
private StoreFactory getStoreFactory() {
|
||||
return this.storeFactory;
|
||||
private StoreFactory getDelegateStoreFactory() {
|
||||
return this.delegateStoreFactory;
|
||||
}
|
||||
|
||||
private Resource createAdapter(CachedResource cached) {
|
||||
|
@ -270,7 +270,7 @@ public class CachedResourceStore implements ResourceStore {
|
|||
|
||||
@Override
|
||||
public void updateScopes(Set<Scope> scopes) {
|
||||
getDelegateForUpdate().updateScopes(scopes.stream().map(scope -> getStoreFactory().getScopeStore().findById(scope.getId(), cached.getResourceServerId())).collect(Collectors.toSet()));
|
||||
getDelegateForUpdate().updateScopes(scopes.stream().map(scope -> getDelegateStoreFactory().getScopeStore().findById(scope.getId(), cached.getResourceServerId())).collect(Collectors.toSet()));
|
||||
cached.updateScopes(scopes);
|
||||
}
|
||||
|
||||
|
@ -293,7 +293,7 @@ public class CachedResourceStore implements ResourceStore {
|
|||
}
|
||||
|
||||
private CachedStoreFactoryProvider getCachedStoreFactory() {
|
||||
return session.getProvider(CachedStoreFactoryProvider.class);
|
||||
return cacheStoreFactory;
|
||||
}
|
||||
|
||||
private List<Resource> cacheResult(String resourceServerId, String key, Supplier<List<Resource>> provider) {
|
||||
|
|
|
@ -44,17 +44,17 @@ public class CachedScopeStore implements ScopeStore {
|
|||
private static final String SCOPE_NAME_CACHE_PREFIX = "scp-name-";
|
||||
|
||||
private final Cache<String, Map<String, List<CachedScope>>> cache;
|
||||
private final KeycloakSession session;
|
||||
private final CachedStoreFactoryProvider cacheStoreFactory;
|
||||
private final CacheTransaction transaction;
|
||||
private ScopeStore delegate;
|
||||
private StoreFactory storeFactory;
|
||||
|
||||
public CachedScopeStore(KeycloakSession session, CacheTransaction transaction, StoreFactory storeFactory) {
|
||||
this.session = session;
|
||||
public CachedScopeStore(KeycloakSession session, CachedStoreFactoryProvider cacheStoreFactory, CacheTransaction transaction, StoreFactory delegate) {
|
||||
this.cacheStoreFactory = cacheStoreFactory;
|
||||
this.transaction = transaction;
|
||||
InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class);
|
||||
this.cache = provider.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME);
|
||||
this.storeFactory = storeFactory;
|
||||
this.storeFactory = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -220,7 +220,7 @@ public class CachedScopeStore implements ScopeStore {
|
|||
}
|
||||
|
||||
private CachedStoreFactoryProvider getCachedStoreFactory() {
|
||||
return session.getProvider(CachedStoreFactoryProvider.class);
|
||||
return cacheStoreFactory;
|
||||
}
|
||||
|
||||
private void invalidateCache(String resourceServerId) {
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
|
||||
package org.keycloak.models.authorization.infinispan;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.keycloak.authorization.store.PolicyStore;
|
||||
import org.keycloak.authorization.store.ResourceServerStore;
|
||||
import org.keycloak.authorization.store.ResourceStore;
|
||||
|
@ -27,31 +30,25 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.models.KeycloakTransaction;
|
||||
import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class InfinispanStoreFactoryProvider implements CachedStoreFactoryProvider {
|
||||
|
||||
private final KeycloakSession session;
|
||||
private final CacheTransaction transaction;
|
||||
private final StoreFactory storeFactory;
|
||||
private final CachedResourceStore resourceStore;
|
||||
private final CachedScopeStore scopeStore;
|
||||
private final CachedPolicyStore policyStore;
|
||||
private ResourceServerStore resourceServerStore;
|
||||
|
||||
InfinispanStoreFactoryProvider(KeycloakSession delegate) {
|
||||
this.session = delegate;
|
||||
public InfinispanStoreFactoryProvider(KeycloakSession session) {
|
||||
this.transaction = new CacheTransaction();
|
||||
this.session.getTransactionManager().enlistAfterCompletion(transaction);
|
||||
storeFactory = this.session.getProvider(StoreFactory.class);
|
||||
resourceStore = new CachedResourceStore(this.session, this.transaction, storeFactory);
|
||||
resourceServerStore = new CachedResourceServerStore(this.session, this.transaction, storeFactory);
|
||||
scopeStore = new CachedScopeStore(this.session, this.transaction, storeFactory);
|
||||
policyStore = new CachedPolicyStore(this.session, this.transaction, storeFactory);
|
||||
session.getTransactionManager().enlistAfterCompletion(transaction);
|
||||
StoreFactory delegate = session.getProvider(StoreFactory.class);
|
||||
resourceStore = new CachedResourceStore(session, this, this.transaction, delegate);
|
||||
resourceServerStore = new CachedResourceServerStore(session, this.transaction, delegate);
|
||||
scopeStore = new CachedScopeStore(session, this, this.transaction, delegate);
|
||||
policyStore = new CachedPolicyStore(session, this, this.transaction, delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
package org.keycloak.models.authorization.infinispan;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.store.StoreFactory;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
|
||||
|
|
|
@ -160,7 +160,7 @@ public class CachedPolicy implements Policy, Serializable {
|
|||
|
||||
@Override
|
||||
public void removeResource(Resource resource) {
|
||||
this.resourcesIds.add(resource.getId());
|
||||
this.resourcesIds.remove(resource.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -637,6 +637,11 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
|||
while(itr.hasNext()) {
|
||||
UserSessionEntity entity = (UserSessionEntity) itr.next().getValue();
|
||||
Set<String> currClientSessions = entity.getClientSessions();
|
||||
|
||||
if (currClientSessions == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (String clientSessionId : currClientSessions) {
|
||||
ClientSessionEntity cls = (ClientSessionEntity) offlineSessionCache.get(clientSessionId);
|
||||
if (cls != null) {
|
||||
|
|
|
@ -18,14 +18,15 @@
|
|||
|
||||
package org.keycloak.authorization.jpa.store;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.store.AuthorizationStoreFactory;
|
||||
import org.keycloak.authorization.store.StoreFactory;
|
||||
import org.keycloak.connections.jpa.JpaConnectionProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
|
|
|
@ -17,14 +17,10 @@
|
|||
*/
|
||||
package org.keycloak.authorization.jpa.store;
|
||||
|
||||
import org.keycloak.authorization.jpa.entities.PolicyEntity;
|
||||
import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
|
||||
import org.keycloak.authorization.jpa.entities.ScopeEntity;
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.authorization.model.Scope;
|
||||
import org.keycloak.authorization.store.PolicyStore;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.NoResultException;
|
||||
|
@ -33,11 +29,14 @@ import javax.persistence.criteria.CriteriaBuilder;
|
|||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.keycloak.authorization.jpa.entities.PolicyEntity;
|
||||
import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.authorization.store.PolicyStore;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
|
@ -51,23 +50,19 @@ public class JPAPolicyStore implements PolicyStore {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Policy create(String name, String type, ResourceServer resourceServer) {
|
||||
public Policy create(AbstractPolicyRepresentation representation, ResourceServer resourceServer) {
|
||||
PolicyEntity entity = new PolicyEntity();
|
||||
|
||||
entity.setId(KeycloakModelUtils.generateId());
|
||||
entity.setName(name);
|
||||
entity.setType(type);
|
||||
entity.setType(representation.getType());
|
||||
entity.setName(representation.getName());
|
||||
entity.setResourceServer((ResourceServerEntity) resourceServer);
|
||||
|
||||
this.entityManager.persist(entity);
|
||||
|
||||
this.entityManager.flush();
|
||||
return entity;
|
||||
}
|
||||
|
||||
public EntityManager getEntityManager() {
|
||||
return this.entityManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String id) {
|
||||
Policy policy = entityManager.find(PolicyEntity.class, id);
|
||||
|
@ -99,7 +94,7 @@ public class JPAPolicyStore implements PolicyStore {
|
|||
@Override
|
||||
public Policy findByName(String name, String resourceServerId) {
|
||||
try {
|
||||
Query query = getEntityManager().createQuery("from PolicyEntity where name = :name and resourceServer.id = :serverId");
|
||||
Query query = entityManager.createQuery("from PolicyEntity where name = :name and resourceServer.id = :serverId");
|
||||
|
||||
query.setParameter("name", name);
|
||||
query.setParameter("serverId", resourceServerId);
|
||||
|
@ -112,7 +107,7 @@ public class JPAPolicyStore implements PolicyStore {
|
|||
|
||||
@Override
|
||||
public List<Policy> findByResourceServer(final String resourceServerId) {
|
||||
Query query = getEntityManager().createQuery("from PolicyEntity where resourceServer.id = :serverId");
|
||||
Query query = entityManager.createQuery("from PolicyEntity where resourceServer.id = :serverId");
|
||||
|
||||
query.setParameter("serverId", resourceServerId);
|
||||
|
||||
|
@ -158,7 +153,7 @@ public class JPAPolicyStore implements PolicyStore {
|
|||
|
||||
@Override
|
||||
public List<Policy> findByResource(final String resourceId, String resourceServerId) {
|
||||
Query query = getEntityManager().createQuery("select p from PolicyEntity p inner join p.resources r where p.resourceServer.id = :serverId and (r.resourceServer.id = :serverId and r.id = :resourceId)");
|
||||
Query query = entityManager.createQuery("select p from PolicyEntity p inner join p.resources r where p.resourceServer.id = :serverId and (r.resourceServer.id = :serverId and r.id = :resourceId)");
|
||||
|
||||
query.setParameter("resourceId", resourceId);
|
||||
query.setParameter("serverId", resourceServerId);
|
||||
|
@ -168,7 +163,7 @@ public class JPAPolicyStore implements PolicyStore {
|
|||
|
||||
@Override
|
||||
public List<Policy> findByResourceType(final String resourceType, String resourceServerId) {
|
||||
Query query = getEntityManager().createQuery("select p from PolicyEntity p inner join p.config c where p.resourceServer.id = :serverId and KEY(c) = 'defaultResourceType' and c like :type");
|
||||
Query query = entityManager.createQuery("select p from PolicyEntity p inner join p.config c where p.resourceServer.id = :serverId and KEY(c) = 'defaultResourceType' and c like :type");
|
||||
|
||||
query.setParameter("serverId", resourceServerId);
|
||||
query.setParameter("type", resourceType);
|
||||
|
@ -183,7 +178,7 @@ public class JPAPolicyStore implements PolicyStore {
|
|||
}
|
||||
|
||||
// Use separate subquery to handle DB2 and MSSSQL
|
||||
Query query = getEntityManager().createQuery("select pe from PolicyEntity pe where pe.resourceServer.id = :serverId and pe.id IN (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.type = 'scope' and s.id in (:scopeIds)))");
|
||||
Query query = entityManager.createQuery("select pe from PolicyEntity pe where pe.resourceServer.id = :serverId and pe.id IN (select p.id from ScopeEntity s inner join s.policies p where s.resourceServer.id = :serverId and (p.resourceServer.id = :serverId and p.type = 'scope' and s.id in (:scopeIds)))");
|
||||
|
||||
query.setParameter("serverId", resourceServerId);
|
||||
query.setParameter("scopeIds", scopeIds);
|
||||
|
@ -193,7 +188,7 @@ public class JPAPolicyStore implements PolicyStore {
|
|||
|
||||
@Override
|
||||
public List<Policy> findByType(String type, String resourceServerId) {
|
||||
Query query = getEntityManager().createQuery("select p from PolicyEntity p where p.resourceServer.id = :serverId and p.type = :type");
|
||||
Query query = entityManager.createQuery("select p from PolicyEntity p where p.resourceServer.id = :serverId and p.type = :type");
|
||||
|
||||
query.setParameter("serverId", resourceServerId);
|
||||
query.setParameter("type", type);
|
||||
|
@ -203,7 +198,7 @@ public class JPAPolicyStore implements PolicyStore {
|
|||
|
||||
@Override
|
||||
public List<Policy> findDependentPolicies(String policyId, String resourceServerId) {
|
||||
Query query = getEntityManager().createQuery("select p from PolicyEntity p inner join p.associatedPolicies ap where p.resourceServer.id = :serverId and (ap.resourceServer.id = :serverId and ap.id = :policyId)");
|
||||
Query query = entityManager.createQuery("select p from PolicyEntity p inner join p.associatedPolicies ap where p.resourceServer.id = :serverId and (ap.resourceServer.id = :serverId and ap.id = :policyId)");
|
||||
|
||||
query.setParameter("serverId", resourceServerId);
|
||||
query.setParameter("policyId", policyId);
|
||||
|
|
|
@ -18,43 +18,49 @@
|
|||
|
||||
package org.keycloak.authorization.jpa.store;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.keycloak.authorization.store.PolicyStore;
|
||||
import org.keycloak.authorization.store.ResourceServerStore;
|
||||
import org.keycloak.authorization.store.ResourceStore;
|
||||
import org.keycloak.authorization.store.ScopeStore;
|
||||
import org.keycloak.authorization.store.StoreFactory;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class JPAStoreFactory implements StoreFactory {
|
||||
|
||||
private final EntityManager entityManager;
|
||||
private final PolicyStore policyStore;
|
||||
private final ResourceServerStore resourceServerStore;
|
||||
private final ResourceStore resourceStore;
|
||||
private final ScopeStore scopeStore;
|
||||
|
||||
public JPAStoreFactory(EntityManager entityManager) {
|
||||
this.entityManager = entityManager;
|
||||
policyStore = new JPAPolicyStore(entityManager);
|
||||
resourceServerStore = new JPAResourceServerStore(entityManager);
|
||||
resourceStore = new JPAResourceStore(entityManager);
|
||||
scopeStore = new JPAScopeStore(entityManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolicyStore getPolicyStore() {
|
||||
return new JPAPolicyStore(this.entityManager);
|
||||
return policyStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceServerStore getResourceServerStore() {
|
||||
return new JPAResourceServerStore(this.entityManager);
|
||||
return resourceServerStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceStore getResourceStore() {
|
||||
return new JPAResourceStore(this.entityManager);
|
||||
return resourceStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScopeStore getScopeStore() {
|
||||
return new JPAScopeStore(this.entityManager);
|
||||
return scopeStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
16
pom.xml
16
pom.xml
|
@ -42,10 +42,12 @@
|
|||
<!-- WildFly -->
|
||||
<jboss.as.version>7.2.0.Final</jboss.as.version>
|
||||
<wildfly.version>10.0.0.Final</wildfly.version>
|
||||
<wildfly.build-tools.version>1.1.3.Final</wildfly.build-tools.version>
|
||||
<wildfly11.version>11.0.0.Alpha1</wildfly11.version> <!-- for testing with wf11 pre-releases -->
|
||||
<wildfly11.build-tools.version>1.1.8.Final</wildfly11.build-tools.version>
|
||||
<eap.version>7.1.0.Alpha1-redhat-16</eap.version>
|
||||
<eap.build-tools.version>1.1.8.Final</eap.build-tools.version>
|
||||
<wildfly.core.version>2.0.10.Final</wildfly.core.version>
|
||||
<wildfly.build-tools.version>1.1.8.Final</wildfly.build-tools.version>
|
||||
|
||||
<version.org.wildfly.security.wildfly-elytron>1.1.0.Beta32</version.org.wildfly.security.wildfly-elytron>
|
||||
<version.org.wildfly.security.elytron-web.undertow-server>1.0.0.Beta14</version.org.wildfly.security.elytron-web.undertow-server>
|
||||
|
@ -1391,6 +1393,13 @@
|
|||
<serverId>jboss-releases-repository</serverId>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<tarLongFileMode>posix</tarLongFileMode>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-release-plugin</artifactId>
|
||||
|
@ -1461,11 +1470,6 @@
|
|||
<artifactId>liquibase-maven-plugin</artifactId>
|
||||
<version>${liquibase.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.wildfly.build</groupId>
|
||||
<artifactId>wildfly-feature-pack-build-maven-plugin</artifactId>
|
||||
<version>${wildfly.build-tools.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.wildfly.build</groupId>
|
||||
<artifactId>wildfly-server-provisioning-maven-plugin</artifactId>
|
||||
|
|
|
@ -21,17 +21,23 @@ package org.keycloak.authorization;
|
|||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.authorization.permission.evaluator.Evaluators;
|
||||
import org.keycloak.authorization.policy.evaluation.DefaultPolicyEvaluator;
|
||||
import org.keycloak.authorization.policy.provider.PolicyProvider;
|
||||
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
|
||||
import org.keycloak.authorization.store.PolicyStore;
|
||||
import org.keycloak.authorization.store.ResourceServerStore;
|
||||
import org.keycloak.authorization.store.ResourceStore;
|
||||
import org.keycloak.authorization.store.ScopeStore;
|
||||
import org.keycloak.authorization.store.StoreFactory;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
||||
|
||||
/**
|
||||
* <p>The main contract here is the creation of {@link org.keycloak.authorization.permission.evaluator.PermissionEvaluator} instances. Usually
|
||||
|
@ -62,25 +68,19 @@ import org.keycloak.provider.Provider;
|
|||
public final class AuthorizationProvider implements Provider {
|
||||
|
||||
private final DefaultPolicyEvaluator policyEvaluator;
|
||||
private final Executor scheduller;
|
||||
private final Supplier<StoreFactory> storeFactory;
|
||||
private StoreFactory storeFactory;
|
||||
private final Map<String, PolicyProviderFactory> policyProviderFactories;
|
||||
private final KeycloakSession keycloakSession;
|
||||
private final RealmModel realm;
|
||||
|
||||
public AuthorizationProvider(KeycloakSession session, RealmModel realm, Supplier<StoreFactory> storeFactory, Map<String, PolicyProviderFactory> policyProviderFactories, Executor scheduller) {
|
||||
public AuthorizationProvider(KeycloakSession session, RealmModel realm, StoreFactory storeFactory, Map<String, PolicyProviderFactory> policyProviderFactories) {
|
||||
this.keycloakSession = session;
|
||||
this.realm = realm;
|
||||
this.storeFactory = storeFactory;
|
||||
this.scheduller = scheduller;
|
||||
this.policyProviderFactories = policyProviderFactories;
|
||||
this.policyEvaluator = new DefaultPolicyEvaluator(this);
|
||||
}
|
||||
|
||||
public AuthorizationProvider(KeycloakSession session, RealmModel realm, StoreFactory storeFactory, Map<String, PolicyProviderFactory> policyProviderFactories) {
|
||||
this(session, realm, () -> storeFactory, policyProviderFactories, Runnable::run);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Evaluators} instance from where {@link org.keycloak.authorization.policy.evaluation.PolicyEvaluator} instances
|
||||
* can be obtained.
|
||||
|
@ -88,7 +88,7 @@ public final class AuthorizationProvider implements Provider {
|
|||
* @return a {@link Evaluators} instance
|
||||
*/
|
||||
public Evaluators evaluators() {
|
||||
return new Evaluators(this.policyEvaluator, this.scheduller);
|
||||
return new Evaluators(policyEvaluator);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,7 +97,105 @@ public final class AuthorizationProvider implements Provider {
|
|||
* @return the {@link StoreFactory}
|
||||
*/
|
||||
public StoreFactory getStoreFactory() {
|
||||
return this.storeFactory.get();
|
||||
return createStoreFactory();
|
||||
}
|
||||
|
||||
private StoreFactory createStoreFactory() {
|
||||
return new StoreFactory() {
|
||||
@Override
|
||||
public ResourceStore getResourceStore() {
|
||||
return storeFactory.getResourceStore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceServerStore getResourceServerStore() {
|
||||
return storeFactory.getResourceServerStore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScopeStore getScopeStore() {
|
||||
return storeFactory.getScopeStore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PolicyStore getPolicyStore() {
|
||||
PolicyStore policyStore = storeFactory.getPolicyStore();
|
||||
return new PolicyStore() {
|
||||
@Override
|
||||
public Policy create(AbstractPolicyRepresentation representation, ResourceServer resourceServer) {
|
||||
return RepresentationToModel.toModel(representation, AuthorizationProvider.this, policyStore.create(representation, resourceServer));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String id) {
|
||||
Policy policy = findById(id, null);
|
||||
|
||||
if (policy != null) {
|
||||
ResourceServer resourceServer = policy.getResourceServer();
|
||||
|
||||
findDependentPolicies(policy.getId(), resourceServer.getId()).forEach(dependentPolicy -> {
|
||||
dependentPolicy.removeAssociatedPolicy(policy);
|
||||
if (dependentPolicy.getAssociatedPolicies().isEmpty()) {
|
||||
delete(dependentPolicy.getId());
|
||||
}
|
||||
});
|
||||
|
||||
policyStore.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy findById(String id, String resourceServerId) {
|
||||
return policyStore.findById(id, resourceServerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy findByName(String name, String resourceServerId) {
|
||||
return policyStore.findByName(name, resourceServerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Policy> findByResourceServer(String resourceServerId) {
|
||||
return policyStore.findByResourceServer(resourceServerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Policy> findByResourceServer(Map<String, String[]> attributes, String resourceServerId, int firstResult, int maxResult) {
|
||||
return policyStore.findByResourceServer(attributes, resourceServerId, firstResult, maxResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Policy> findByResource(String resourceId, String resourceServerId) {
|
||||
return policyStore.findByResource(resourceId, resourceServerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Policy> findByResourceType(String resourceType, String resourceServerId) {
|
||||
return policyStore.findByResourceType(resourceType, resourceServerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Policy> findByScopeIds(List<String> scopeIds, String resourceServerId) {
|
||||
return policyStore.findByScopeIds(scopeIds, resourceServerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Policy> findByType(String type, String resourceServerId) {
|
||||
return policyStore.findByType(type, resourceServerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Policy> findDependentPolicies(String id, String resourceServerId) {
|
||||
return policyStore.findDependentPolicies(id, resourceServerId);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
storeFactory.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,22 +17,18 @@
|
|||
*/
|
||||
package org.keycloak.authorization.permission.evaluator;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.keycloak.authorization.Decision;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
* @see PermissionEvaluator
|
||||
*/
|
||||
class ScheduledPermissionEvaluator implements PermissionEvaluator {
|
||||
class DefaultPermissionEvaluator implements PermissionEvaluator {
|
||||
|
||||
private final PermissionEvaluator publisher;
|
||||
private final Executor scheduler;
|
||||
|
||||
ScheduledPermissionEvaluator(PermissionEvaluator publisher, Executor scheduler) {
|
||||
DefaultPermissionEvaluator(PermissionEvaluator publisher) {
|
||||
this.publisher = publisher;
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
@Override
|
|
@ -19,7 +19,6 @@
|
|||
package org.keycloak.authorization.permission.evaluator;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.keycloak.authorization.permission.ResourcePermission;
|
||||
import org.keycloak.authorization.policy.evaluation.DefaultPolicyEvaluator;
|
||||
|
@ -33,11 +32,9 @@ import org.keycloak.authorization.policy.evaluation.EvaluationContext;
|
|||
public final class Evaluators {
|
||||
|
||||
private final DefaultPolicyEvaluator policyEvaluator;
|
||||
private final Executor scheduler;
|
||||
|
||||
public Evaluators(DefaultPolicyEvaluator policyEvaluator, Executor scheduler) {
|
||||
public Evaluators(DefaultPolicyEvaluator policyEvaluator) {
|
||||
this.policyEvaluator = policyEvaluator;
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
public PermissionEvaluator from(List<ResourcePermission> permissions, EvaluationContext evaluationContext) {
|
||||
|
@ -45,6 +42,6 @@ public final class Evaluators {
|
|||
}
|
||||
|
||||
public PermissionEvaluator schedule(List<ResourcePermission> permissions, EvaluationContext evaluationContext) {
|
||||
return new ScheduledPermissionEvaluator(new IterablePermissionEvaluator(permissions.iterator(), evaluationContext, this.policyEvaluator), this.scheduler);
|
||||
return new DefaultPermissionEvaluator(new IterablePermissionEvaluator(permissions.iterator(), evaluationContext, this.policyEvaluator));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.keycloak.authorization.model.Scope;
|
|||
import org.keycloak.authorization.permission.ResourcePermission;
|
||||
import org.keycloak.authorization.policy.provider.PolicyProvider;
|
||||
import org.keycloak.authorization.store.PolicyStore;
|
||||
import org.keycloak.authorization.store.ResourceStore;
|
||||
import org.keycloak.authorization.store.StoreFactory;
|
||||
import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
|
||||
|
||||
|
@ -46,11 +47,13 @@ public class DefaultPolicyEvaluator implements PolicyEvaluator {
|
|||
private final AuthorizationProvider authorization;
|
||||
private final StoreFactory storeFactory;
|
||||
private final PolicyStore policyStore;
|
||||
private final ResourceStore resourceStore;
|
||||
|
||||
public DefaultPolicyEvaluator(AuthorizationProvider authorization) {
|
||||
this.authorization = authorization;
|
||||
storeFactory = this.authorization.getStoreFactory();
|
||||
policyStore = storeFactory.getPolicyStore();
|
||||
resourceStore = storeFactory.getResourceStore();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -159,7 +162,7 @@ public class DefaultPolicyEvaluator implements PolicyEvaluator {
|
|||
String type = resource.getType();
|
||||
|
||||
if (type != null) {
|
||||
List<Resource> resourcesByType = authorization.getStoreFactory().getResourceStore().findByType(type, resource.getResourceServer().getId());
|
||||
List<Resource> resourcesByType = resourceStore.findByType(type, resource.getResourceServer().getId());
|
||||
|
||||
for (Resource resourceType : resourcesByType) {
|
||||
if (resourceType.getOwner().equals(resource.getResourceServer().getClientId())) {
|
||||
|
|
|
@ -18,16 +18,11 @@
|
|||
|
||||
package org.keycloak.authorization.policy.provider;
|
||||
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public interface PolicyProviderAdminService {
|
||||
public interface PolicyProviderAdminService<R extends AbstractPolicyRepresentation> {
|
||||
|
||||
void onCreate(Policy policy);
|
||||
|
||||
void onUpdate(Policy policy);
|
||||
|
||||
void onRemove(Policy policy);
|
||||
}
|
||||
|
|
|
@ -22,11 +22,13 @@ import org.keycloak.authorization.AuthorizationProvider;
|
|||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public interface PolicyProviderFactory extends ProviderFactory<PolicyProvider> {
|
||||
public interface PolicyProviderFactory<R extends AbstractPolicyRepresentation> extends ProviderFactory<PolicyProvider> {
|
||||
|
||||
String getName();
|
||||
|
||||
|
@ -34,5 +36,31 @@ public interface PolicyProviderFactory extends ProviderFactory<PolicyProvider> {
|
|||
|
||||
PolicyProvider create(AuthorizationProvider authorization);
|
||||
|
||||
PolicyProviderAdminService getAdminResource(ResourceServer resourceServer);
|
||||
default R toRepresentation(Policy policy, R representation) {
|
||||
return representation;
|
||||
}
|
||||
|
||||
default Class<R> getRepresentationType() {
|
||||
return (Class<R>) PolicyRepresentation.class;
|
||||
}
|
||||
|
||||
default void onCreate(Policy policy, R representation, AuthorizationProvider authorization) {
|
||||
|
||||
}
|
||||
|
||||
default void onUpdate(Policy policy, R representation, AuthorizationProvider authorization) {
|
||||
|
||||
}
|
||||
|
||||
default void onRemove(Policy policy, AuthorizationProvider authorization) {
|
||||
|
||||
}
|
||||
|
||||
default void onImport(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
|
||||
|
||||
}
|
||||
|
||||
default PolicyProviderAdminService getAdminResource(ResourceServer resourceServer, AuthorizationProvider authorization) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
|
||||
package org.keycloak.authorization.store;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.keycloak.authorization.store.syncronization.ClientApplicationSynchronizer;
|
||||
import org.keycloak.authorization.store.syncronization.RealmSynchronizer;
|
||||
import org.keycloak.authorization.store.syncronization.Synchronizer;
|
||||
|
@ -29,9 +32,6 @@ import org.keycloak.models.UserModel.UserRemovedEvent;
|
|||
import org.keycloak.provider.ProviderEvent;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
|
|
|
@ -18,12 +18,13 @@
|
|||
package org.keycloak.authorization.store;
|
||||
|
||||
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
||||
|
||||
/**
|
||||
* A {@link PolicyStore} is responsible to manage the persistence of {@link Policy} instances.
|
||||
*
|
||||
|
@ -35,12 +36,11 @@ public interface PolicyStore {
|
|||
* Creates a new {@link Policy} instance. The new instance is not necessarily persisted though, which may require
|
||||
* a call to the {#save} method to actually make it persistent.
|
||||
*
|
||||
* @param name the name of the policy
|
||||
* @param type the type of the policy
|
||||
* @param representation the policy representation
|
||||
* @param resourceServer the resource server to which this policy belongs
|
||||
* @return a new instance of {@link Policy}
|
||||
*/
|
||||
Policy create(String name, String type, ResourceServer resourceServer);
|
||||
Policy create(AbstractPolicyRepresentation representation, ResourceServer resourceServer);
|
||||
|
||||
/**
|
||||
* Deletes a policy from the underlying persistence mechanism.
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.keycloak.authorization.model.Policy;
|
|||
import org.keycloak.authorization.model.Resource;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.authorization.model.Scope;
|
||||
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
|
||||
import org.keycloak.authorization.store.ResourceStore;
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
import org.keycloak.common.util.Time;
|
||||
|
@ -87,6 +88,7 @@ import org.keycloak.representations.idm.RoleRepresentation;
|
|||
import org.keycloak.representations.idm.UserConsentRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.idm.UserSessionRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
|
@ -793,16 +795,29 @@ public class ModelToRepresentation {
|
|||
return server;
|
||||
}
|
||||
|
||||
public static PolicyRepresentation toRepresentation(Policy model) {
|
||||
PolicyRepresentation representation = new PolicyRepresentation();
|
||||
public static <R extends AbstractPolicyRepresentation> R toRepresentation(Policy policy, Class<R> representationType, AuthorizationProvider authorization) {
|
||||
R representation;
|
||||
|
||||
representation.setId(model.getId());
|
||||
representation.setName(model.getName());
|
||||
representation.setDescription(model.getDescription());
|
||||
representation.setType(model.getType());
|
||||
representation.setDecisionStrategy(model.getDecisionStrategy());
|
||||
representation.setLogic(model.getLogic());
|
||||
representation.setConfig(new HashMap<>(model.getConfig()));
|
||||
try {
|
||||
representation = representationType.newInstance();
|
||||
} catch (Exception cause) {
|
||||
throw new RuntimeException("Could not create policy [" + policy.getType() + "] representation", cause);
|
||||
}
|
||||
|
||||
PolicyProviderFactory providerFactory = authorization.getProviderFactory(policy.getType());
|
||||
|
||||
representation.setId(policy.getId());
|
||||
representation.setName(policy.getName());
|
||||
representation.setDescription(policy.getDescription());
|
||||
representation.setType(policy.getType());
|
||||
representation.setDecisionStrategy(policy.getDecisionStrategy());
|
||||
representation.setLogic(policy.getLogic());
|
||||
|
||||
if (representation instanceof PolicyRepresentation) {
|
||||
PolicyRepresentation.class.cast(representation).setConfig(policy.getConfig());
|
||||
} else {
|
||||
representation = (R) providerFactory.toRepresentation(policy, representation);
|
||||
}
|
||||
|
||||
return representation;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,18 @@
|
|||
|
||||
package org.keycloak.models.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.AuthorizationProviderFactory;
|
||||
|
@ -24,7 +36,7 @@ import org.keycloak.authorization.model.Policy;
|
|||
import org.keycloak.authorization.model.Resource;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.authorization.model.Scope;
|
||||
import org.keycloak.authorization.policy.provider.PolicyProvider;
|
||||
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
|
||||
import org.keycloak.authorization.store.PolicyStore;
|
||||
import org.keycloak.authorization.store.ResourceServerStore;
|
||||
import org.keycloak.authorization.store.ResourceStore;
|
||||
|
@ -92,6 +104,7 @@ import org.keycloak.representations.idm.UserConsentRepresentation;
|
|||
import org.keycloak.representations.idm.UserFederationMapperRepresentation;
|
||||
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation;
|
||||
|
@ -103,18 +116,6 @@ import org.keycloak.storage.UserStorageProviderModel;
|
|||
import org.keycloak.storage.federated.UserFederatedStorageProvider;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class RepresentationToModel {
|
||||
|
||||
private static Logger logger = Logger.getLogger(RepresentationToModel.class);
|
||||
|
@ -1896,9 +1897,6 @@ public class RepresentationToModel {
|
|||
resourceServer.setPolicyEnforcementMode(rep.getPolicyEnforcementMode());
|
||||
resourceServer.setAllowRemoteResourceManagement(rep.isAllowRemoteResourceManagement());
|
||||
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
ScopeStore scopeStore = storeFactory.getScopeStore();
|
||||
|
||||
rep.getScopes().forEach(scope -> {
|
||||
toModel(scope, resourceServer, authorization);
|
||||
});
|
||||
|
@ -1932,138 +1930,12 @@ public class RepresentationToModel {
|
|||
|
||||
private static Policy importPolicies(AuthorizationProvider authorization, ResourceServer resourceServer, List<PolicyRepresentation> policiesToImport, String parentPolicyName) {
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
KeycloakSession session = authorization.getKeycloakSession();
|
||||
RealmModel realm = authorization.getRealm();
|
||||
for (PolicyRepresentation policyRepresentation : policiesToImport) {
|
||||
if (parentPolicyName != null && !parentPolicyName.equals(policyRepresentation.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Map<String, String> config = policyRepresentation.getConfig();
|
||||
|
||||
String roles = config.get("roles");
|
||||
|
||||
if (roles != null && !roles.isEmpty()) {
|
||||
try {
|
||||
List<Map> rolesMap = (List<Map>) JsonSerialization.readValue(roles, List.class);
|
||||
config.put("roles", JsonSerialization.writeValueAsString(rolesMap.stream().map(roleConfig -> {
|
||||
String roleName = roleConfig.get("id").toString();
|
||||
String clientId = null;
|
||||
int clientIdSeparator = roleName.indexOf("/");
|
||||
|
||||
if (clientIdSeparator != -1) {
|
||||
clientId = roleName.substring(0, clientIdSeparator);
|
||||
roleName = roleName.substring(clientIdSeparator + 1);
|
||||
}
|
||||
|
||||
RoleModel role;
|
||||
|
||||
if (clientId == null) {
|
||||
role = realm.getRole(roleName);
|
||||
} else {
|
||||
role = realm.getClientByClientId(clientId).getRole(roleName);
|
||||
}
|
||||
|
||||
// fallback to find any client role with the given name
|
||||
if (role == null) {
|
||||
String finalRoleName = roleName;
|
||||
role = realm.getClients().stream().map(clientModel -> clientModel.getRole(finalRoleName)).filter(roleModel -> roleModel != null)
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
if (role == null) {
|
||||
role = realm.getRoleById(roleName);
|
||||
|
||||
if (role == null) {
|
||||
String finalRoleName1 = roleName;
|
||||
role = realm.getClients().stream().map(clientModel -> clientModel.getRole(finalRoleName1)).filter(roleModel -> roleModel != null)
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
if (role == null) {
|
||||
throw new RuntimeException("Error while importing configuration. Role [" + roleName + "] could not be found.");
|
||||
}
|
||||
|
||||
roleConfig.put("id", role.getId());
|
||||
return roleConfig;
|
||||
}).collect(Collectors.toList())));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error while exporting policy [" + policyRepresentation.getName() + "].", e);
|
||||
}
|
||||
}
|
||||
|
||||
String users = config.get("users");
|
||||
|
||||
if (users != null && !users.isEmpty()) {
|
||||
try {
|
||||
List<String> usersMap = (List<String>) JsonSerialization.readValue(users, List.class);
|
||||
config.put("users", JsonSerialization.writeValueAsString(usersMap.stream().map(userId -> {
|
||||
UserModel user = session.users().getUserByUsername(userId, realm);
|
||||
|
||||
if (user == null) {
|
||||
user = session.users().getUserById(userId, realm);
|
||||
}
|
||||
|
||||
if (user == null) {
|
||||
throw new RuntimeException("Error while importing configuration. User [" + userId + "] could not be found.");
|
||||
}
|
||||
|
||||
return user.getId();
|
||||
}).collect(Collectors.toList())));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error while exporting policy [" + policyRepresentation.getName() + "].", e);
|
||||
}
|
||||
}
|
||||
|
||||
String scopes = config.get("scopes");
|
||||
|
||||
if (scopes != null && !scopes.isEmpty()) {
|
||||
try {
|
||||
ScopeStore scopeStore = storeFactory.getScopeStore();
|
||||
List<String> scopesMap = (List<String>) JsonSerialization.readValue(scopes, List.class);
|
||||
config.put("scopes", JsonSerialization.writeValueAsString(scopesMap.stream().map(scopeName -> {
|
||||
Scope newScope = scopeStore.findByName(scopeName, resourceServer.getId());
|
||||
|
||||
if (newScope == null) {
|
||||
newScope = scopeStore.findById(scopeName, resourceServer.getId());
|
||||
}
|
||||
|
||||
if (newScope == null) {
|
||||
throw new RuntimeException("Scope with name [" + scopeName + "] not defined.");
|
||||
}
|
||||
|
||||
return newScope.getId();
|
||||
}).collect(Collectors.toList())));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error while exporting policy [" + policyRepresentation.getName() + "].", e);
|
||||
}
|
||||
}
|
||||
|
||||
String policyResources = config.get("resources");
|
||||
|
||||
if (policyResources != null && !policyResources.isEmpty()) {
|
||||
ResourceStore resourceStore = storeFactory.getResourceStore();
|
||||
try {
|
||||
List<String> resources = JsonSerialization.readValue(policyResources, List.class);
|
||||
config.put("resources", JsonSerialization.writeValueAsString(resources.stream().map(resourceName -> {
|
||||
Resource resource = resourceStore.findByName(resourceName, resourceServer.getId());
|
||||
|
||||
if (resource == null) {
|
||||
resource = resourceStore.findById(resourceName, resourceServer.getId());
|
||||
}
|
||||
|
||||
if (resource == null) {
|
||||
throw new RuntimeException("Resource with name [" + resourceName + "] not defined.");
|
||||
}
|
||||
|
||||
return resource.getId();
|
||||
}).collect(Collectors.toList())));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error while exporting policy [" + policyRepresentation.getName() + "].", e);
|
||||
}
|
||||
}
|
||||
|
||||
String applyPolicies = config.get("applyPolicies");
|
||||
|
||||
if (applyPolicies != null && !applyPolicies.isEmpty()) {
|
||||
|
@ -2087,91 +1959,111 @@ public class RepresentationToModel {
|
|||
return policy.getId();
|
||||
}).collect(Collectors.toList())));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error while exporting policy [" + policyRepresentation.getName() + "].", e);
|
||||
throw new RuntimeException("Error while importing policy [" + policyRepresentation.getName() + "].", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (parentPolicyName == null) {
|
||||
toModel(policyRepresentation, resourceServer, authorization);
|
||||
} else if (parentPolicyName.equals(policyRepresentation.getName())) {
|
||||
return toModel(policyRepresentation, resourceServer, authorization);
|
||||
PolicyStore policyStore = storeFactory.getPolicyStore();
|
||||
Policy policy = policyStore.findById(policyRepresentation.getId(), resourceServer.getId());
|
||||
|
||||
if (policy == null) {
|
||||
policy = policyStore.findByName(policyRepresentation.getName(), resourceServer.getId());
|
||||
}
|
||||
|
||||
if (policy == null) {
|
||||
policy = policyStore.create(policyRepresentation, resourceServer);
|
||||
} else {
|
||||
policy = toModel(policyRepresentation, authorization, policy);
|
||||
}
|
||||
|
||||
if (parentPolicyName != null && parentPolicyName.equals(policyRepresentation.getName())) {
|
||||
return policy;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Policy toModel(PolicyRepresentation policy, ResourceServer resourceServer, AuthorizationProvider authorization) {
|
||||
String type = policy.getType();
|
||||
PolicyProvider provider = authorization.getProvider(type);
|
||||
public static Policy toModel(AbstractPolicyRepresentation representation, AuthorizationProvider authorization, Policy model) {
|
||||
model.setName(representation.getName());
|
||||
model.setDescription(representation.getDescription());
|
||||
model.setDecisionStrategy(representation.getDecisionStrategy());
|
||||
model.setLogic(representation.getLogic());
|
||||
|
||||
if (provider == null) {
|
||||
//TODO: temporary, remove this check on future versions as drools type is now deprecated
|
||||
if ("drools".equalsIgnoreCase(type)) {
|
||||
type = "rules";
|
||||
Set resources = representation.getResources();
|
||||
Set scopes = representation.getScopes();
|
||||
Set policies = representation.getPolicies();
|
||||
|
||||
if (representation instanceof PolicyRepresentation) {
|
||||
PolicyRepresentation policy = PolicyRepresentation.class.cast(representation);
|
||||
String resourcesConfig = policy.getConfig().get("resources");
|
||||
|
||||
if (resourcesConfig != null) {
|
||||
try {
|
||||
resources = JsonSerialization.readValue(resourcesConfig, Set.class);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
if (authorization.getProvider(type) == null) {
|
||||
throw new RuntimeException("Unknown polucy type [" + type + "]. Could not find a provider for this type.");
|
||||
|
||||
String scopesConfig = policy.getConfig().get("scopes");
|
||||
|
||||
if (scopesConfig != null) {
|
||||
try {
|
||||
scopes = JsonSerialization.readValue(scopesConfig, Set.class);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
String policiesConfig = policy.getConfig().get("applyPolicies");
|
||||
|
||||
if (policiesConfig != null) {
|
||||
try {
|
||||
policies = JsonSerialization.readValue(policiesConfig, Set.class);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
model.setConfig(policy.getConfig());
|
||||
}
|
||||
|
||||
PolicyStore policyStore = authorization.getStoreFactory().getPolicyStore();
|
||||
Policy existing;
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
|
||||
if (policy.getId() != null) {
|
||||
existing = policyStore.findById(policy.getId(), resourceServer.getId());
|
||||
updateResources(resources, model, storeFactory);
|
||||
updateScopes(scopes, model, storeFactory);
|
||||
updateAssociatedPolicies(policies, model, storeFactory);
|
||||
|
||||
PolicyProviderFactory provider = authorization.getProviderFactory(model.getType());
|
||||
|
||||
if (representation instanceof PolicyRepresentation) {
|
||||
provider.onImport(model, PolicyRepresentation.class.cast(representation), authorization);
|
||||
} else if (representation.getId() == null) {
|
||||
provider.onCreate(model, representation, authorization);
|
||||
} else {
|
||||
existing = policyStore.findByName(policy.getName(), resourceServer.getId());
|
||||
provider.onUpdate(model, representation, authorization);
|
||||
}
|
||||
|
||||
if (existing != null) {
|
||||
existing.setName(policy.getName());
|
||||
existing.setDescription(policy.getDescription());
|
||||
existing.setConfig(policy.getConfig());
|
||||
existing.setDecisionStrategy(policy.getDecisionStrategy());
|
||||
existing.setLogic(policy.getLogic());
|
||||
|
||||
updateResources(existing, authorization);
|
||||
updateAssociatedPolicies(existing, resourceServer, authorization);
|
||||
updateScopes(existing, authorization);
|
||||
|
||||
return existing;
|
||||
}
|
||||
|
||||
Policy model = policyStore.create(policy.getName(), type, resourceServer);
|
||||
|
||||
model.setDescription(policy.getDescription());
|
||||
model.setDecisionStrategy(policy.getDecisionStrategy());
|
||||
model.setLogic(policy.getLogic());
|
||||
model.setConfig(policy.getConfig());
|
||||
|
||||
updateResources(model, authorization);
|
||||
updateAssociatedPolicies(model, resourceServer, authorization);
|
||||
updateScopes(model, authorization);
|
||||
|
||||
policy.setId(model.getId());
|
||||
representation.setId(model.getId());
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
private static void updateScopes(Policy policy, AuthorizationProvider authorization) {
|
||||
String scopes = policy.getConfig().get("scopes");
|
||||
if (scopes != null) {
|
||||
String[] scopeIds;
|
||||
|
||||
try {
|
||||
scopeIds = JsonSerialization.readValue(scopes, String[].class);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
private static void updateScopes(Set<String> scopeIds, Policy policy, StoreFactory storeFactory) {
|
||||
if (scopeIds != null) {
|
||||
if (scopeIds.isEmpty()) {
|
||||
for (Scope scope : new HashSet<Scope>(policy.getScopes())) {
|
||||
policy.removeScope(scope);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
|
||||
for (String scopeId : scopeIds) {
|
||||
boolean hasScope = false;
|
||||
|
||||
for (Scope scopeModel : new HashSet<Scope>(policy.getScopes())) {
|
||||
if (scopeModel.getId().equals(scopeId)) {
|
||||
if (scopeModel.getId().equals(scopeId) || scopeModel.getName().equals(scopeId)) {
|
||||
hasScope = true;
|
||||
}
|
||||
}
|
||||
|
@ -2180,7 +2072,10 @@ public class RepresentationToModel {
|
|||
Scope scope = storeFactory.getScopeStore().findById(scopeId, resourceServer.getId());
|
||||
|
||||
if (scope == null) {
|
||||
storeFactory.getScopeStore().findByName(scopeId, resourceServer.getId());
|
||||
scope = storeFactory.getScopeStore().findByName(scopeId, resourceServer.getId());
|
||||
if (scope == null) {
|
||||
throw new RuntimeException("Scope with id or name [" + scopeId + "] does not exist");
|
||||
}
|
||||
}
|
||||
|
||||
policy.addScope(scope);
|
||||
|
@ -2191,7 +2086,7 @@ public class RepresentationToModel {
|
|||
boolean hasScope = false;
|
||||
|
||||
for (String scopeId : scopeIds) {
|
||||
if (scopeModel.getId().equals(scopeId)) {
|
||||
if (scopeModel.getId().equals(scopeId) || scopeModel.getName().equals(scopeId)) {
|
||||
hasScope = true;
|
||||
}
|
||||
}
|
||||
|
@ -2199,24 +2094,22 @@ public class RepresentationToModel {
|
|||
policy.removeScope(scopeModel);
|
||||
}
|
||||
}
|
||||
|
||||
policy.getConfig().remove("scopes");
|
||||
}
|
||||
|
||||
policy.getConfig().remove("scopes");
|
||||
}
|
||||
|
||||
private static void updateAssociatedPolicies(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization) {
|
||||
String policies = policy.getConfig().get("applyPolicies");
|
||||
private static void updateAssociatedPolicies(Set<String> policyIds, Policy policy, StoreFactory storeFactory) {
|
||||
ResourceServer resourceServer = policy.getResourceServer();
|
||||
|
||||
if (policies != null) {
|
||||
String[] policyIds;
|
||||
|
||||
try {
|
||||
policyIds = JsonSerialization.readValue(policies, String[].class);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
if (policyIds != null) {
|
||||
if (policyIds.isEmpty()) {
|
||||
for (Policy associated: new HashSet<Policy>(policy.getAssociatedPolicies())) {
|
||||
policy.removeAssociatedPolicy(associated);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
PolicyStore policyStore = storeFactory.getPolicyStore();
|
||||
|
||||
for (String policyId : policyIds) {
|
||||
|
@ -2228,12 +2121,14 @@ public class RepresentationToModel {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (!hasPolicy) {
|
||||
Policy associatedPolicy = policyStore.findById(policyId, resourceServer.getId());
|
||||
|
||||
if (associatedPolicy == null) {
|
||||
associatedPolicy = policyStore.findByName(policyId, resourceServer.getId());
|
||||
if (associatedPolicy == null) {
|
||||
throw new RuntimeException("Policy with id or name [" + policyId + "] does not exist");
|
||||
}
|
||||
}
|
||||
|
||||
policy.addAssociatedPolicy(associatedPolicy);
|
||||
|
@ -2250,31 +2145,24 @@ public class RepresentationToModel {
|
|||
}
|
||||
if (!hasPolicy) {
|
||||
policy.removeAssociatedPolicy(policyModel);
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
policy.getConfig().remove("applyPolicies");
|
||||
}
|
||||
|
||||
policy.getConfig().remove("applyPolicies");
|
||||
}
|
||||
|
||||
private static void updateResources(Policy policy, AuthorizationProvider authorization) {
|
||||
String resources = policy.getConfig().get("resources");
|
||||
if (resources != null) {
|
||||
String[] resourceIds;
|
||||
|
||||
try {
|
||||
resourceIds = JsonSerialization.readValue(resources, String[].class);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
private static void updateResources(Set<String> resourceIds, Policy policy, StoreFactory storeFactory) {
|
||||
if (resourceIds != null) {
|
||||
if (resourceIds.isEmpty()) {
|
||||
for (Scope scope : new HashSet<Scope>(policy.getScopes())) {
|
||||
policy.removeScope(scope);
|
||||
}
|
||||
}
|
||||
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
|
||||
for (String resourceId : resourceIds) {
|
||||
boolean hasResource = false;
|
||||
for (Resource resourceModel : new HashSet<Resource>(policy.getResources())) {
|
||||
if (resourceModel.getId().equals(resourceId)) {
|
||||
if (resourceModel.getId().equals(resourceId) || resourceModel.getName().equals(resourceId)) {
|
||||
hasResource = true;
|
||||
}
|
||||
}
|
||||
|
@ -2282,7 +2170,10 @@ public class RepresentationToModel {
|
|||
Resource resource = storeFactory.getResourceStore().findById(resourceId, policy.getResourceServer().getId());
|
||||
|
||||
if (resource == null) {
|
||||
throw new RuntimeException("Resource [" + resourceId + "] not found.");
|
||||
resource = storeFactory.getResourceStore().findByName(resourceId, policy.getResourceServer().getId());
|
||||
if (resource == null) {
|
||||
throw new RuntimeException("Resource with id or name [" + resourceId + "] does not exist");
|
||||
}
|
||||
}
|
||||
|
||||
policy.addResource(resource);
|
||||
|
@ -2293,7 +2184,7 @@ public class RepresentationToModel {
|
|||
boolean hasResource = false;
|
||||
|
||||
for (String resourceId : resourceIds) {
|
||||
if (resourceModel.getId().equals(resourceId)) {
|
||||
if (resourceModel.getId().equals(resourceId) || resourceModel.getName().equals(resourceId)) {
|
||||
hasResource = true;
|
||||
}
|
||||
}
|
||||
|
@ -2302,9 +2193,9 @@ public class RepresentationToModel {
|
|||
policy.removeResource(resourceModel);
|
||||
}
|
||||
}
|
||||
|
||||
policy.getConfig().remove("resources");
|
||||
}
|
||||
|
||||
policy.getConfig().remove("resources");
|
||||
}
|
||||
|
||||
public static Resource toModel(ResourceRepresentation resource, ResourceServer resourceServer, AuthorizationProvider authorization) {
|
||||
|
|
|
@ -21,7 +21,6 @@ package org.keycloak.authorization;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.authorization.policy.provider.PolicyProvider;
|
||||
|
@ -38,7 +37,6 @@ import org.keycloak.provider.ProviderFactory;
|
|||
*/
|
||||
public class DefaultAuthorizationProviderFactory implements AuthorizationProviderFactory {
|
||||
|
||||
private Executor scheduler;
|
||||
private Map<String, PolicyProviderFactory> policyProviderFactories;
|
||||
|
||||
@Override
|
||||
|
@ -48,15 +46,6 @@ public class DefaultAuthorizationProviderFactory implements AuthorizationProvide
|
|||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
//TODO: user-defined configuration
|
||||
// Executor executor = Executors.newWorkStealingPool();
|
||||
// this.scheduler = command -> {
|
||||
// Map<Class<?>, Object> contextDataMap = ResteasyProviderFactory.getContextDataMap();
|
||||
// executor.execute(() -> {
|
||||
// ResteasyProviderFactory.pushContextDataMap(contextDataMap);
|
||||
// command.run();
|
||||
// });
|
||||
// };
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -77,11 +66,9 @@ public class DefaultAuthorizationProviderFactory implements AuthorizationProvide
|
|||
@Override
|
||||
public AuthorizationProvider create(KeycloakSession session, RealmModel realm) {
|
||||
StoreFactory storeFactory = session.getProvider(CachedStoreFactoryProvider.class);
|
||||
|
||||
if (storeFactory == null) {
|
||||
storeFactory = session.getProvider(StoreFactory.class);
|
||||
}
|
||||
|
||||
return new AuthorizationProvider(session, realm, storeFactory, policyProviderFactories);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.admin;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.services.resources.admin.RealmAuth;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class PermissionService extends PolicyService {
|
||||
|
||||
public PermissionService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) {
|
||||
super(resourceServer, authorization, auth);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PolicyResourceService doCreatePolicyResource(Policy policy) {
|
||||
return new PolicyTypeResourceService(policy, resourceServer, authorization, auth);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Object> doSearch(Integer firstResult, Integer maxResult, Map<String, String[]> filters) {
|
||||
filters.put("permission", new String[] {Boolean.TRUE.toString()});
|
||||
return super.doSearch(firstResult, maxResult, filters);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* 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.admin;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
|
||||
import org.keycloak.authorization.store.PolicyStore;
|
||||
import org.keycloak.authorization.store.StoreFactory;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
|
||||
import org.keycloak.services.resources.admin.RealmAuth;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class PolicyResourceService {
|
||||
|
||||
private final Policy policy;
|
||||
protected final ResourceServer resourceServer;
|
||||
protected final AuthorizationProvider authorization;
|
||||
protected final RealmAuth auth;
|
||||
|
||||
public PolicyResourceService(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) {
|
||||
this.policy = policy;
|
||||
this.resourceServer = resourceServer;
|
||||
this.authorization = authorization;
|
||||
this.auth = auth;
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Consumes("application/json")
|
||||
@Produces("application/json")
|
||||
@NoCache
|
||||
public Response update(String payload) {
|
||||
this.auth.requireManage();
|
||||
|
||||
AbstractPolicyRepresentation representation = doCreateRepresentation(payload);
|
||||
|
||||
if (policy == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
representation.setId(policy.getId());
|
||||
|
||||
RepresentationToModel.toModel(representation, authorization, policy);
|
||||
|
||||
return Response.status(Status.CREATED).build();
|
||||
}
|
||||
|
||||
@DELETE
|
||||
public Response delete() {
|
||||
this.auth.requireManage();
|
||||
|
||||
if (policy == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
PolicyStore policyStore = storeFactory.getPolicyStore();
|
||||
PolicyProviderFactory resource = getProviderFactory(policy.getType());
|
||||
|
||||
resource.onRemove(policy, authorization);
|
||||
|
||||
policyStore.delete(policy.getId());
|
||||
|
||||
return Response.noContent().build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
@NoCache
|
||||
public Response findById() {
|
||||
this.auth.requireView();
|
||||
|
||||
if (policy == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
return Response.ok(toRepresentation(policy, authorization)).build();
|
||||
}
|
||||
|
||||
protected AbstractPolicyRepresentation toRepresentation(Policy policy, AuthorizationProvider authorization) {
|
||||
return ModelToRepresentation.toRepresentation(policy, PolicyRepresentation.class, authorization);
|
||||
}
|
||||
|
||||
@Path("/dependentPolicies")
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
@NoCache
|
||||
public Response getDependentPolicies() {
|
||||
this.auth.requireView();
|
||||
|
||||
if (policy == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
List<Policy> policies = authorization.getStoreFactory().getPolicyStore().findDependentPolicies(policy.getId(), resourceServer.getId());
|
||||
|
||||
return Response.ok(policies.stream().map(policy -> {
|
||||
PolicyRepresentation representation1 = new PolicyRepresentation();
|
||||
|
||||
representation1.setId(policy.getId());
|
||||
representation1.setName(policy.getName());
|
||||
representation1.setType(policy.getType());
|
||||
|
||||
return representation1;
|
||||
}).collect(Collectors.toList())).build();
|
||||
}
|
||||
|
||||
@Path("/scopes")
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
@NoCache
|
||||
public Response getScopes() {
|
||||
this.auth.requireView();
|
||||
|
||||
if (policy == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
return Response.ok(policy.getScopes().stream().map(scope -> {
|
||||
ScopeRepresentation representation = new ScopeRepresentation();
|
||||
|
||||
representation.setId(scope.getId());
|
||||
representation.setName(scope.getName());
|
||||
|
||||
return representation;
|
||||
}).collect(Collectors.toList())).build();
|
||||
}
|
||||
|
||||
@Path("/resources")
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
@NoCache
|
||||
public Response getResources() {
|
||||
this.auth.requireView();
|
||||
|
||||
if (policy == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
return Response.ok(policy.getResources().stream().map(resource -> {
|
||||
ResourceRepresentation representation = new ResourceRepresentation();
|
||||
|
||||
representation.setId(resource.getId());
|
||||
representation.setName(resource.getName());
|
||||
|
||||
return representation;
|
||||
}).collect(Collectors.toList())).build();
|
||||
}
|
||||
|
||||
@Path("/associatedPolicies")
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
@NoCache
|
||||
public Response getAssociatedPolicies() {
|
||||
this.auth.requireView();
|
||||
|
||||
if (policy == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
return Response.ok(policy.getAssociatedPolicies().stream().map(policy -> {
|
||||
PolicyRepresentation representation1 = new PolicyRepresentation();
|
||||
|
||||
representation1.setId(policy.getId());
|
||||
representation1.setName(policy.getName());
|
||||
representation1.setType(policy.getType());
|
||||
|
||||
return representation1;
|
||||
}).collect(Collectors.toList())).build();
|
||||
}
|
||||
|
||||
protected AbstractPolicyRepresentation doCreateRepresentation(String payload) {
|
||||
PolicyRepresentation representation;
|
||||
|
||||
try {
|
||||
representation = JsonSerialization.readValue(payload, PolicyRepresentation.class);
|
||||
} catch (IOException cause) {
|
||||
throw new RuntimeException("Failed to deserialize representation", cause);
|
||||
}
|
||||
|
||||
return representation;
|
||||
}
|
||||
|
||||
private PolicyProviderFactory getProviderFactory(String policyType) {
|
||||
return authorization.getProviderFactory(policyType);
|
||||
}
|
||||
|
||||
protected Policy getPolicy() {
|
||||
return policy;
|
||||
}
|
||||
}
|
|
@ -17,9 +17,7 @@
|
|||
*/
|
||||
package org.keycloak.authorization.admin;
|
||||
|
||||
import static org.keycloak.models.utils.ModelToRepresentation.toRepresentation;
|
||||
import static org.keycloak.models.utils.RepresentationToModel.toModel;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -29,14 +27,13 @@ import java.util.Map;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
|
@ -48,24 +45,24 @@ import org.keycloak.authorization.model.ResourceServer;
|
|||
import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
|
||||
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
|
||||
import org.keycloak.authorization.store.PolicyStore;
|
||||
import org.keycloak.authorization.store.ResourceStore;
|
||||
import org.keycloak.authorization.store.ScopeStore;
|
||||
import org.keycloak.authorization.store.StoreFactory;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.PolicyProviderRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
|
||||
import org.keycloak.services.ErrorResponseException;
|
||||
import org.keycloak.services.resources.admin.RealmAuth;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class PolicyService {
|
||||
|
||||
private final ResourceServer resourceServer;
|
||||
private final AuthorizationProvider authorization;
|
||||
private final RealmAuth auth;
|
||||
protected final ResourceServer resourceServer;
|
||||
protected final AuthorizationProvider authorization;
|
||||
protected final RealmAuth auth;
|
||||
|
||||
public PolicyService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) {
|
||||
this.resourceServer = resourceServer;
|
||||
|
@ -73,210 +70,66 @@ public class PolicyService {
|
|||
this.auth = auth;
|
||||
}
|
||||
|
||||
@POST
|
||||
@Consumes("application/json")
|
||||
@Produces("application/json")
|
||||
@NoCache
|
||||
public Response create(PolicyRepresentation representation) {
|
||||
this.auth.requireManage();
|
||||
Policy policy = toModel(representation, this.resourceServer, authorization);
|
||||
PolicyProviderAdminService resource = getPolicyProviderAdminResource(policy.getType(), authorization);
|
||||
@Path("{type}")
|
||||
public Object getResource(@PathParam("type") String type) {
|
||||
PolicyProviderFactory providerFactory = getPolicyProviderFactory(type);
|
||||
|
||||
if (resource != null) {
|
||||
try {
|
||||
resource.onCreate(policy);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (providerFactory != null) {
|
||||
return new PolicyTypeService(type, resourceServer, authorization, auth);
|
||||
}
|
||||
|
||||
Policy policy = authorization.getStoreFactory().getPolicyStore().findById(type, resourceServer.getId());
|
||||
|
||||
return doCreatePolicyResource(policy);
|
||||
}
|
||||
|
||||
protected Object doCreatePolicyResource(Policy policy) {
|
||||
return new PolicyResourceService(policy, resourceServer, authorization, auth);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public Response create(String payload) {
|
||||
this.auth.requireManage();
|
||||
|
||||
AbstractPolicyRepresentation representation = doCreateRepresentation(payload);
|
||||
Policy policy = create(representation);
|
||||
|
||||
representation.setId(policy.getId());
|
||||
|
||||
return Response.status(Status.CREATED).entity(representation).build();
|
||||
}
|
||||
|
||||
@Path("{id}")
|
||||
@PUT
|
||||
@Consumes("application/json")
|
||||
@Produces("application/json")
|
||||
@NoCache
|
||||
public Response update(@PathParam("id") String id, PolicyRepresentation representation) {
|
||||
this.auth.requireManage();
|
||||
representation.setId(id);
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
Policy policy = storeFactory.getPolicyStore().findById(representation.getId(), resourceServer.getId());
|
||||
protected AbstractPolicyRepresentation doCreateRepresentation(String payload) {
|
||||
PolicyRepresentation representation;
|
||||
|
||||
if (policy == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
try {
|
||||
representation = JsonSerialization.readValue(payload, PolicyRepresentation.class);
|
||||
} catch (IOException cause) {
|
||||
throw new RuntimeException("Failed to deserialize representation", cause);
|
||||
}
|
||||
|
||||
policy = toModel(representation, resourceServer, authorization);
|
||||
|
||||
PolicyProviderAdminService resource = getPolicyProviderAdminResource(policy.getType(), authorization);
|
||||
|
||||
if (resource != null) {
|
||||
try {
|
||||
resource.onUpdate(policy);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
return Response.status(Status.CREATED).build();
|
||||
return representation;
|
||||
}
|
||||
|
||||
@Path("{id}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("id") String id) {
|
||||
this.auth.requireManage();
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
PolicyStore policyStore = storeFactory.getPolicyStore();
|
||||
Policy policy = policyStore.findById(id, resourceServer.getId());
|
||||
public Policy create(AbstractPolicyRepresentation representation) {
|
||||
PolicyStore policyStore = authorization.getStoreFactory().getPolicyStore();
|
||||
Policy existing = policyStore.findByName(representation.getName(), resourceServer.getId());
|
||||
|
||||
if (policy == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
if (existing != null) {
|
||||
throw new ErrorResponseException("Policy with name [" + representation.getName() + "] already exists", "Conflicting policy", Status.CONFLICT);
|
||||
}
|
||||
|
||||
PolicyProviderAdminService resource = getPolicyProviderAdminResource(policy.getType(), authorization);
|
||||
|
||||
if (resource != null) {
|
||||
try {
|
||||
resource.onRemove(policy);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
policyStore.findDependentPolicies(id, resourceServer.getId()).forEach(dependentPolicy -> {
|
||||
if (dependentPolicy.getAssociatedPolicies().size() == 1) {
|
||||
policyStore.delete(dependentPolicy.getId());
|
||||
} else {
|
||||
dependentPolicy.removeAssociatedPolicy(policy);
|
||||
}
|
||||
});
|
||||
|
||||
policyStore.delete(policy.getId());
|
||||
|
||||
return Response.noContent().build();
|
||||
}
|
||||
|
||||
@Path("{id}")
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
@NoCache
|
||||
public Response findById(@PathParam("id") String id) {
|
||||
this.auth.requireView();
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
Policy model = storeFactory.getPolicyStore().findById(id, resourceServer.getId());
|
||||
|
||||
if (model == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
return Response.ok(toRepresentation(model)).build();
|
||||
}
|
||||
|
||||
@Path("{id}/dependentPolicies")
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
@NoCache
|
||||
public Response getDependentPolicies(@PathParam("id") String id) {
|
||||
this.auth.requireView();
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
Policy model = storeFactory.getPolicyStore().findById(id, resourceServer.getId());
|
||||
|
||||
if (model == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
List<Policy> policies = authorization.getStoreFactory().getPolicyStore().findDependentPolicies(model.getId(), resourceServer.getId());
|
||||
|
||||
return Response.ok(policies.stream().map(policy -> {
|
||||
PolicyRepresentation representation1 = new PolicyRepresentation();
|
||||
|
||||
representation1.setId(policy.getId());
|
||||
representation1.setName(policy.getName());
|
||||
representation1.setType(policy.getType());
|
||||
|
||||
return representation1;
|
||||
}).collect(Collectors.toList())).build();
|
||||
}
|
||||
|
||||
@Path("{id}/scopes")
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
@NoCache
|
||||
public Response getScopes(@PathParam("id") String id) {
|
||||
this.auth.requireView();
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
Policy model = storeFactory.getPolicyStore().findById(id, resourceServer.getId());
|
||||
|
||||
if (model == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
return Response.ok(model.getScopes().stream().map(scope -> {
|
||||
ScopeRepresentation representation = new ScopeRepresentation();
|
||||
|
||||
representation.setId(scope.getId());
|
||||
representation.setName(scope.getName());
|
||||
|
||||
return representation;
|
||||
}).collect(Collectors.toList())).build();
|
||||
}
|
||||
|
||||
@Path("{id}/resources")
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
@NoCache
|
||||
public Response getResources(@PathParam("id") String id) {
|
||||
this.auth.requireView();
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
Policy model = storeFactory.getPolicyStore().findById(id, resourceServer.getId());
|
||||
|
||||
if (model == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
return Response.ok(model.getResources().stream().map(resource -> {
|
||||
ResourceRepresentation representation = new ResourceRepresentation();
|
||||
|
||||
representation.setId(resource.getId());
|
||||
representation.setName(resource.getName());
|
||||
|
||||
return representation;
|
||||
}).collect(Collectors.toList())).build();
|
||||
}
|
||||
|
||||
@Path("{id}/associatedPolicies")
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
@NoCache
|
||||
public Response getAssociatedPolicies(@PathParam("id") String id) {
|
||||
this.auth.requireView();
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
Policy model = storeFactory.getPolicyStore().findById(id, resourceServer.getId());
|
||||
|
||||
if (model == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
return Response.ok(model.getAssociatedPolicies().stream().map(policy -> {
|
||||
PolicyRepresentation representation1 = new PolicyRepresentation();
|
||||
|
||||
representation1.setId(policy.getId());
|
||||
representation1.setName(policy.getName());
|
||||
representation1.setType(policy.getType());
|
||||
|
||||
return representation1;
|
||||
}).collect(Collectors.toList())).build();
|
||||
return policyStore.create(representation, resourceServer);
|
||||
}
|
||||
|
||||
@Path("/search")
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public Response find(@QueryParam("name") String name) {
|
||||
public Response findByName(@QueryParam("name") String name) {
|
||||
this.auth.requireView();
|
||||
StoreFactory storeFactory = authorization.getStoreFactory();
|
||||
|
||||
|
@ -290,11 +143,11 @@ public class PolicyService {
|
|||
return Response.status(Status.OK).build();
|
||||
}
|
||||
|
||||
return Response.ok(toRepresentation(model)).build();
|
||||
return Response.ok(toRepresentation(model, authorization)).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public Response findAll(@QueryParam("policyId") String id,
|
||||
@QueryParam("name") String name,
|
||||
|
@ -363,15 +216,24 @@ public class PolicyService {
|
|||
}
|
||||
|
||||
return Response.ok(
|
||||
policyStore.findByResourceServer(search, resourceServer.getId(), firstResult != null ? firstResult : -1, maxResult != null ? maxResult : Constants.DEFAULT_MAX_RESULTS).stream()
|
||||
.map(policy -> toRepresentation(policy))
|
||||
.collect(Collectors.toList()))
|
||||
doSearch(firstResult, maxResult, search))
|
||||
.build();
|
||||
}
|
||||
|
||||
protected AbstractPolicyRepresentation toRepresentation(Policy model, AuthorizationProvider authorization) {
|
||||
return ModelToRepresentation.toRepresentation(model, PolicyRepresentation.class, authorization);
|
||||
}
|
||||
|
||||
protected List<Object> doSearch(Integer firstResult, Integer maxResult, Map<String, String[]> filters) {
|
||||
PolicyStore policyStore = authorization.getStoreFactory().getPolicyStore();
|
||||
return policyStore.findByResourceServer(filters, resourceServer.getId(), firstResult != null ? firstResult : -1, maxResult != null ? maxResult : Constants.DEFAULT_MAX_RESULTS).stream()
|
||||
.map(policy -> toRepresentation(policy, authorization))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Path("providers")
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public Response findPolicyProviders() {
|
||||
this.auth.requireView();
|
||||
|
@ -400,20 +262,12 @@ public class PolicyService {
|
|||
return resource;
|
||||
}
|
||||
|
||||
@Path("{policyType}")
|
||||
public Object getPolicyTypeResource(@PathParam("policyType") String policyType) {
|
||||
this.auth.requireView();
|
||||
return getPolicyProviderAdminResource(policyType, this.authorization);
|
||||
protected PolicyProviderAdminService getPolicyProviderAdminResource(String policyType) {
|
||||
return getPolicyProviderFactory(policyType).getAdminResource(resourceServer, authorization);
|
||||
}
|
||||
|
||||
private PolicyProviderAdminService getPolicyProviderAdminResource(String policyType, AuthorizationProvider authorization) {
|
||||
PolicyProviderFactory providerFactory = authorization.getProviderFactory(policyType);
|
||||
|
||||
if (providerFactory != null) {
|
||||
return providerFactory.getAdminResource(this.resourceServer);
|
||||
}
|
||||
|
||||
return null;
|
||||
protected PolicyProviderFactory getPolicyProviderFactory(String policyType) {
|
||||
return authorization.getProviderFactory(policyType);
|
||||
}
|
||||
|
||||
private void findAssociatedPolicies(Policy policy, List<Policy> policies) {
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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.admin;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
||||
import org.keycloak.services.resources.admin.RealmAuth;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class PolicyTypeResourceService extends PolicyResourceService {
|
||||
|
||||
public PolicyTypeResourceService(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) {
|
||||
super(policy, resourceServer, authorization, auth);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractPolicyRepresentation doCreateRepresentation(String payload) {
|
||||
String type = getPolicy().getType();
|
||||
Class<? extends AbstractPolicyRepresentation> representationType = authorization.getProviderFactory(type).getRepresentationType();
|
||||
|
||||
if (representationType == null) {
|
||||
throw new RuntimeException("Policy provider for type [" + type + "] returned a null representation type.");
|
||||
}
|
||||
|
||||
AbstractPolicyRepresentation representation;
|
||||
|
||||
try {
|
||||
representation = JsonSerialization.readValue(payload, representationType);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to deserialize JSON using policy provider for type [" + type + "].", e);
|
||||
}
|
||||
|
||||
representation.setType(type);
|
||||
|
||||
return representation;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractPolicyRepresentation toRepresentation(Policy policy, AuthorizationProvider authorization) {
|
||||
PolicyProviderFactory providerFactory = authorization.getProviderFactory(policy.getType());
|
||||
return ModelToRepresentation.toRepresentation(policy, providerFactory.getRepresentationType(), authorization);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* 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.admin;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.ws.rs.Path;
|
||||
|
||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.model.Policy;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
|
||||
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
||||
import org.keycloak.services.resources.admin.RealmAuth;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class PolicyTypeService extends PolicyService {
|
||||
|
||||
private final String type;
|
||||
|
||||
PolicyTypeService(String type, ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) {
|
||||
super(resourceServer, authorization, auth);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Path("/provider")
|
||||
public Object getPolicyAdminResourceProvider() {
|
||||
PolicyProviderAdminService resource = getPolicyProviderAdminResource(type);
|
||||
|
||||
if (resource == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ResteasyProviderFactory.getInstance().injectProperties(resource);
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doCreatePolicyResource(Policy policy) {
|
||||
return new PolicyTypeResourceService(policy, resourceServer,authorization, auth);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractPolicyRepresentation doCreateRepresentation(String payload) {
|
||||
PolicyProviderFactory provider = getPolicyProviderFactory(type);
|
||||
Class<? extends AbstractPolicyRepresentation> representationType = provider.getRepresentationType();
|
||||
|
||||
if (representationType == null) {
|
||||
throw new RuntimeException("Policy provider for type [" + type + "] returned a null representation type.");
|
||||
}
|
||||
|
||||
AbstractPolicyRepresentation representation;
|
||||
|
||||
try {
|
||||
representation = JsonSerialization.readValue(payload, representationType);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to deserialize JSON using policy provider for type [" + type + "].", e);
|
||||
}
|
||||
|
||||
representation.setType(type);
|
||||
|
||||
return representation;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractPolicyRepresentation toRepresentation(Policy policy, AuthorizationProvider authorization) {
|
||||
PolicyProviderFactory providerFactory = authorization.getProviderFactory(policy.getType());
|
||||
return ModelToRepresentation.toRepresentation(policy, providerFactory.getRepresentationType(), authorization);
|
||||
}
|
||||
}
|
|
@ -17,6 +17,22 @@
|
|||
*/
|
||||
package org.keycloak.authorization.admin;
|
||||
|
||||
import static org.keycloak.models.utils.ModelToRepresentation.toRepresentation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.keycloak.authorization.AuthorizationProvider;
|
||||
import org.keycloak.authorization.model.ResourceServer;
|
||||
|
@ -34,25 +50,11 @@ import org.keycloak.models.utils.RepresentationToModel;
|
|||
import org.keycloak.representations.idm.authorization.DecisionStrategy;
|
||||
import org.keycloak.representations.idm.authorization.Logic;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
|
||||
import org.keycloak.services.resources.admin.RealmAuth;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static org.keycloak.models.utils.ModelToRepresentation.toRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
|
@ -171,22 +173,26 @@ public class ResourceServerService {
|
|||
return resource;
|
||||
}
|
||||
|
||||
@Path("/permission")
|
||||
public Object getPermissionTypeResource() {
|
||||
this.auth.requireView();
|
||||
PermissionService resource = new PermissionService(this.resourceServer, this.authorization, this.auth);
|
||||
|
||||
ResteasyProviderFactory.getInstance().injectProperties(resource);
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
private void createDefaultPermission(ResourceRepresentation resource, PolicyRepresentation policy) {
|
||||
PolicyRepresentation defaultPermission = new PolicyRepresentation();
|
||||
ResourcePermissionRepresentation defaultPermission = new ResourcePermissionRepresentation();
|
||||
|
||||
defaultPermission.setName("Default Permission");
|
||||
defaultPermission.setType("resource");
|
||||
defaultPermission.setDescription("A permission that applies to the default resource type");
|
||||
defaultPermission.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
|
||||
defaultPermission.setLogic(Logic.POSITIVE);
|
||||
|
||||
HashMap<String, String> defaultPermissionConfig = new HashMap<>();
|
||||
|
||||
defaultPermissionConfig.put("default", "true");
|
||||
defaultPermissionConfig.put("defaultResourceType", resource.getType());
|
||||
defaultPermissionConfig.put("applyPolicies", "[\"" + policy.getName() + "\"]");
|
||||
|
||||
defaultPermission.setConfig(defaultPermissionConfig);
|
||||
defaultPermission.setResourceType(resource.getType());
|
||||
defaultPermission.addPolicy(policy.getName());
|
||||
|
||||
getPolicyResource().create(defaultPermission);
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue