[KEYCLOAK-4769] - Policy enforcer path matching tests
This commit is contained in:
parent
b72166ebf1
commit
80a80512ea
19 changed files with 1021 additions and 33 deletions
|
@ -49,7 +49,6 @@ class PathMatcher {
|
||||||
|
|
||||||
PathConfig matchingAnyPath = null;
|
PathConfig matchingAnyPath = null;
|
||||||
PathConfig matchingAnySuffixPath = null;
|
PathConfig matchingAnySuffixPath = null;
|
||||||
PathConfig matchingPath = null;
|
|
||||||
|
|
||||||
for (PathConfig entry : paths.values()) {
|
for (PathConfig entry : paths.values()) {
|
||||||
String expectedUri = entry.getPath();
|
String expectedUri = entry.getPath();
|
||||||
|
@ -132,56 +131,77 @@ class PathMatcher {
|
||||||
return targetUri.startsWith(expectedUri.substring(0, expectedUri.length() - 2));
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String buildUriFromTemplate(String expectedUri, String targetUri) {
|
public String buildUriFromTemplate(String expectedUri, String targetUri) {
|
||||||
int patternStartIndex = expectedUri.indexOf("{");
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
char[] expectedUriChars = expectedUri.toCharArray();
|
char[] expectedUriChars = expectedUri.toCharArray();
|
||||||
char[] matchingUri = Arrays.copyOfRange(expectedUriChars, 0, patternStartIndex);
|
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))) {
|
if (Arrays.equals(matchingUri, Arrays.copyOf(targetUri.toCharArray(), matchingUri.length))) {
|
||||||
int matchingLastIndex = matchingUri.length;
|
matchingUri = Arrays.copyOf(matchingUri, targetUri.length());
|
||||||
matchingUri = Arrays.copyOf(matchingUri, targetUri.length()); // +1 so we can add a slash at the end
|
int paramIndex = 0;
|
||||||
int targetPatternStartIndex = patternStartIndex;
|
|
||||||
|
|
||||||
while (patternStartIndex != -1) {
|
for (int i = patternStartIndex; i < expectedUriChars.length; i++) {
|
||||||
int parameterStartIndex = -1;
|
if (matchingUriLastIndex >= matchingUri.length) {
|
||||||
|
|
||||||
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) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((targetPatternStartIndex == 0 || targetPatternStartIndex == targetUri.length()) && parameterStartIndex != -1) {
|
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;
|
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);
|
return String.valueOf(matchingUri);
|
||||||
|
|
|
@ -196,10 +196,12 @@ public class PolicyEnforcerConfig {
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public boolean hasPattern() {
|
public boolean hasPattern() {
|
||||||
return getPath().indexOf("{") != -1;
|
return getPath().indexOf("{") != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public boolean isInstance() {
|
public boolean isInstance() {
|
||||||
return this.parentConfig != null;
|
return this.parentConfig != null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,13 +17,16 @@
|
||||||
package org.keycloak.admin.client.resource;
|
package org.keycloak.admin.client.resource;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.POST;
|
import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||||
import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
|
import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,4 +42,9 @@ public interface ResourcePermissionsResource {
|
||||||
@Path("{id}")
|
@Path("{id}")
|
||||||
ResourcePermissionResource findById(@PathParam("id") String id);
|
ResourcePermissionResource findById(@PathParam("id") String id);
|
||||||
|
|
||||||
|
@Path("/search")
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@NoCache
|
||||||
|
ResourcePermissionRepresentation findByName(@QueryParam("name") String name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,13 +17,16 @@
|
||||||
package org.keycloak.admin.client.resource;
|
package org.keycloak.admin.client.resource;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.POST;
|
import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||||
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
|
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,4 +42,9 @@ public interface RolePoliciesResource {
|
||||||
@Path("{id}")
|
@Path("{id}")
|
||||||
RolePolicyResource findById(@PathParam("id") String id);
|
RolePolicyResource findById(@PathParam("id") String id);
|
||||||
|
|
||||||
|
@Path("/search")
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@NoCache
|
||||||
|
RolePolicyRepresentation findByName(@QueryParam("name") String name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,13 +17,16 @@
|
||||||
package org.keycloak.admin.client.resource;
|
package org.keycloak.admin.client.resource;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.POST;
|
import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||||
import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation;
|
import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,4 +41,10 @@ public interface ScopePermissionsResource {
|
||||||
|
|
||||||
@Path("{id}")
|
@Path("{id}")
|
||||||
ScopePermissionResource findById(@PathParam("id") String id);
|
ScopePermissionResource findById(@PathParam("id") String id);
|
||||||
|
|
||||||
|
@Path("/search")
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@NoCache
|
||||||
|
ScopePermissionRepresentation findByName(@QueryParam("name") String name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,13 +17,16 @@
|
||||||
package org.keycloak.admin.client.resource;
|
package org.keycloak.admin.client.resource;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.POST;
|
import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||||
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
|
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,4 +42,9 @@ public interface UserPoliciesResource {
|
||||||
@Path("{id}")
|
@Path("{id}")
|
||||||
UserPolicyResource findById(@PathParam("id") String id);
|
UserPolicyResource findById(@PathParam("id") String id);
|
||||||
|
|
||||||
|
@Path("/search")
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@NoCache
|
||||||
|
UserPolicyRepresentation findByName(@QueryParam("name") String name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,7 @@ public class KeycloakOnUndertow implements DeployableContainer<KeycloakOnUnderto
|
||||||
FilterInfo filter = Servlets.filter("SessionFilter", KeycloakSessionServletFilter.class);
|
FilterInfo filter = Servlets.filter("SessionFilter", KeycloakSessionServletFilter.class);
|
||||||
di.addFilter(filter);
|
di.addFilter(filter);
|
||||||
di.addFilterUrlMapping("SessionFilter", "/*", DispatcherType.REQUEST);
|
di.addFilterUrlMapping("SessionFilter", "/*", DispatcherType.REQUEST);
|
||||||
|
filter.setAsyncSupported(true);
|
||||||
|
|
||||||
return di;
|
return di;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
<module>photoz</module>
|
<module>photoz</module>
|
||||||
<module>hello-world-authz-service</module>
|
<module>hello-world-authz-service</module>
|
||||||
<module>servlet-authz</module>
|
<module>servlet-authz</module>
|
||||||
|
<module>servlet-policy-enforcer</module>
|
||||||
<module>servlets</module>
|
<module>servlets</module>
|
||||||
<module>app-profile-jee</module>
|
<module>app-profile-jee</module>
|
||||||
<module>cors</module>
|
<module>cors</module>
|
||||||
|
|
53
testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/pom.xml
Executable file
53
testsuite/integration-arquillian/test-apps/servlet-policy-enforcer/pom.xml
Executable file
|
@ -0,0 +1,53 @@
|
||||||
|
<?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.
|
||||||
|
~
|
||||||
|
-->
|
||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.keycloak.testsuite</groupId>
|
||||||
|
<artifactId>integration-arquillian-test-apps</artifactId>
|
||||||
|
<version>3.1.0.CR1-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>servlet-policy-enforcer</artifactId>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
|
||||||
|
<name>Keycloak Authz: Simple Servlet App with Policy Enforcer</name>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.jboss.as.plugins</groupId>
|
||||||
|
<artifactId>jboss-as-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skip>false</skip>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.wildfly.plugins</groupId>
|
||||||
|
<artifactId>wildfly-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skip>false</skip>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
|
@ -0,0 +1,265 @@
|
||||||
|
{
|
||||||
|
"realm": "servlet-policy-enforcer-authz",
|
||||||
|
"enabled": true,
|
||||||
|
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
|
||||||
|
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||||
|
"requiredCredentials": [
|
||||||
|
"password"
|
||||||
|
],
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"username": "alice",
|
||||||
|
"enabled": true,
|
||||||
|
"credentials": [
|
||||||
|
{
|
||||||
|
"type": "password",
|
||||||
|
"value": "alice"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"realmRoles": [
|
||||||
|
"uma_authorization"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"username": "jdoe",
|
||||||
|
"enabled": true,
|
||||||
|
"credentials": [
|
||||||
|
{
|
||||||
|
"type": "password",
|
||||||
|
"value": "jdoe"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"realmRoles": [
|
||||||
|
"uma_authorization"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"username": "service-account-servlet-policy-enforcer",
|
||||||
|
"enabled": true,
|
||||||
|
"serviceAccountClientId": "servlet-policy-enforcer",
|
||||||
|
"clientRoles": {
|
||||||
|
"servlet-policy-enforcer": [
|
||||||
|
"uma_protection"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"clients": [
|
||||||
|
{
|
||||||
|
"clientId": "servlet-policy-enforcer",
|
||||||
|
"secret": "secret",
|
||||||
|
"authorizationServicesEnabled": true,
|
||||||
|
"enabled": true,
|
||||||
|
"redirectUris": [
|
||||||
|
"/servlet-policy-enforcer/*"
|
||||||
|
],
|
||||||
|
"baseUrl": "/servlet-policy-enforcer",
|
||||||
|
"adminUrl": "/servlet-policy-enforcer",
|
||||||
|
"directAccessGrantsEnabled": true,
|
||||||
|
"authorizationSettings": {
|
||||||
|
"allowRemoteResourceManagement": false,
|
||||||
|
"policyEnforcementMode": "ENFORCING",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"name": "Welcome Resource",
|
||||||
|
"uri": "",
|
||||||
|
"typedScopes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 1",
|
||||||
|
"uri": "",
|
||||||
|
"typedScopes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 2",
|
||||||
|
"uri": "/resource/resource-a",
|
||||||
|
"typedScopes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 3",
|
||||||
|
"uri": "/resource/resource-b/test",
|
||||||
|
"typedScopes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 4",
|
||||||
|
"uri": "/resource-c",
|
||||||
|
"typedScopes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 5",
|
||||||
|
"uri": "/resource/d/resource-d",
|
||||||
|
"typedScopes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 6",
|
||||||
|
"uri": "",
|
||||||
|
"typedScopes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 7",
|
||||||
|
"uri": "",
|
||||||
|
"typedScopes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 8",
|
||||||
|
"typedScopes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 9",
|
||||||
|
"typedScopes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 10",
|
||||||
|
"typedScopes": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 11",
|
||||||
|
"typedScopes": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"policies": [
|
||||||
|
{
|
||||||
|
"name": "Default Policy",
|
||||||
|
"type": "js",
|
||||||
|
"logic": "POSITIVE",
|
||||||
|
"decisionStrategy": "AFFIRMATIVE",
|
||||||
|
"config": {
|
||||||
|
"code": "// by default, grants any permission associated with this policy\n$evaluation.grant();\n",
|
||||||
|
"applyPolicies": "[]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Deny Policy",
|
||||||
|
"type": "js",
|
||||||
|
"logic": "NEGATIVE",
|
||||||
|
"decisionStrategy": "UNANIMOUS",
|
||||||
|
"config": {
|
||||||
|
"code": "$evaluation.grant();"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 3 Permission",
|
||||||
|
"type": "resource",
|
||||||
|
"logic": "POSITIVE",
|
||||||
|
"decisionStrategy": "AFFIRMATIVE",
|
||||||
|
"config": {
|
||||||
|
"resources": "[\"Pattern 3\"]",
|
||||||
|
"applyPolicies": "[\"Default Policy\"]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 2 Permission",
|
||||||
|
"type": "resource",
|
||||||
|
"logic": "POSITIVE",
|
||||||
|
"decisionStrategy": "AFFIRMATIVE",
|
||||||
|
"config": {
|
||||||
|
"resources": "[\"Pattern 2\"]",
|
||||||
|
"applyPolicies": "[\"Default Policy\"]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 4 Permission",
|
||||||
|
"type": "resource",
|
||||||
|
"logic": "POSITIVE",
|
||||||
|
"decisionStrategy": "UNANIMOUS",
|
||||||
|
"config": {
|
||||||
|
"resources": "[\"Pattern 4\"]",
|
||||||
|
"applyPolicies": "[\"Default Policy\"]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 5 Permission",
|
||||||
|
"type": "resource",
|
||||||
|
"logic": "POSITIVE",
|
||||||
|
"decisionStrategy": "UNANIMOUS",
|
||||||
|
"config": {
|
||||||
|
"resources": "[\"Pattern 5\"]",
|
||||||
|
"applyPolicies": "[\"Default Policy\"]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 7 Permission",
|
||||||
|
"type": "resource",
|
||||||
|
"logic": "POSITIVE",
|
||||||
|
"decisionStrategy": "AFFIRMATIVE",
|
||||||
|
"config": {
|
||||||
|
"resources": "[\"Pattern 7\"]",
|
||||||
|
"applyPolicies": "[\"Default Policy\"]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 8 Permission",
|
||||||
|
"type": "resource",
|
||||||
|
"logic": "POSITIVE",
|
||||||
|
"decisionStrategy": "UNANIMOUS",
|
||||||
|
"config": {
|
||||||
|
"resources": "[\"Pattern 8\"]",
|
||||||
|
"applyPolicies": "[\"Default Policy\"]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 9 Permission",
|
||||||
|
"type": "resource",
|
||||||
|
"logic": "POSITIVE",
|
||||||
|
"decisionStrategy": "UNANIMOUS",
|
||||||
|
"config": {
|
||||||
|
"resources": "[\"Pattern 9\"]",
|
||||||
|
"applyPolicies": "[\"Default Policy\"]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 6 Permission",
|
||||||
|
"type": "resource",
|
||||||
|
"logic": "POSITIVE",
|
||||||
|
"decisionStrategy": "AFFIRMATIVE",
|
||||||
|
"config": {
|
||||||
|
"resources": "[\"Pattern 6\"]",
|
||||||
|
"applyPolicies": "[\"Default Policy\"]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Welcome Resource Permission",
|
||||||
|
"type": "resource",
|
||||||
|
"logic": "POSITIVE",
|
||||||
|
"decisionStrategy": "UNANIMOUS",
|
||||||
|
"config": {
|
||||||
|
"resources": "[\"Welcome Resource\"]",
|
||||||
|
"applyPolicies": "[\"Default Policy\"]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 1 Permission",
|
||||||
|
"type": "resource",
|
||||||
|
"logic": "POSITIVE",
|
||||||
|
"decisionStrategy": "UNANIMOUS",
|
||||||
|
"config": {
|
||||||
|
"resources": "[\"Pattern 1\"]",
|
||||||
|
"applyPolicies": "[\"Default Policy\"]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 10 Permission",
|
||||||
|
"type": "resource",
|
||||||
|
"logic": "POSITIVE",
|
||||||
|
"decisionStrategy": "UNANIMOUS",
|
||||||
|
"config": {
|
||||||
|
"resources": "[\"Pattern 10\"]",
|
||||||
|
"applyPolicies": "[\"Default Policy\"]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 11 Permission",
|
||||||
|
"type": "resource",
|
||||||
|
"logic": "POSITIVE",
|
||||||
|
"decisionStrategy": "UNANIMOUS",
|
||||||
|
"config": {
|
||||||
|
"resources": "[\"Pattern 11\"]",
|
||||||
|
"applyPolicies": "[\"Default Policy\"]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"scopes": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
{
|
||||||
|
"realm": "servlet-policy-enforcer-authz",
|
||||||
|
"auth-server-url": "http://localhost:8180/auth",
|
||||||
|
"ssl-required": "external",
|
||||||
|
"resource": "servlet-policy-enforcer",
|
||||||
|
"credentials": {
|
||||||
|
"secret": "secret"
|
||||||
|
},
|
||||||
|
"policy-enforcer": {
|
||||||
|
"on-deny-redirect-to": "/servlet-policy-enforcer/denied.jsp",
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"name": "Welcome Resource",
|
||||||
|
"path": "/index.jsp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 1",
|
||||||
|
"path": "/resource/{pattern}/{sub-resource}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 2",
|
||||||
|
"path": "/{pattern}/resource-a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 3",
|
||||||
|
"path": "/{pattern}/resource-b"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 4",
|
||||||
|
"path": "/resource-c"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 5",
|
||||||
|
"path": "/resource/{pattern}/resource-d"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 6",
|
||||||
|
"path": "/resource/{pattern}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 7",
|
||||||
|
"path": "/resource/{pattern}/f/{resource}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 8",
|
||||||
|
"path": "/resource"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 9",
|
||||||
|
"path": "/file/*.suffix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 10",
|
||||||
|
"path": "/resource/{pattern}/i/{resource}/*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pattern 11",
|
||||||
|
"path": "/api/{version}/{resource}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?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.
|
||||||
|
~
|
||||||
|
-->
|
||||||
|
|
||||||
|
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
||||||
|
version="3.0">
|
||||||
|
|
||||||
|
<module-name>servlet-policy-enforcer</module-name>
|
||||||
|
|
||||||
|
<security-constraint>
|
||||||
|
<web-resource-collection>
|
||||||
|
<web-resource-name>All Resources</web-resource-name>
|
||||||
|
<url-pattern>/*</url-pattern>
|
||||||
|
</web-resource-collection>
|
||||||
|
<auth-constraint>
|
||||||
|
<role-name>uma_authorization</role-name>
|
||||||
|
</auth-constraint>
|
||||||
|
</security-constraint>
|
||||||
|
|
||||||
|
<login-config>
|
||||||
|
<auth-method>KEYCLOAK</auth-method>
|
||||||
|
<realm-name>servlet-policy-enforcer</realm-name>
|
||||||
|
</login-config>
|
||||||
|
|
||||||
|
<security-role>
|
||||||
|
<role-name>uma_authorization</role-name>
|
||||||
|
</security-role>
|
||||||
|
</web-app>
|
|
@ -0,0 +1,2 @@
|
||||||
|
<%@include file="logout-include.jsp"%>
|
||||||
|
<p>You can not access this resource</p>
|
|
@ -0,0 +1,2 @@
|
||||||
|
<%@include file="logout-include.jsp"%>
|
||||||
|
<p>Welcome</p>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<%@ page import="org.keycloak.common.util.KeycloakUriBuilder" %>
|
||||||
|
<%@ page import="org.keycloak.constants.ServiceUrlConstants" %>
|
||||||
|
<%
|
||||||
|
String scheme = request.getScheme();
|
||||||
|
String host = request.getServerName();
|
||||||
|
int port = request.getServerPort();
|
||||||
|
String contextPath = request.getContextPath();
|
||||||
|
String redirectUri = scheme + "://" + host + ":" + port + contextPath;
|
||||||
|
%>
|
||||||
|
<h2>Click here <a href="<%= KeycloakUriBuilder.fromUri("http://localhost:8180/auth").path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH)
|
||||||
|
.queryParam("redirect_uri", redirectUri).build("servlet-policy-enforcer-authz").toString()%>">Sign Out</a></h2>
|
|
@ -51,6 +51,14 @@
|
||||||
<exclude name="**/subsystem-config.xml"/>
|
<exclude name="**/subsystem-config.xml"/>
|
||||||
</fileset>
|
</fileset>
|
||||||
</copy>
|
</copy>
|
||||||
|
<copy todir="target/test-apps/servlet-policy-enforcer" overwrite="true">
|
||||||
|
<fileset dir="../servlet-policy-enforcer">
|
||||||
|
<exclude name="**/target/**"/>
|
||||||
|
<exclude name="**/*.iml"/>
|
||||||
|
<exclude name="**/*.unconfigured"/>
|
||||||
|
<exclude name="**/subsystem-config.xml"/>
|
||||||
|
</fileset>
|
||||||
|
</copy>
|
||||||
<copy todir="target/test-apps/cors" overwrite="true">
|
<copy todir="target/test-apps/cors" overwrite="true">
|
||||||
<fileset dir="../cors">
|
<fileset dir="../cors">
|
||||||
<exclude name="**/target/**"/>
|
<exclude name="**/target/**"/>
|
||||||
|
|
|
@ -0,0 +1,447 @@
|
||||||
|
/*
|
||||||
|
* 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.testsuite.adapter.example.authorization;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.keycloak.testsuite.util.IOUtil.loadRealm;
|
||||||
|
import static org.keycloak.testsuite.util.WaitUtils.pause;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.container.test.api.Deployer;
|
||||||
|
import org.jboss.arquillian.container.test.api.Deployment;
|
||||||
|
import org.jboss.arquillian.test.api.ArquillianResource;
|
||||||
|
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.admin.client.resource.AuthorizationResource;
|
||||||
|
import org.keycloak.admin.client.resource.ClientResource;
|
||||||
|
import org.keycloak.admin.client.resource.ClientsResource;
|
||||||
|
import org.keycloak.admin.client.resource.ResourcePermissionsResource;
|
||||||
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
|
||||||
|
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||||
|
import org.keycloak.testsuite.ProfileAssume;
|
||||||
|
import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
|
||||||
|
import org.keycloak.testsuite.util.WaitUtils;
|
||||||
|
import org.openqa.selenium.By;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
*/
|
||||||
|
public abstract class AbstractServletPolicyEnforcerTest extends AbstractExampleAdapterTest {
|
||||||
|
|
||||||
|
protected static final String REALM_NAME = "servlet-policy-enforcer-authz";
|
||||||
|
protected static final String RESOURCE_SERVER_ID = "servlet-policy-enforcer";
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void enabled() { ProfileAssume.assumePreview(); }
|
||||||
|
|
||||||
|
@ArquillianResource
|
||||||
|
private Deployer deployer;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
|
||||||
|
testRealms.add(
|
||||||
|
loadRealm(new File(TEST_APPS_HOME_DIR + "/servlet-policy-enforcer/servlet-policy-enforcer-authz-realm.json")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deployment(name = RESOURCE_SERVER_ID, managed = false)
|
||||||
|
public static WebArchive deployment() throws IOException {
|
||||||
|
return exampleDeployment(RESOURCE_SERVER_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPattern1() throws Exception {
|
||||||
|
performTests(() -> {
|
||||||
|
login("alice", "alice");
|
||||||
|
|
||||||
|
navigateTo("/resource/a/b");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 1 Permission", "Deny Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/resource/a/b");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 1 Permission", "Default Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/resource/a/b");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPattern2() throws Exception {
|
||||||
|
performTests(() -> {
|
||||||
|
login("alice", "alice");
|
||||||
|
|
||||||
|
navigateTo("/a/resource-a");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
navigateTo("/b/resource-a");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 2 Permission", "Deny Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/a/resource-a");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
navigateTo("/b/resource-a");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 2 Permission", "Default Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/b/resource-a");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPattern3() throws Exception {
|
||||||
|
performTests(() -> {
|
||||||
|
login("alice", "alice");
|
||||||
|
|
||||||
|
navigateTo("/a/resource-b");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
navigateTo("/b/resource-b");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 3 Permission", "Deny Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/a/resource-b");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
navigateTo("/b/resource-b");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 3 Permission", "Default Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/b/resource-b");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 2 Permission", "Default Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/b/resource-a");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 3 Permission", "Deny Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/a/resource-b");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
navigateTo("/b/resource-a");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPattern4() throws Exception {
|
||||||
|
performTests(() -> {
|
||||||
|
login("alice", "alice");
|
||||||
|
|
||||||
|
navigateTo("/resource-c");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 4 Permission", "Deny Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/resource-c");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 4 Permission", "Default Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/resource-c");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPattern5() throws Exception {
|
||||||
|
performTests(() -> {
|
||||||
|
login("alice", "alice");
|
||||||
|
|
||||||
|
navigateTo("/resource/a/resource-d");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
navigateTo("/resource/b/resource-d");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 5 Permission", "Deny Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/resource/a/resource-d");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
navigateTo("/resource/b/resource-d");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 5 Permission", "Default Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/resource/b/resource-d");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPattern6() throws Exception {
|
||||||
|
performTests(() -> {
|
||||||
|
login("alice", "alice");
|
||||||
|
|
||||||
|
navigateTo("/resource/a");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
navigateTo("/resource/b");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 6 Permission", "Deny Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/resource/a");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
navigateTo("/resource/b");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 6 Permission", "Default Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/resource/b");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPattern7() throws Exception {
|
||||||
|
performTests(() -> {
|
||||||
|
login("alice", "alice");
|
||||||
|
|
||||||
|
navigateTo("/resource/a/f/b");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
navigateTo("/resource/c/f/d");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 7 Permission", "Deny Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/resource/a/f/b");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
navigateTo("/resource/c/f/d");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 7 Permission", "Default Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/resource/c/f/d");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPattern8() throws Exception {
|
||||||
|
performTests(() -> {
|
||||||
|
login("alice", "alice");
|
||||||
|
|
||||||
|
navigateTo("/resource");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 8 Permission", "Deny Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/resource");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 8 Permission", "Default Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/resource");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPattern9() throws Exception {
|
||||||
|
performTests(() -> {
|
||||||
|
login("alice", "alice");
|
||||||
|
|
||||||
|
navigateTo("/file/*.suffix");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 9 Permission", "Deny Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/file/*.suffix");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 9 Permission", "Default Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/file/*.suffix");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPattern10() throws Exception {
|
||||||
|
performTests(() -> {
|
||||||
|
login("alice", "alice");
|
||||||
|
|
||||||
|
navigateTo("/resource/a/i/b/c/d/e");
|
||||||
|
navigateTo("/resource/a/i/b/c/");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 10 Permission", "Deny Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/resource/a/i/b/c/d/e");
|
||||||
|
navigateTo("/resource/a/i/b/c/d");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Pattern 10 Permission", "Default Policy");
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/resource/a/i/b/c/d");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPattern11UsingResourceInstancePermission() throws Exception {
|
||||||
|
performTests(() -> {
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo("/api/v1/resource-a");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
navigateTo("/api/v1/resource-b");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
ResourceRepresentation resource = new ResourceRepresentation("/api/v1/resource-c");
|
||||||
|
|
||||||
|
resource.setUri(resource.getName());
|
||||||
|
|
||||||
|
getAuthorizationResource().resources().create(resource);
|
||||||
|
|
||||||
|
createResourcePermission(resource.getName() + " permission", resource.getName(), "Default Policy");
|
||||||
|
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo(resource.getUri());
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies(resource.getName() + " permission", "Deny Policy");
|
||||||
|
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo(resource.getUri());
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
|
||||||
|
updatePermissionPolicies(resource.getName() + " permission", "Default Policy");
|
||||||
|
|
||||||
|
login("alice", "alice");
|
||||||
|
navigateTo(resource.getUri());
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
navigateTo("/api/v1");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
navigateTo("/api/v1/");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
navigateTo("/api");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
navigateTo("/api/");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void navigateTo(String path) {
|
||||||
|
this.driver.navigate().to(getResourceServerUrl() + path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performTests(ExceptionRunnable assertion) {
|
||||||
|
performTests(() -> {}, assertion);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performTests(ExceptionRunnable beforeDeploy, ExceptionRunnable assertion) {
|
||||||
|
try {
|
||||||
|
beforeDeploy.run();
|
||||||
|
deployer.deploy(RESOURCE_SERVER_ID);
|
||||||
|
assertion.run();
|
||||||
|
} catch (FileNotFoundException cause) {
|
||||||
|
throw new RuntimeException("Failed to import authorization settings", cause);
|
||||||
|
} catch (Exception cause) {
|
||||||
|
throw new RuntimeException("Error while executing tests", cause);
|
||||||
|
} finally {
|
||||||
|
deployer.undeploy(RESOURCE_SERVER_ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthorizationResource getAuthorizationResource() {
|
||||||
|
return getClientResource(RESOURCE_SERVER_ID).authorization();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClientResource getClientResource(String clientId) {
|
||||||
|
ClientsResource clients = this.realmsResouce().realm(REALM_NAME).clients();
|
||||||
|
ClientRepresentation resourceServer = clients.findByClientId(clientId).get(0);
|
||||||
|
return clients.get(resourceServer.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logOut() {
|
||||||
|
navigateTo();
|
||||||
|
By by = By.xpath("//a[text() = 'Sign Out']");
|
||||||
|
WaitUtils.waitUntilElement(by);
|
||||||
|
this.driver.findElement(by).click();
|
||||||
|
pause(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void login(String username, String password) {
|
||||||
|
try {
|
||||||
|
navigateTo();
|
||||||
|
if (this.driver.getCurrentUrl().startsWith(getResourceServerUrl().toString())) {
|
||||||
|
logOut();
|
||||||
|
navigateTo();
|
||||||
|
}
|
||||||
|
this.loginPage.form().login(username, password);
|
||||||
|
navigateTo();
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
} catch (Exception cause) {
|
||||||
|
throw new RuntimeException("Login failed", cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void navigateTo() {
|
||||||
|
this.driver.navigate().to(getResourceServerUrl());
|
||||||
|
WaitUtils.waitUntilElement(By.xpath("//p[text() = 'Welcome']"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean wasDenied() {
|
||||||
|
return this.driver.getPageSource().contains("You can not access this resource");
|
||||||
|
}
|
||||||
|
|
||||||
|
private URL getResourceServerUrl() {
|
||||||
|
try {
|
||||||
|
return new URL(this.appServerContextRootPage + "/" + RESOURCE_SERVER_ID);
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
throw new RuntimeException("Could not obtain resource server url.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePermissionPolicies(String permissionName, String... policyNames) {
|
||||||
|
ResourcePermissionsResource permissions = getAuthorizationResource().permissions().resource();
|
||||||
|
ResourcePermissionRepresentation permission = permissions.findByName(permissionName);
|
||||||
|
|
||||||
|
permission.addPolicy(policyNames);
|
||||||
|
|
||||||
|
permissions.findById(permission.getId()).update(permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createResourcePermission(String name, String resourceName, String... policyNames) {
|
||||||
|
ResourcePermissionRepresentation permission = new ResourcePermissionRepresentation();
|
||||||
|
|
||||||
|
permission.setName(name);
|
||||||
|
permission.addResource(resourceName);
|
||||||
|
permission.addPolicy(policyNames);
|
||||||
|
|
||||||
|
getAuthorizationResource().permissions().resource().create(permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface ExceptionRunnable {
|
||||||
|
void run() throws Exception;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* 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.testsuite.adapter.example.authorization;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.container.test.api.RunAsClient;
|
||||||
|
import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
*/
|
||||||
|
@RunAsClient
|
||||||
|
@AppServerContainer("app-server-wildfly")
|
||||||
|
//@AdapterLibsLocationProperty("adapter.libs.wildfly")
|
||||||
|
public class WildflyServletPolicyEnforcerAdapterTest extends AbstractServletPolicyEnforcerTest {
|
||||||
|
|
||||||
|
}
|
|
@ -350,6 +350,12 @@
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<type>war</type>
|
<type>war</type>
|
||||||
</artifactItem>
|
</artifactItem>
|
||||||
|
<artifactItem>
|
||||||
|
<groupId>org.keycloak.testsuite</groupId>
|
||||||
|
<artifactId>servlet-policy-enforcer</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<type>war</type>
|
||||||
|
</artifactItem>
|
||||||
<artifactItem>
|
<artifactItem>
|
||||||
<groupId>org.keycloak.testsuite</groupId>
|
<groupId>org.keycloak.testsuite</groupId>
|
||||||
<artifactId>integration-arquillian-test-apps-cors-angular-product</artifactId>
|
<artifactId>integration-arquillian-test-apps-cors-angular-product</artifactId>
|
||||||
|
|
Loading…
Reference in a new issue