Removing PHOTOZ client and related tests testing UI. Closes #19668
This commit is contained in:
parent
d9b95e0240
commit
eb77dcf014
42 changed files with 0 additions and 3581 deletions
|
@ -1,79 +0,0 @@
|
|||
{
|
||||
"realm": "photoz",
|
||||
"auth-server-url": "http://localhost:8180/auth",
|
||||
"ssl-required": "external",
|
||||
"resource": "photoz-restful-api",
|
||||
"bearer-only" : true,
|
||||
"credentials": {
|
||||
"jwt": {
|
||||
"client-key-password": "password",
|
||||
"client-keystore-file": "classpath:keystore.jks",
|
||||
"client-keystore-password": "password",
|
||||
"client-key-alias": "secure-portal",
|
||||
"token-timeout": 10,
|
||||
"client-keystore-type": "jks"
|
||||
}
|
||||
},
|
||||
"policy-enforcer": {
|
||||
"enforcement-mode": "PERMISSIVE",
|
||||
"user-managed-access": {},
|
||||
"path-cache": {
|
||||
"lifespan": 25000
|
||||
},
|
||||
"paths": [
|
||||
{
|
||||
"name" : "Album Resource",
|
||||
"path" : "/album",
|
||||
"methods" : [
|
||||
{
|
||||
"method": "GET",
|
||||
"scopes-enforcement-mode" : "DISABLED"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "Album Resource",
|
||||
"path" : "/album/{id}/",
|
||||
"methods" : [
|
||||
{
|
||||
"method": "DELETE",
|
||||
"scopes" : ["album:delete"]
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"scopes" : ["album:view"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path" : "/profile"
|
||||
},
|
||||
{
|
||||
"name" : "Admin Resources",
|
||||
"path" : "/admin/*"
|
||||
},
|
||||
{
|
||||
"name" : "Scope Protected Resource",
|
||||
"path" : "/scope-any",
|
||||
"methods": [
|
||||
{
|
||||
"method": "GET",
|
||||
"scopes": ["scope-a", "scope-b"],
|
||||
"scopes-enforcement-mode": "ANY"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "Scope Protected Resource",
|
||||
"path" : "/scope-all",
|
||||
"methods": [
|
||||
{
|
||||
"method": "GET",
|
||||
"scopes": ["scope-a", "scope-b"],
|
||||
"scopes-enforcement-mode": "ALL"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
{
|
||||
"realm": "photoz",
|
||||
"auth-server-url": "http://localhost:8180/auth",
|
||||
"ssl-required": "external",
|
||||
"resource": "photoz-restful-api",
|
||||
"bearer-only" : true,
|
||||
"credentials": {
|
||||
"jwt": {
|
||||
"client-key-password": "password",
|
||||
"client-keystore-file": "classpath:keystore.jks",
|
||||
"client-keystore-password": "password",
|
||||
"client-key-alias": "secure-portal",
|
||||
"token-timeout": 10,
|
||||
"client-keystore-type": "jks"
|
||||
}
|
||||
},
|
||||
"policy-enforcer": {
|
||||
"enforcement-mode": "PERMISSIVE",
|
||||
"user-managed-access": {},
|
||||
"lazy-load-paths": true,
|
||||
"paths": [
|
||||
{
|
||||
"name" : "Album Resource",
|
||||
"path" : "/album",
|
||||
"methods" : [
|
||||
{
|
||||
"method": "GET",
|
||||
"scopes-enforcement-mode" : "DISABLED"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "Album Resource",
|
||||
"path" : "/album/{id}/",
|
||||
"methods" : [
|
||||
{
|
||||
"method": "DELETE",
|
||||
"scopes" : ["album:delete"]
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"scopes" : ["album:view"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path" : "/profile"
|
||||
},
|
||||
{
|
||||
"name" : "Admin Resources",
|
||||
"path" : "/admin/*"
|
||||
},
|
||||
{
|
||||
"name" : "Scope Protected Resource",
|
||||
"path" : "/scope-any",
|
||||
"methods": [
|
||||
{
|
||||
"method": "GET",
|
||||
"scopes": ["scope-a", "scope-b"],
|
||||
"scopes-enforcement-mode": "ANY"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "Scope Protected Resource",
|
||||
"path" : "/scope-all",
|
||||
"methods": [
|
||||
{
|
||||
"method": "GET",
|
||||
"scopes": ["scope-a", "scope-b"],
|
||||
"scopes-enforcement-mode": "ALL"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.keycloak.testsuite</groupId>
|
||||
<artifactId>integration-arquillian-test-apps-photoz-parent</artifactId>
|
||||
<version>999.0.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>photoz-html5-client</artifactId>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<name>Keycloak Authz Tests: Photoz HTML5 Client</name>
|
||||
<description>Photoz Test HTML5 Client</description>
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<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>
|
|
@ -1,25 +0,0 @@
|
|||
<!--
|
||||
~ Copyright 2021 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.
|
||||
~
|
||||
-->
|
||||
|
||||
<jboss-deployment-structure>
|
||||
<deployment>
|
||||
<dependencies>
|
||||
<module name="org.keycloak.keycloak-common" services="import"/>
|
||||
</dependencies>
|
||||
</deployment>
|
||||
</jboss-deployment-structure>
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>photoz-html5-client</module-name>
|
||||
|
||||
</web-app>
|
|
@ -1,67 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Photoz HTML5 Client</title>
|
||||
|
||||
<script src="lib/jwt-decode.min.js"></script>
|
||||
|
||||
<script src="http://localhost:8180/auth/js/keycloak.js"></script>
|
||||
<script src="http://localhost:8180/auth/js/keycloak-authz.js"></script>
|
||||
</head>
|
||||
|
||||
<h2>Result</h2>
|
||||
<pre style="background-color: #ddd; border: 1px solid #ccc; padding: 10px;" id="output"></pre>
|
||||
|
||||
<h2>Events</h2>
|
||||
<pre style="background-color: #ddd; border: 1px solid #ccc; padding: 10px;" id="events"></pre>
|
||||
|
||||
|
||||
<script>
|
||||
function showExpires() {
|
||||
if (!keycloak.tokenParsed) {
|
||||
output("Not authenticated");
|
||||
return;
|
||||
}
|
||||
|
||||
var o = 'Token Expires:\t\t' + new Date((keycloak.tokenParsed.exp + keycloak.timeSkew) * 1000).toLocaleString() + '\n';
|
||||
o += 'Token Expires in:\t' + Math.round(keycloak.tokenParsed.exp + keycloak.timeSkew - new Date().getTime() / 1000) + ' seconds\n';
|
||||
|
||||
if (keycloak.refreshTokenParsed) {
|
||||
o += 'Refresh Token Expires:\t' + new Date((keycloak.refreshTokenParsed.exp + keycloak.timeSkew) * 1000).toLocaleString() + '\n';
|
||||
o += 'Refresh Expires in:\t' + Math.round(keycloak.refreshTokenParsed.exp + keycloak.timeSkew - new Date().getTime() / 1000) + ' seconds';
|
||||
}
|
||||
|
||||
output(o);
|
||||
}
|
||||
|
||||
function showError() {
|
||||
output("Error: " + getParameterByName("error") + "\n" + "Error description: " + getParameterByName("error_description"));
|
||||
}
|
||||
|
||||
function getParameterByName(name, url) {
|
||||
if (!url) url = window.location.href;
|
||||
name = name.replace(/[\[\]]/g, "\\$&");
|
||||
var regex = new RegExp("[?&#]" + name + "(=([^&#]*)|&|#|$)"),
|
||||
results = regex.exec(url);
|
||||
if (!results) return null;
|
||||
if (!results[2]) return '';
|
||||
return decodeURIComponent(results[2].replace(/\+/g, " "));
|
||||
}
|
||||
|
||||
function output(data) {
|
||||
if (typeof data === 'object') {
|
||||
data = JSON.stringify(data, null, ' ');
|
||||
}
|
||||
document.getElementById('output').innerHTML = data;
|
||||
}
|
||||
|
||||
function event(event) {
|
||||
var e = document.getElementById('events').innerHTML;
|
||||
document.getElementById('events').innerHTML = new Date().toLocaleString() + "\t" + event + "\n" + e;
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"realm": "photoz",
|
||||
"auth-server-url" : "http://localhost:8080/auth",
|
||||
"ssl-required" : "external",
|
||||
"resource" : "photoz-html5-client",
|
||||
"public-client" : true
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
!function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(a,b){function c(a){return decodeURIComponent(atob(a).replace(/(.)/g,function(a,b){var c=b.charCodeAt(0).toString(16).toUpperCase();return c.length<2&&(c="0"+c),"%"+c}))}var d=a("Base64");b.exports=function(a){var b=a.replace(/-/g,"+").replace(/_/g,"/");switch(b.length%4){case 0:break;case 2:b+="==";break;case 3:b+="=";break;default:throw"Illegal base64url string!"}try{return c(b)}catch(e){return d.atob(b)}}},{Base64:4}],2:[function(a,b){"use strict";var c=a("./base64_url_decode"),d=a("./json_parse");b.exports=function(a){if(!a)throw new Error("Invalid token specified");return d(c(a.split(".")[1]))}},{"./base64_url_decode":1,"./json_parse":3}],3:[function(require,module,exports){module.exports=function(str){var parsed;return parsed="object"==typeof JSON?JSON.parse(str):eval("("+str+")")}},{}],4:[function(a,b,c){!function(){var a="undefined"!=typeof c?c:this,b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",d=function(){try{document.createElement("$")}catch(a){return a}}();a.btoa||(a.btoa=function(a){for(var c,e,f=0,g=b,h="";a.charAt(0|f)||(g="=",f%1);h+=g.charAt(63&c>>8-f%1*8)){if(e=a.charCodeAt(f+=.75),e>255)throw d;c=c<<8|e}return h}),a.atob||(a.atob=function(a){if(a=a.replace(/=+$/,""),a.length%4==1)throw d;for(var c,e,f=0,g=0,h="";e=a.charAt(g++);~e&&(c=f%4?64*c+e:e,f++%4)?h+=String.fromCharCode(255&c>>(-2*f&6)):0)e=b.indexOf(e);return h})}()},{}],5:[function(a){var b="undefined"!=typeof self?self:"undefined"!=typeof window?window:{},c=a("./lib/index");"function"==typeof b.window.define&&b.window.define.amd?b.window.define("jwt_decode",function(){return c}):b.window&&(b.window.jwt_decode=c)},{"./lib/index":2}]},{},[5]);
|
|
@ -1,5 +0,0 @@
|
|||
<%@page import="org.keycloak.common.util.Time"%>
|
||||
|
||||
<%
|
||||
Time.setOffset(Integer.parseInt(request.getParameter("offset")));
|
||||
%>
|
|
@ -1,159 +0,0 @@
|
|||
{
|
||||
"realm": "photoz",
|
||||
"enabled": true,
|
||||
"userManagedAccessAllowed": true,
|
||||
"sslRequired": "external",
|
||||
"accessTokenLifespan": 100000,
|
||||
"requiredCredentials": [
|
||||
"password"
|
||||
],
|
||||
"users": [
|
||||
{
|
||||
"username": "alice",
|
||||
"enabled": true,
|
||||
"email": "alice@keycloak.org",
|
||||
"firstName": "Alice",
|
||||
"lastName": "In Chains",
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "alice"
|
||||
}
|
||||
],
|
||||
"realmRoles": [
|
||||
"user", "uma_authorization"
|
||||
],
|
||||
"clientRoles": {
|
||||
"photoz-restful-api": [
|
||||
"manage-albums"
|
||||
],
|
||||
"account": [
|
||||
"manage-account"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"username": "jdoe",
|
||||
"enabled": true,
|
||||
"email": "jdoe@keycloak.org",
|
||||
"firstName": "John",
|
||||
"lastName": "Doe",
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "jdoe"
|
||||
}
|
||||
],
|
||||
"realmRoles": [
|
||||
"user", "uma_authorization"
|
||||
],
|
||||
"clientRoles": {
|
||||
"photoz-restful-api": [
|
||||
"manage-albums"
|
||||
],
|
||||
"account": [
|
||||
"manage-account"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"username": "pedroigor",
|
||||
"enabled": true,
|
||||
"email": "pedroigor@keycloak.org",
|
||||
"firstName": "Pedro Igor",
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "pedroigor"
|
||||
}
|
||||
],
|
||||
"realmRoles": [
|
||||
"user", "uma_authorization"
|
||||
],
|
||||
"clientRoles": {
|
||||
"photoz-restful-api": [
|
||||
"manage-albums"
|
||||
],
|
||||
"account": [
|
||||
"manage-account"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"username": "admin",
|
||||
"enabled": true,
|
||||
"email": "admin@admin.com",
|
||||
"firstName": "Admin",
|
||||
"lastName": "Istrator",
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "admin"
|
||||
}
|
||||
],
|
||||
"realmRoles": [
|
||||
"admin", "uma_authorization"
|
||||
],
|
||||
"clientRoles": {
|
||||
"realm-management": [
|
||||
"realm-admin"
|
||||
],
|
||||
"photoz-restful-api": [
|
||||
"manage-albums"
|
||||
],
|
||||
"account": [
|
||||
"manage-account"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"username": "service-account-photoz-restful-api",
|
||||
"enabled": true,
|
||||
"serviceAccountClientId": "photoz-restful-api",
|
||||
"clientRoles": {
|
||||
"photoz-restful-api" : ["uma_protection"]
|
||||
}
|
||||
}
|
||||
],
|
||||
"roles": {
|
||||
"realm": [
|
||||
{
|
||||
"name": "user",
|
||||
"description": "User privileges"
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"description": "Administrator privileges"
|
||||
}
|
||||
]
|
||||
},
|
||||
"clients": [
|
||||
{
|
||||
"clientId": "photoz-html5-client",
|
||||
"enabled": true,
|
||||
"adminUrl": "/photoz-html5-client",
|
||||
"baseUrl": "/photoz-html5-client",
|
||||
"publicClient": true,
|
||||
"consentRequired" : true,
|
||||
"fullScopeAllowed" : true,
|
||||
"redirectUris": [
|
||||
"*"
|
||||
],
|
||||
"webOrigins": ["*"]
|
||||
},
|
||||
{
|
||||
"clientId": "photoz-restful-api",
|
||||
"enabled": true,
|
||||
"baseUrl": "/photoz-restful-api",
|
||||
"authorizationServicesEnabled" : true,
|
||||
"redirectUris": [
|
||||
"*"
|
||||
],
|
||||
"webOrigins" : ["*"],
|
||||
"clientAuthenticatorType": "client-jwt",
|
||||
"attributes" : {
|
||||
"jwt.credential.certificate" : "MIICqTCCAZECBgFT0Ngs/DANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1zZWN1cmUtcG9ydGFsMB4XDTE2MDQwMTA4MDA0MVoXDTI2MDQwMTA4MDIyMVowGDEWMBQGA1UEAwwNc2VjdXJlLXBvcnRhbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJa4GixpmzP511AmI0eLPLORyJwXS8908MUvdG3hmh8jMOIhe28XjIFeZSY09vFxh22F2SUMjxU/B2Hw4PDJUkebuNR7rXhOIYCJAo6eEZzjSBY/wngFtfm74zJ/eLCobBtDvIld7jobdHTfE1Oz9+GzvtG0k7cm7ubrLT0J4I1UsFZj3b//3wa+O0vNaTwHC1Jz/m59VbtXqyO4xEzIdl416cnGCmEmk5qd5h1de2UoLi/CTad8HftIJhzN1qhlySzW/9Ha70aYlDH2hiibDsXDTrNaMdaaLik7I8Rv/nIbggysG863PKZo8wknDe62QctH5VYSSktiy4gjSJkGh7ECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAZnnx+AHQ8txugGcFK8gWjildDgk+v31fBHBDvmLQaSzsUaIOJaK4wnlwUI+VfR46HmBXhjlDCobFLUptd+kz0G7xapcIn3b5jLrySUUD7L+LAp1vNOQU4mKhTGS3IEvNB73D3GH9rQ+M3KEcoN3f99fNKqKsUdxbmZqGf4VOQ57PUfLBw4PJJGlROPosBc7ivPRyeYnKekhoCTynq30BAD1FA1BA8ppcY4ZVGADPTAgMJxpglpFY9LiqCwdLAGW1ttnsyIJ7DpT+kybhhk7c+MU7gyQdv8xPnMR0bSCB9hndowgBn5oZ393aMscwMNCzwJ0aWBs1sUyn3X0RIsu9Jg=="
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,228 +0,0 @@
|
|||
{
|
||||
"allowRemoteResourceManagement": true,
|
||||
"policyEnforcementMode": "ENFORCING",
|
||||
"resources": [
|
||||
{
|
||||
"name": "User Profile Resource",
|
||||
"uri": "/profile",
|
||||
"type": "http://photoz.com/profile",
|
||||
"scopes": [
|
||||
{
|
||||
"name": "profile:view"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Album Resource",
|
||||
"uri": "/album/*",
|
||||
"type": "http://photoz.com/album",
|
||||
"scopes": [
|
||||
{
|
||||
"name": "album:view"
|
||||
},
|
||||
{
|
||||
"name": "album:delete"
|
||||
},
|
||||
{
|
||||
"name": "album:create"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Admin Resources",
|
||||
"uri": "/admin/*",
|
||||
"type": "http://photoz.com/admin",
|
||||
"scopes": [
|
||||
{
|
||||
"name": "admin:manage"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Scope Protected Resource",
|
||||
"uri": "/scope-any",
|
||||
"scopes": [
|
||||
{
|
||||
"name": "scope-a"
|
||||
},
|
||||
{
|
||||
"name": "scope-b"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"policies": [
|
||||
{
|
||||
"name": "Only Owner Policy",
|
||||
"description": "Defines that only the resource owner is allowed to do something",
|
||||
"type": "script-scripts/only-owner-policy.js",
|
||||
"logic": "POSITIVE",
|
||||
"decisionStrategy": "UNANIMOUS"
|
||||
},
|
||||
{
|
||||
"name": "Any Admin Policy",
|
||||
"description": "Defines that adminsitrators can do something",
|
||||
"type": "role",
|
||||
"logic": "POSITIVE",
|
||||
"decisionStrategy": "UNANIMOUS",
|
||||
"config": {
|
||||
"applyPolicies": "[]",
|
||||
"roles": "[{\"id\":\"admin\",\"required\":true}]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Any User Policy",
|
||||
"description": "Defines that only users from well known clients are allowed to access",
|
||||
"type": "role",
|
||||
"logic": "POSITIVE",
|
||||
"decisionStrategy": "UNANIMOUS",
|
||||
"config": {
|
||||
"applyPolicies": "[]",
|
||||
"roles": "[{\"id\":\"user\"},{\"id\":\"photoz-restful-api/manage-albums\",\"required\":true}]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Only From a Specific Client Address",
|
||||
"description": "Defines that only clients from a specific address can do something",
|
||||
"type": "script-scripts/only-from-specific-address-policy.js",
|
||||
"logic": "POSITIVE",
|
||||
"decisionStrategy": "UNANIMOUS"
|
||||
},
|
||||
{
|
||||
"name": "Deny From a Specific Client Address",
|
||||
"description": "Defines that only clients from a specific address can do something",
|
||||
"type": "script-scripts/deny-from-specific-address-policy.js",
|
||||
"logic": "POSITIVE",
|
||||
"decisionStrategy": "UNANIMOUS"
|
||||
},
|
||||
{
|
||||
"name": "Administration Policy",
|
||||
"description": "Defines that only administrators from a specific network address can do something.",
|
||||
"type": "aggregate",
|
||||
"logic": "POSITIVE",
|
||||
"decisionStrategy": "UNANIMOUS",
|
||||
"config": {
|
||||
"applyPolicies": "[\"Only From a Specific Client Address\",\"Any Admin Policy\"]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Only Owner and Administrators Policy",
|
||||
"description": "Defines that only the resource owner and administrators can do something",
|
||||
"type": "aggregate",
|
||||
"logic": "POSITIVE",
|
||||
"decisionStrategy": "AFFIRMATIVE",
|
||||
"config": {
|
||||
"applyPolicies": "[\"Administration Policy\",\"Only Owner Policy\"]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Only From @keycloak.org or Admin",
|
||||
"description": "Defines that only users from @keycloak.org",
|
||||
"type": "script-scripts/only-from-specific-domain-or-admin-policy.js",
|
||||
"logic": "POSITIVE",
|
||||
"decisionStrategy": "UNANIMOUS"
|
||||
},
|
||||
{
|
||||
"name": "Album Resource Permission",
|
||||
"description": "General policies that apply to all album resources.",
|
||||
"type": "resource",
|
||||
"logic": "POSITIVE",
|
||||
"decisionStrategy": "AFFIRMATIVE",
|
||||
"config": {
|
||||
"defaultResourceType": "http://photoz.com/album",
|
||||
"default": "true",
|
||||
"applyPolicies": "[\"Any User Policy\",\"Administration Policy\"]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Admin Resource Permission",
|
||||
"description": "General policy for any administrative resource.",
|
||||
"type": "resource",
|
||||
"logic": "POSITIVE",
|
||||
"decisionStrategy": "UNANIMOUS",
|
||||
"config": {
|
||||
"defaultResourceType": "http://photoz.com/admin",
|
||||
"default": "true",
|
||||
"applyPolicies": "[\"Administration Policy\"]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "View User Permission",
|
||||
"description": "Defines who is allowed to view an user profile",
|
||||
"type": "scope",
|
||||
"logic": "POSITIVE",
|
||||
"decisionStrategy": "UNANIMOUS",
|
||||
"config": {
|
||||
"applyPolicies": "[\"Only From @keycloak.org or Admin\"]",
|
||||
"scopes": "[\"profile:view\"]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Delete Album Permission",
|
||||
"description": "A policy that only allows the owner to delete his albums.",
|
||||
"type": "scope",
|
||||
"logic": "POSITIVE",
|
||||
"decisionStrategy": "UNANIMOUS",
|
||||
"config": {
|
||||
"applyPolicies": "[\"Only Owner and Administrators Policy\"]",
|
||||
"scopes": "[\"album:delete\"]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "View Album Permission",
|
||||
"description": "A policy that only allows the owner to view his albums.",
|
||||
"type": "scope",
|
||||
"logic": "POSITIVE",
|
||||
"decisionStrategy": "UNANIMOUS",
|
||||
"config": {
|
||||
"applyPolicies": "[\"Only Owner and Administrators Policy\"]",
|
||||
"scopes": "[\"album:view\"]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Deny Policy",
|
||||
"type": "script-scripts/always-deny-policy.js",
|
||||
"logic": "POSITIVE",
|
||||
"decisionStrategy": "UNANIMOUS"
|
||||
},
|
||||
{
|
||||
"name": "Protected Scope A Permission",
|
||||
"type": "scope",
|
||||
"logic": "POSITIVE",
|
||||
"decisionStrategy": "UNANIMOUS",
|
||||
"config": {
|
||||
"resources": "[\"Scope Protected Resource\"]",
|
||||
"scopes": "[\"scope-a\"]",
|
||||
"applyPolicies": "[\"Any User Policy\"]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Protected Scope B Permission",
|
||||
"type": "scope",
|
||||
"logic": "POSITIVE",
|
||||
"decisionStrategy": "UNANIMOUS",
|
||||
"config": {
|
||||
"resources": "[\"Scope Protected Resource\"]",
|
||||
"scopes": "[\"scope-b\"]",
|
||||
"applyPolicies": "[\"Deny Policy\"]"
|
||||
}
|
||||
}
|
||||
],
|
||||
"scopes": [
|
||||
{
|
||||
"name": "profile:view"
|
||||
},
|
||||
{
|
||||
"name": "album:view"
|
||||
},
|
||||
{
|
||||
"name": "album:create"
|
||||
},
|
||||
{
|
||||
"name": "album:delete"
|
||||
},
|
||||
{
|
||||
"name": "admin:manage"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.keycloak.testsuite</groupId>
|
||||
<artifactId>integration-arquillian-test-apps-photoz-parent</artifactId>
|
||||
<version>999.0.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>photoz-restful-api</artifactId>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<name>Keycloak Authz Test: Photoz RESTful API</name>
|
||||
<description>Photoz RESTful API</description>
|
||||
|
||||
<properties>
|
||||
<jakarta.persistence.version>${jakarta.persistence-legacy.version}</jakarta.persistence.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jboss.spec.javax.ws.rs</groupId>
|
||||
<artifactId>jboss-jaxrs-api_2.1_spec</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.persistence</groupId>
|
||||
<artifactId>jakarta.persistence-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.spec.javax.ejb</groupId>
|
||||
<artifactId>jboss-ejb-api_3.2_spec</artifactId>
|
||||
<version>1.0.0.Final</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-authz-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<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>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<version>3.3.2</version>
|
||||
<configuration>
|
||||
<attachClasses>true</attachClasses>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -1,88 +0,0 @@
|
|||
package org.keycloak.example.photoz;
|
||||
|
||||
import org.keycloak.example.photoz.entity.Album;
|
||||
import org.keycloak.example.photoz.entity.Photo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author mhajas
|
||||
*/
|
||||
public class CustomDatabase {
|
||||
|
||||
private static final CustomDatabase INSTANCE = new CustomDatabase();
|
||||
private List<Album> albums;
|
||||
private List<Photo> photos;
|
||||
private Long lastIndex = 0L;
|
||||
|
||||
|
||||
public static final CustomDatabase create() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private CustomDatabase() {
|
||||
albums = new ArrayList<>();
|
||||
}
|
||||
|
||||
public List<Album> getAll() {
|
||||
return albums;
|
||||
}
|
||||
|
||||
public void addAlbum(Album a) {
|
||||
a.setId(lastIndex++);
|
||||
albums.add(a);
|
||||
}
|
||||
|
||||
public void remove(Album albumToRemove) {
|
||||
Iterator<Album> iter = albums.iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
Album a = iter.next();
|
||||
if (a.getId().equals(albumToRemove.getId())) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Album findById(Long id) {
|
||||
for (Album a : albums) {
|
||||
if(a.getId().equals(id)) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Album findByName(String name) {
|
||||
for (Album a : albums) {
|
||||
if(a.getName().equals(name)) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Album> findByUserId(String userId) {
|
||||
List<Album> result = new ArrayList<>();
|
||||
|
||||
for (Album a : albums) {
|
||||
if (a.getUserId().equals(userId)) {
|
||||
result.add(a);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public int cleanAll() {
|
||||
int result = albums.size() + photos.size();
|
||||
albums.clear();
|
||||
photos.clear();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package org.keycloak.example.photoz;
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class ErrorResponse extends WebApplicationException {
|
||||
|
||||
private final Response.Status status;
|
||||
|
||||
public ErrorResponse(String message) {
|
||||
this(message, Response.Status.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
public ErrorResponse(String message, Response.Status status) {
|
||||
super(message, status);
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getResponse() {
|
||||
Map<String, String> errorResponse = new HashMap<>();
|
||||
|
||||
errorResponse.put("message", getMessage());
|
||||
|
||||
return Response.status(status).entity(errorResponse).build();
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
package org.keycloak.example.photoz;
|
||||
|
||||
import org.keycloak.example.photoz.admin.AdminAlbumService;
|
||||
import org.keycloak.example.photoz.album.AlbumService;
|
||||
import org.keycloak.example.photoz.album.ProfileService;
|
||||
import org.keycloak.example.photoz.unsecured.UnsecuredService;
|
||||
|
||||
import javax.ws.rs.ApplicationPath;
|
||||
import javax.ws.rs.core.Application;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Basic auth app.
|
||||
*/
|
||||
@ApplicationPath("/")
|
||||
public class PhotozApplication extends Application {
|
||||
@Override
|
||||
public Set<Class<?>> getClasses() {
|
||||
Set<Class<?>> resources = new LinkedHashSet<Class<?>>();
|
||||
resources.add(AlbumService.class);
|
||||
resources.add(AdminAlbumService.class);
|
||||
resources.add(ProfileService.class);
|
||||
resources.add(UnsecuredService.class);
|
||||
return resources;
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
* JBoss, Home of Professional Open Source
|
||||
*
|
||||
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.example.photoz.admin;
|
||||
|
||||
import org.keycloak.example.photoz.CustomDatabase;
|
||||
import org.keycloak.example.photoz.entity.Album;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
@Path("/admin/album")
|
||||
public class AdminAlbumService {
|
||||
|
||||
public static final String SCOPE_ADMIN_ALBUM_MANAGE = "admin:manage";
|
||||
|
||||
private CustomDatabase entityManager = CustomDatabase.create();
|
||||
|
||||
@Context
|
||||
private HttpHeaders headers;
|
||||
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
public Response findAll() {
|
||||
HashMap<String, List<Album>> albums = new HashMap<>();
|
||||
List<Album> result = this.entityManager.getAll();
|
||||
|
||||
for (Album album : result) {
|
||||
//We need to compile this under JDK7 so we can't use lambdas
|
||||
//albums.computeIfAbsent(album.getUserId(), key -> new ArrayList<>()).add(album);
|
||||
|
||||
if (!albums.containsKey(album.getUserId())) {
|
||||
albums.put(album.getUserId(), Collections.singletonList(album));
|
||||
}
|
||||
}
|
||||
|
||||
return Response.ok(albums).build();
|
||||
}
|
||||
}
|
|
@ -1,166 +0,0 @@
|
|||
package org.keycloak.example.photoz.album;
|
||||
|
||||
import org.keycloak.KeycloakSecurityContext;
|
||||
import org.keycloak.authorization.client.AuthzClient;
|
||||
import org.keycloak.authorization.client.ClientAuthorizationContext;
|
||||
import org.keycloak.example.photoz.CustomDatabase;
|
||||
import org.keycloak.example.photoz.entity.Album;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
|
||||
import org.keycloak.authorization.client.resource.ProtectionResource;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
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.Context;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
@Path("/album")
|
||||
public class AlbumService {
|
||||
|
||||
private final Logger log = Logger.getLogger(AlbumService.class);
|
||||
|
||||
public static final String SCOPE_ALBUM_VIEW = "album:view";
|
||||
public static final String SCOPE_ALBUM_DELETE = "album:delete";
|
||||
|
||||
private CustomDatabase customDatabase = CustomDatabase.create();
|
||||
|
||||
@Context
|
||||
private HttpServletRequest request;
|
||||
|
||||
@POST
|
||||
@Consumes("application/json")
|
||||
@Produces("application/json")
|
||||
public Response create(Album newAlbum, @QueryParam("user") String invalidUser, @Context HttpHeaders headers) {
|
||||
printAuthHeaders(headers);
|
||||
|
||||
String userId = request.getUserPrincipal().getName();
|
||||
|
||||
if (invalidUser != null) {
|
||||
userId = invalidUser;
|
||||
}
|
||||
|
||||
newAlbum.setUserId(userId);
|
||||
|
||||
log.debug("PERSISTING " + newAlbum);
|
||||
customDatabase.addAlbum(newAlbum);
|
||||
try {
|
||||
createProtectedResource(newAlbum);
|
||||
} catch (RuntimeException e) {
|
||||
log.debug("ERROR " + e);
|
||||
customDatabase.remove(newAlbum);
|
||||
return Response.status(500).entity(e.getMessage()).build(); //
|
||||
}
|
||||
|
||||
return Response.ok(newAlbum).build();
|
||||
}
|
||||
|
||||
@Path("{name}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("name") String name, @Context HttpHeaders headers) {
|
||||
printAuthHeaders(headers);
|
||||
|
||||
Album album = this.customDatabase.findByName(name);
|
||||
|
||||
try {
|
||||
deleteProtectedResource(album);
|
||||
this.customDatabase.remove(album);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not delete album.", e);
|
||||
}
|
||||
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
public Response findAll(@QueryParam("getAll") Boolean getAll) {
|
||||
if (getAll != null && getAll) {
|
||||
return Response.ok(this.customDatabase.getAll()).build();
|
||||
} else {
|
||||
return Response.ok(this.customDatabase.findByUserId(request.getUserPrincipal().getName())).build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{name}")
|
||||
@Produces("application/json")
|
||||
public Response findById(@PathParam("name") String name) {
|
||||
Album result = this.customDatabase.findByName(name);
|
||||
|
||||
if (result == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
}
|
||||
|
||||
return Response.ok(result).build();
|
||||
}
|
||||
|
||||
private void createProtectedResource(Album album) {
|
||||
log.debug("Creating ProtectedResource for " + album);
|
||||
try {
|
||||
HashSet<ScopeRepresentation> scopes = new HashSet<>();
|
||||
|
||||
scopes.add(new ScopeRepresentation(SCOPE_ALBUM_VIEW));
|
||||
scopes.add(new ScopeRepresentation(SCOPE_ALBUM_DELETE));
|
||||
|
||||
ResourceRepresentation albumResource = new ResourceRepresentation(album.getName(), scopes, "/album/" + album.getName(), "http://photoz.com/album");
|
||||
|
||||
albumResource.setOwner(album.getUserId());
|
||||
|
||||
if (album.isUserManaged()) {
|
||||
albumResource.setOwnerManagedAccess(true);
|
||||
}
|
||||
|
||||
getAuthzClient().protection().resource().create(albumResource);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not register protected resource.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteProtectedResource(Album album) {
|
||||
String uri = "/album/" + album.getName();
|
||||
|
||||
try {
|
||||
ProtectionResource protection = getAuthzClient().protection();
|
||||
List<ResourceRepresentation> search = protection.resource().findByUri(uri);
|
||||
|
||||
if (search.isEmpty()) {
|
||||
throw new RuntimeException("Could not find protected resource with URI [" + uri + "]");
|
||||
}
|
||||
|
||||
protection.resource().delete(search.get(0).getId());
|
||||
} catch (RuntimeException e) {
|
||||
throw new RuntimeException("Could not search protected resource.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private AuthzClient getAuthzClient() {
|
||||
return getAuthorizationContext().getClient();
|
||||
}
|
||||
|
||||
private ClientAuthorizationContext getAuthorizationContext() {
|
||||
return ClientAuthorizationContext.class.cast(getKeycloakSecurityContext().getAuthorizationContext());
|
||||
}
|
||||
|
||||
private KeycloakSecurityContext getKeycloakSecurityContext() {
|
||||
return KeycloakSecurityContext.class.cast(request.getAttribute(KeycloakSecurityContext.class.getName()));
|
||||
}
|
||||
|
||||
private void printAuthHeaders(HttpHeaders headers) {
|
||||
log.debug("-----------------Authorization headers--------------------------");
|
||||
for (String authHeader : headers.getRequestHeader(HttpHeaders.AUTHORIZATION)) {
|
||||
log.debug(authHeader);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* JBoss, Home of Professional Open Source
|
||||
*
|
||||
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.example.photoz.album;
|
||||
|
||||
import org.keycloak.example.photoz.CustomDatabase;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.security.Principal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
@Path("/profile")
|
||||
public class ProfileService {
|
||||
|
||||
private static final String PROFILE_VIEW = "profile:view";
|
||||
|
||||
private CustomDatabase customDatabase = CustomDatabase.create();
|
||||
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
public Response view(@Context HttpServletRequest request) {
|
||||
Principal userPrincipal = request.getUserPrincipal();
|
||||
List albums = this.customDatabase.findByUserId(userPrincipal.getName());
|
||||
return Response.ok(new Profile(userPrincipal.getName(), albums.size())).build();
|
||||
}
|
||||
|
||||
public static class Profile {
|
||||
private String userName;
|
||||
private int totalAlbums;
|
||||
|
||||
public Profile(String name, int totalAlbums) {
|
||||
this.userName = name;
|
||||
this.totalAlbums = totalAlbums;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public int getTotalAlbums() {
|
||||
return totalAlbums;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* JBoss, Home of Professional Open Source
|
||||
*
|
||||
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.example.photoz.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Transient;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
@Entity
|
||||
@Table(uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = {"name", "userId"})
|
||||
})
|
||||
public class Album implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
@OneToMany(mappedBy = "album", fetch = FetchType.EAGER)
|
||||
private List<Photo> photos = new ArrayList<>();
|
||||
|
||||
@Column(nullable = false)
|
||||
private String userId;
|
||||
|
||||
@Transient
|
||||
private boolean userManaged = false;
|
||||
|
||||
public Long getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public void setId(final Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<Photo> getPhotos() {
|
||||
return this.photos;
|
||||
}
|
||||
|
||||
public void setPhotos(final List<Photo> photos) {
|
||||
this.photos = photos;
|
||||
}
|
||||
|
||||
public void setUserId(final String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return this.userId;
|
||||
}
|
||||
|
||||
public boolean isUserManaged() {
|
||||
return userManaged;
|
||||
}
|
||||
|
||||
public void setUserManaged(boolean userManaged) {
|
||||
this.userManaged = userManaged;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Album{" + "id=" + id + ", name=" + name + ", userId=" + userId + '}';
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* JBoss, Home of Professional Open Source
|
||||
*
|
||||
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.example.photoz.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Lob;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
@Entity
|
||||
public class Photo implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
@Column
|
||||
private String name;
|
||||
|
||||
@ManyToOne
|
||||
private Album album;
|
||||
|
||||
@Lob
|
||||
@Column
|
||||
@Basic(fetch = FetchType.LAZY)
|
||||
private byte[] image;
|
||||
|
||||
public Long getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public void setId(final Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Album getAlbum() {
|
||||
return this.album;
|
||||
}
|
||||
|
||||
public void setAlbum(final Album album) {
|
||||
this.album = album;
|
||||
}
|
||||
|
||||
public byte[] getImage() {
|
||||
return this.image;
|
||||
}
|
||||
|
||||
public void setImage(final byte[] image) {
|
||||
this.image = image;
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Copyright 2018 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.example.photoz.unsecured;
|
||||
|
||||
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.GET;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.example.photoz.CustomDatabase;
|
||||
|
||||
/**
|
||||
* Service used to ensure there is clean DB before test
|
||||
*
|
||||
* @author <a href="mailto:vramik@redhat.com">Vlastislav Ramik</a>
|
||||
*/
|
||||
@Path("/unsecured/clean")
|
||||
public class UnsecuredService {
|
||||
|
||||
private final Logger log = Logger.getLogger(UnsecuredService.class);
|
||||
|
||||
private CustomDatabase customDatabase = CustomDatabase.create();
|
||||
|
||||
@GET
|
||||
@Produces("application/json")
|
||||
public Response cleanAll() {
|
||||
int deleted = customDatabase.cleanAll();
|
||||
|
||||
if (deleted != 0) {
|
||||
log.warnf("Database was not empty. Deleted Albums + Photos {0}", deleted);
|
||||
} else {
|
||||
log.debug("Database was clean before test");
|
||||
}
|
||||
return Response.ok().build();
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1,27 +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.
|
||||
~
|
||||
-->
|
||||
|
||||
<jboss-deployment-structure>
|
||||
<deployment>
|
||||
<dependencies>
|
||||
<module name="org.keycloak.keycloak-authz-client" services="import"/>
|
||||
<module name="com.h2database.h2" services="import"/>
|
||||
</dependencies>
|
||||
</deployment>
|
||||
</jboss-deployment-structure>
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans 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/beans_1_0.xsd">
|
||||
</beans>
|
|
@ -1,76 +0,0 @@
|
|||
{
|
||||
"realm": "photoz",
|
||||
"auth-server-url": "http://localhost:8180/auth",
|
||||
"ssl-required": "external",
|
||||
"resource": "photoz-restful-api",
|
||||
"bearer-only" : true,
|
||||
"credentials": {
|
||||
"jwt": {
|
||||
"client-key-password": "password",
|
||||
"client-keystore-file": "classpath:keystore.jks",
|
||||
"client-keystore-password": "password",
|
||||
"client-key-alias": "secure-portal",
|
||||
"token-timeout": 10,
|
||||
"client-keystore-type": "jks"
|
||||
}
|
||||
},
|
||||
"policy-enforcer": {
|
||||
"enforcement-mode": "PERMISSIVE",
|
||||
"user-managed-access": {},
|
||||
"paths": [
|
||||
{
|
||||
"name" : "Album Resource",
|
||||
"path" : "/album",
|
||||
"methods" : [
|
||||
{
|
||||
"method": "GET",
|
||||
"scopes-enforcement-mode" : "DISABLED"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "Album Resource",
|
||||
"path" : "/album/{id}/",
|
||||
"methods" : [
|
||||
{
|
||||
"method": "DELETE",
|
||||
"scopes" : ["album:delete"]
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"scopes" : ["album:view"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path" : "/profile"
|
||||
},
|
||||
{
|
||||
"name" : "Admin Resources",
|
||||
"path" : "/admin/*"
|
||||
},
|
||||
{
|
||||
"name" : "Scope Protected Resource",
|
||||
"path" : "/scope-any",
|
||||
"methods": [
|
||||
{
|
||||
"method": "GET",
|
||||
"scopes": ["scope-a", "scope-b"],
|
||||
"scopes-enforcement-mode": "ANY"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "Scope Protected Resource",
|
||||
"path" : "/scope-all",
|
||||
"methods": [
|
||||
{
|
||||
"method": "GET",
|
||||
"scopes": ["scope-a", "scope-b"],
|
||||
"scopes-enforcement-mode": "ALL"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>photoz-restful-api</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>user</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>All Resources</web-resource-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>admin</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Unsecured</web-resource-name>
|
||||
<url-pattern>/unsecured/*</url-pattern>
|
||||
</web-resource-collection>
|
||||
</security-constraint>
|
||||
|
||||
<login-config>
|
||||
<auth-method>KEYCLOAK</auth-method>
|
||||
<realm-name>photoz</realm-name>
|
||||
</login-config>
|
||||
|
||||
<security-role>
|
||||
<role-name>admin</role-name>
|
||||
</security-role>
|
||||
|
||||
<security-role>
|
||||
<role-name>user</role-name>
|
||||
</security-role>
|
||||
</web-app>
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.keycloak.testsuite</groupId>
|
||||
<artifactId>integration-arquillian-test-apps</artifactId>
|
||||
<version>999.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>integration-arquillian-test-apps-photoz-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Keycloak Authz: PhotoZ Test Parent</name>
|
||||
<description>PhotoZ Test Application</description>
|
||||
|
||||
<modules>
|
||||
<module>photoz-restful-api</module>
|
||||
<module>photoz-html5-client</module>
|
||||
</modules>
|
||||
</project>
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
<modules>
|
||||
<module>test-apps-dist</module>
|
||||
<module>photoz</module>
|
||||
<module>hello-world-authz-service</module>
|
||||
<module>servlet-authz</module>
|
||||
<module>servlet-policy-enforcer</module>
|
||||
|
|
|
@ -19,14 +19,6 @@
|
|||
|
||||
<target name="all">
|
||||
<delete dir="target/test-apps"/>
|
||||
<copy todir="target/test-apps/photoz" overwrite="true">
|
||||
<fileset dir="../photoz">
|
||||
<exclude name="**/target/**"/>
|
||||
<exclude name="**/*.iml"/>
|
||||
<exclude name="**/*.unconfigured"/>
|
||||
<exclude name="**/subsystem-config.xml"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
<copy todir="target/test-apps/hello-world-authz-service" overwrite="true">
|
||||
<fileset dir="../hello-world-authz-service">
|
||||
<exclude name="**/target/**"/>
|
||||
|
|
|
@ -144,12 +144,6 @@
|
|||
<artifactId>integration-arquillian-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.testsuite</groupId>
|
||||
<artifactId>photoz-restful-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>classes</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mvel</groupId>
|
||||
<artifactId>mvel2</artifactId>
|
||||
|
|
|
@ -1,318 +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.testsuite.adapter.page;
|
||||
|
||||
import org.jboss.arquillian.container.test.api.OperateOnDeployment;
|
||||
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.jboss.arquillian.test.api.ArquillianResource;
|
||||
import org.keycloak.testsuite.auth.page.login.OIDCLogin;
|
||||
import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
|
||||
import org.keycloak.testsuite.util.JavascriptBrowser;
|
||||
import org.keycloak.testsuite.util.UIUtils;
|
||||
import org.keycloak.testsuite.util.URLUtils;
|
||||
import org.keycloak.testsuite.util.javascript.JavascriptStateValidator;
|
||||
import org.keycloak.testsuite.util.javascript.JavascriptTestExecutorWithAuthorization;
|
||||
import org.keycloak.testsuite.util.javascript.ResponseValidator;
|
||||
import org.keycloak.testsuite.util.javascript.XMLHttpRequest;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.keycloak.testsuite.util.UIUtils.clickLink;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.pause;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
|
||||
|
||||
public static final String DEPLOYMENT_NAME = "photoz-html5-client";
|
||||
public static final int WAIT_AFTER_OPERATION = 1000;
|
||||
|
||||
@ArquillianResource
|
||||
@OperateOnDeployment(DEPLOYMENT_NAME)
|
||||
private URL url;
|
||||
|
||||
@Drone
|
||||
@JavascriptBrowser
|
||||
protected WebDriver driver;
|
||||
|
||||
@Page
|
||||
@JavascriptBrowser
|
||||
protected OIDCLogin loginPage;
|
||||
|
||||
|
||||
@FindBy(xpath = "//a[@ng-click = 'Identity.logout()']")
|
||||
@JavascriptBrowser
|
||||
private WebElement signOutButton;
|
||||
|
||||
@FindBy(id = "entitlement")
|
||||
@JavascriptBrowser
|
||||
private WebElement entitlement;
|
||||
|
||||
@FindBy(id = "entitlements")
|
||||
@JavascriptBrowser
|
||||
private WebElement entitlements;
|
||||
|
||||
@FindBy(id = "get-all-resources")
|
||||
@JavascriptBrowser
|
||||
private WebElement viewAllAlbums;
|
||||
|
||||
@FindBy(id = "output")
|
||||
@JavascriptBrowser
|
||||
private WebElement output;
|
||||
|
||||
private JavascriptTestExecutorWithAuthorization testExecutor;
|
||||
private String apiUrl;
|
||||
|
||||
public void setTestExecutorPlayground(JavascriptTestExecutorWithAuthorization executor, String apiUrl) {
|
||||
testExecutor = executor;
|
||||
this.apiUrl = apiUrl;
|
||||
}
|
||||
|
||||
public void createAlbum(String name) {
|
||||
createAlbum(name, false);
|
||||
}
|
||||
|
||||
public void createAlbum(String name, boolean managed) {
|
||||
createAlbum(name, managed, false, null);
|
||||
}
|
||||
|
||||
public void createAlbum(String name, boolean managed, boolean invalidUser, ResponseValidator validator) {
|
||||
testExecutor.sendXMLHttpRequest(
|
||||
XMLHttpRequest.create()
|
||||
.method("POST")
|
||||
.url(apiUrl + "/album" + (invalidUser ? "?user=invalidUser" : ""))
|
||||
.content("JSON.stringify(JSON.parse('{\"name\" : \"" + name + "\", \"userManaged\": " + Boolean.toString(managed) + " }'))")
|
||||
.addHeader("Content-Type", "application/json; charset=UTF-8")
|
||||
, validator);
|
||||
}
|
||||
|
||||
|
||||
public void createAlbumWithInvalidUser(String name, ResponseValidator validator) {
|
||||
createAlbum(name, false, true, validator);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public URL getInjectedUrl() {
|
||||
return this.url;
|
||||
}
|
||||
|
||||
public void deleteAlbum(String name, ResponseValidator validator) {
|
||||
testExecutor.sendXMLHttpRequest(
|
||||
XMLHttpRequest.create()
|
||||
.method("DELETE")
|
||||
.url(apiUrl + "/album/" + name + "/") // it doesn't work without ending "/"
|
||||
, validator);
|
||||
}
|
||||
|
||||
public void navigateToAdminAlbum(ResponseValidator validator) {
|
||||
testExecutor.sendXMLHttpRequest(
|
||||
XMLHttpRequest.create()
|
||||
.method("GET")
|
||||
.addHeader("Accept", "application/json")
|
||||
.url(apiUrl + "/admin/album")
|
||||
, validator);
|
||||
}
|
||||
|
||||
public void logOut() {
|
||||
navigateTo();
|
||||
waitUntilElement(signOutButton).is().clickable(); // Sometimes doesn't work in PhantomJS!
|
||||
clickLink(signOutButton);
|
||||
}
|
||||
|
||||
public void requestEntitlement(JavascriptStateValidator validator) {
|
||||
testExecutor.executeAsyncScript("var callback = arguments[arguments.length - 1];" +
|
||||
"window.authorization.entitlement('photoz-restful-api', {" +
|
||||
" \"permissions\": [" +
|
||||
" {" +
|
||||
" \"id\" : \"Album Resource\"" +
|
||||
" }" +
|
||||
" ]" +
|
||||
"}).then(function (rpt) {" +
|
||||
" callback(JSON.stringify(jwt_decode(rpt), null, ' '));" +
|
||||
"});", validator);
|
||||
}
|
||||
|
||||
public void requestEntitlements(JavascriptStateValidator validator) {
|
||||
testExecutor.executeAsyncScript("var callback = arguments[arguments.length - 1];" +
|
||||
"window.authorization.entitlement('photoz-restful-api', {}).then(function (rpt) {" +
|
||||
" callback(JSON.stringify(jwt_decode(rpt), null, ' '));" +
|
||||
"});", validator);
|
||||
}
|
||||
|
||||
private void waitForDenial() {
|
||||
waitUntilElement(output).text().contains("You can not access");
|
||||
}
|
||||
|
||||
private void waitForNotDenial() {
|
||||
waitUntilElement(output).text().not().contains("You can not access");
|
||||
}
|
||||
|
||||
public void viewAllAlbums() {
|
||||
viewAllAlbums.click();
|
||||
pause(WAIT_AFTER_OPERATION);
|
||||
}
|
||||
|
||||
public void viewProfile(ResponseValidator validator) {
|
||||
testExecutor.sendXMLHttpRequest(
|
||||
XMLHttpRequest.create()
|
||||
.method("GET")
|
||||
.addHeader("Accept", "application/json")
|
||||
.url(apiUrl + "/profile")
|
||||
, validator);
|
||||
}
|
||||
|
||||
public void viewAlbum(String name, ResponseValidator validator) {
|
||||
testExecutor.sendXMLHttpRequest(
|
||||
XMLHttpRequest.create()
|
||||
.method("GET")
|
||||
.addHeader("Accept", "application/json")
|
||||
.url(apiUrl + "/album/" + name + "/")
|
||||
, validator);
|
||||
}
|
||||
|
||||
public void accountPage() {
|
||||
testExecutor.openAccountPage(null);
|
||||
}
|
||||
|
||||
public void accountMyResources() {
|
||||
accountPage();
|
||||
WebElement myResources = driver.findElement(By.xpath("//a[text() = 'My Resources']"));
|
||||
waitUntilElement(myResources).is().clickable();
|
||||
myResources.click();
|
||||
}
|
||||
|
||||
public void accountMyResource(String name) {
|
||||
accountMyResources();
|
||||
WebElement myResource = driver.findElement(By.id("detail-" + name));
|
||||
waitUntilElement(myResource).is().clickable();
|
||||
myResource.click();
|
||||
}
|
||||
|
||||
public void accountGrantResource(String name, String requester) {
|
||||
accountMyResources();
|
||||
grantResource(name, requester);
|
||||
}
|
||||
|
||||
public void grantResource(String name, String requester) {
|
||||
WebElement grantResource = driver.findElement(By.id("grant-" + name + "-" + requester));
|
||||
waitUntilElement(grantResource).is().clickable();
|
||||
grantResource.click();
|
||||
}
|
||||
|
||||
public void accountGrantRemoveScope(String name, String requester, String scope) {
|
||||
accountMyResources();
|
||||
WebElement grantRemoveScope = driver.findElement(By.id("grant-remove-scope-" + name + "-" + requester + "-" + scope));
|
||||
waitUntilElement(grantRemoveScope).is().clickable();
|
||||
grantRemoveScope.click();
|
||||
}
|
||||
|
||||
public void accountRevokeResource(String name, String requester) {
|
||||
accountMyResource(name);
|
||||
revokeResource(name, requester);
|
||||
}
|
||||
|
||||
public void revokeResource(String name, String requester) {
|
||||
WebElement revokeResource = driver.findElement(By.id("revoke-" + name + "-" + requester));
|
||||
waitUntilElement(revokeResource).is().clickable();
|
||||
revokeResource.click();
|
||||
}
|
||||
|
||||
public void accountShareResource(String name, String user) {
|
||||
accountMyResource(name);
|
||||
shareResource(user);
|
||||
}
|
||||
|
||||
public void accountShareRemoveScope(String name, String user, String scope) {
|
||||
accountMyResource(name);
|
||||
|
||||
WebElement shareRemoveScope = driver.findElement(By.id("share-remove-scope-" + name + "-" + scope));
|
||||
waitUntilElement(shareRemoveScope).is().clickable();
|
||||
shareRemoveScope.click();
|
||||
|
||||
shareResource(user);
|
||||
}
|
||||
|
||||
public void shareResource(String user) {
|
||||
WebElement userIdInput = driver.findElement(By.id("user_id"));
|
||||
UIUtils.setTextInputValue(userIdInput, user);
|
||||
pause(200); // We need to wait a bit for the form to "accept" the input (otherwise it registers the input as empty)
|
||||
waitUntilElement(userIdInput).attribute(UIUtils.VALUE_ATTR_NAME).contains(user);
|
||||
|
||||
WebElement shareButton = driver.findElement(By.id("share-button"));
|
||||
waitUntilElement(shareButton).is().clickable();
|
||||
shareButton.click();
|
||||
}
|
||||
|
||||
public void assertError() {
|
||||
assertEquals("We are sorry...", driver.findElement(By.id("kc-page-title")).getText());
|
||||
}
|
||||
|
||||
public void accountDenyResource(String name) {
|
||||
accountMyResource(name);
|
||||
WebElement denyLink = driver.findElement(By.linkText("Deny"));
|
||||
waitUntilElement(denyLink).is().clickable();
|
||||
denyLink.click();
|
||||
waitForPageToLoad();
|
||||
}
|
||||
|
||||
public void requestResourceProtectedAnyScope(ResponseValidator validator) {
|
||||
testExecutor.sendXMLHttpRequest(
|
||||
XMLHttpRequest.create()
|
||||
.method("GET")
|
||||
.url(apiUrl + "/scope-any")
|
||||
, validator);
|
||||
}
|
||||
|
||||
public void requestResourceProtectedAllScope(ResponseValidator validator) {
|
||||
testExecutor.sendXMLHttpRequest(
|
||||
XMLHttpRequest.create()
|
||||
.method("GET")
|
||||
.url(apiUrl + "/scope-all")
|
||||
, validator);
|
||||
}
|
||||
|
||||
public WebElement getOutput() {
|
||||
return output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void navigateTo() {
|
||||
driver.navigate().to(toString());
|
||||
waitForPageToLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurrent() {
|
||||
return URLUtils.currentUrlStartsWith(toString());
|
||||
}
|
||||
|
||||
public void executeScript(String script) {
|
||||
testExecutor.executeScript(script);
|
||||
}
|
||||
}
|
|
@ -1,167 +0,0 @@
|
|||
package org.keycloak.testsuite.util.javascript;
|
||||
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.testsuite.auth.page.login.OAuthGrant;
|
||||
import org.keycloak.testsuite.auth.page.login.OIDCLogin;
|
||||
import org.keycloak.testsuite.pages.ConsentPage;
|
||||
import org.keycloak.testsuite.util.URLUtils;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
|
||||
|
||||
/**
|
||||
* @author mhajas
|
||||
*/
|
||||
public class JavascriptTestExecutorWithAuthorization extends JavascriptTestExecutor {
|
||||
|
||||
public static JavascriptTestExecutorWithAuthorization create(WebDriver driver, OIDCLogin loginPage) {
|
||||
return new JavascriptTestExecutorWithAuthorization(driver, loginPage);
|
||||
}
|
||||
|
||||
private JavascriptTestExecutorWithAuthorization(WebDriver driver, OIDCLogin loginPage) {
|
||||
super(driver, loginPage);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JavascriptTestExecutorWithAuthorization init(JSObjectBuilder argumentsBuilder, JavascriptStateValidator validator) {
|
||||
super.init(argumentsBuilder, validator);
|
||||
Object output = jsExecutor.executeScript(
|
||||
"var callback = arguments[arguments.length - 1];" +
|
||||
"window.authorization = new KeycloakAuthorization(window.keycloak);" +
|
||||
"while (typeof window.authorization === 'undefined') {}" + // Wait until authorization is initialized
|
||||
"return 'Authz initialized'");
|
||||
|
||||
assertThat(output, is("Authz initialized"));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavascriptTestExecutorWithAuthorization login(JavascriptStateValidator validator) {
|
||||
super.login(validator);
|
||||
return this;
|
||||
}
|
||||
|
||||
public JavascriptTestExecutorWithAuthorization loginFormWithScopesWithPossibleConsentPage(UserRepresentation user, JavascriptStateValidator validator, OAuthGrant oAuthGrantPage, String... scopes) {
|
||||
String currentUrl = jsDriver.getCurrentUrl();
|
||||
|
||||
if (scopes.length > 0) {
|
||||
StringBuilder scopesValue = new StringBuilder();
|
||||
|
||||
for (String scope : scopes) {
|
||||
if (scopesValue.length() != 0) {
|
||||
scopesValue.append(" ");
|
||||
}
|
||||
scopesValue.append(scope);
|
||||
}
|
||||
|
||||
scopesValue.append(" openid");
|
||||
|
||||
|
||||
StringBuilder urlWithScopeParam = new StringBuilder(currentUrl);
|
||||
|
||||
int scopeIndex = currentUrl.indexOf("scope");
|
||||
|
||||
if (scopeIndex != -1) {
|
||||
// Remove scope param from url
|
||||
urlWithScopeParam.delete(scopeIndex, currentUrl.indexOf('&', scopeIndex));
|
||||
// Add scope param to the end of query
|
||||
urlWithScopeParam.append("&").append("scope=");
|
||||
}
|
||||
|
||||
if (!currentUrl.contains("?")) {
|
||||
urlWithScopeParam.append("?scope=");
|
||||
}
|
||||
|
||||
urlWithScopeParam.append(scopesValue);
|
||||
|
||||
URLUtils.navigateToUri(urlWithScopeParam.toString());
|
||||
waitForPageToLoad();
|
||||
}
|
||||
|
||||
loginFormWithPossibleConsentPage(user, oAuthGrantPage, validator);
|
||||
return this;
|
||||
}
|
||||
|
||||
public JavascriptTestExecutorWithAuthorization loginFormWithPossibleConsentPage(UserRepresentation user, OAuthGrant oAuthGrantPage, JavascriptStateValidator validator) {
|
||||
super.loginForm(user);
|
||||
|
||||
try {
|
||||
// simple check if we are at the consent page, if so just click 'Yes'
|
||||
if (oAuthGrantPage.isCurrent(jsDriver)) {
|
||||
oAuthGrantPage.accept();
|
||||
waitForPageToLoad();
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
// ignore errors when checking consent page, if an error tests will also fail
|
||||
}
|
||||
|
||||
if (validator != null) {
|
||||
validator.validate(jsDriver, null, events);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavascriptTestExecutor sendXMLHttpRequest(XMLHttpRequest request, ResponseValidator validator) {
|
||||
// Intercept all requests and add rpt or token
|
||||
|
||||
// check if rpt is already present
|
||||
Object o = jsExecutor.executeScript("if(window.authorization && window.authorization.rpt) return true; else return false;");
|
||||
|
||||
|
||||
|
||||
if (o == null || o.equals(false)) {
|
||||
// RPT is not present yet, lets try to use bearer token
|
||||
request.includeBearerToken();
|
||||
} else {
|
||||
// RPT token is present so we will use it
|
||||
request.includeRpt();
|
||||
}
|
||||
|
||||
// Try to send request
|
||||
Map<String, Object> result = request.send(jsExecutor);
|
||||
|
||||
// If request was denied do UMA
|
||||
if ((Long.valueOf(403).equals(result.get("status")) || Long.valueOf(401).equals(result.get("status")))) {
|
||||
//extracting ticket from response
|
||||
String headersString = (String) result.get("responseHeaders");
|
||||
|
||||
List<String> headersList = Arrays.asList(headersString.split("\r\n"));
|
||||
String wwwAuthenticate = headersList.stream().filter(s -> s.toLowerCase().startsWith("www-authenticate:")).findFirst().get();
|
||||
|
||||
if (wwwAuthenticate.contains("UMA") && wwwAuthenticate.contains("ticket")) {
|
||||
String ticket = Arrays.asList(wwwAuthenticate.split(",")).stream().filter(s -> s.startsWith("ticket")).findFirst().get();
|
||||
|
||||
ticket = ticket.substring(0, ticket.length() - 1).replaceFirst("ticket=\"", "");
|
||||
|
||||
// AuthorizationRequest for RPT
|
||||
o = jsExecutor.executeAsyncScript(
|
||||
"var callback = arguments[arguments.length - 1];" +
|
||||
"window.authorization" +
|
||||
".authorize(" + JSObjectBuilder.create().add("ticket", ticket).build() + ")" +
|
||||
".then(function (rpt) {callback(rpt)}, function() {callback('failed1')}, function() {callback('failed2')});");
|
||||
|
||||
o = jsExecutor.executeScript("if(window.authorization && window.authorization.rpt) return true; else return false;"); // return window.authorization && window.authorization.rpt doesn't work
|
||||
|
||||
if (o != null && o.equals(true)) {
|
||||
request.includeRpt();
|
||||
result = request.send(jsExecutor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (validator != null) {
|
||||
validator.validate(result);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -1,312 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 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.authz.adapter.example;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.keycloak.common.Profile.Feature.AUTHORIZATION;
|
||||
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
|
||||
import static org.keycloak.testsuite.utils.io.IOUtil.loadJson;
|
||||
import static org.keycloak.testsuite.utils.io.IOUtil.loadRealm;
|
||||
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.client.LaxRedirectStrategy;
|
||||
import org.jboss.arquillian.container.spi.client.container.DeploymentException;
|
||||
import org.jboss.arquillian.container.test.api.Deployer;
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.jboss.arquillian.test.api.ArquillianResource;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.keycloak.admin.client.resource.AuthorizationResource;
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.admin.client.resource.ClientScopesResource;
|
||||
import org.keycloak.admin.client.resource.ClientsResource;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.protocol.ProtocolMapperUtils;
|
||||
import org.keycloak.protocol.oidc.mappers.UserClientRoleMappingMapper;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.ClientScopeRepresentation;
|
||||
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
|
||||
import org.keycloak.testsuite.ProfileAssume;
|
||||
import org.keycloak.testsuite.adapter.page.PhotozClientAuthzTestApp;
|
||||
import org.keycloak.testsuite.admin.ApiUtil;
|
||||
import org.keycloak.testsuite.arquillian.AppServerTestEnricher;
|
||||
import org.keycloak.testsuite.auth.page.login.OAuthGrant;
|
||||
import org.keycloak.testsuite.util.DroneUtils;
|
||||
import org.keycloak.testsuite.util.JavascriptBrowser;
|
||||
import org.keycloak.testsuite.util.javascript.JavascriptTestExecutorWithAuthorization;
|
||||
import org.openqa.selenium.JavascriptExecutor;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
import org.openqa.selenium.support.ui.WebDriverWait;
|
||||
import org.wildfly.extras.creaper.core.online.CliException;
|
||||
import org.wildfly.extras.creaper.core.online.OnlineManagementClient;
|
||||
import org.wildfly.extras.creaper.core.online.operations.admin.Administration;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public abstract class AbstractBasePhotozExampleAdapterTest extends AbstractPhotozJavascriptExecutorTest {
|
||||
|
||||
protected static final String RESOURCE_SERVER_ID = "photoz-restful-api";
|
||||
protected static final String ALICE_ALBUM_NAME = "Alice-Family-Album";
|
||||
private static final int TOKEN_LIFESPAN_LEEWAY = 3; // seconds
|
||||
|
||||
@ArquillianResource
|
||||
private Deployer deployer;
|
||||
|
||||
@Page
|
||||
@JavascriptBrowser protected PhotozClientAuthzTestApp clientPage;
|
||||
|
||||
@Page
|
||||
@JavascriptBrowser
|
||||
private OAuthGrant oAuthGrantPage;
|
||||
|
||||
protected JavascriptTestExecutorWithAuthorization testExecutor;
|
||||
|
||||
@FindBy(id = "output")
|
||||
@JavascriptBrowser
|
||||
protected WebElement outputArea;
|
||||
|
||||
@FindBy(id = "events")
|
||||
@JavascriptBrowser
|
||||
protected WebElement eventsArea;
|
||||
|
||||
@BeforeClass
|
||||
public static void enabled() {
|
||||
ProfileAssume.assumeFeatureEnabled(AUTHORIZATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultPageUriParameters() {
|
||||
super.setDefaultPageUriParameters();
|
||||
testRealmPage.setAuthRealm(REALM_NAME);
|
||||
oAuthGrantPage.setAuthRealm(REALM_NAME);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforePhotozExampleAdapterTest() throws Exception {
|
||||
DroneUtils.addWebDriver(jsDriver);
|
||||
deployIgnoreIfDuplicate(RESOURCE_SERVER_ID);
|
||||
|
||||
clientPage.navigateTo();
|
||||
// waitForPageToLoad();
|
||||
assertCurrentUrlStartsWith(clientPage.toString());
|
||||
|
||||
testExecutor = JavascriptTestExecutorWithAuthorization.create(jsDriver, jsDriverTestRealmLoginPage);
|
||||
clientPage.setTestExecutorPlayground(testExecutor, appServerContextRootPage + "/" + RESOURCE_SERVER_ID);
|
||||
jsDriver.manage().deleteAllCookies();
|
||||
|
||||
try (CloseableHttpClient httpClient = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).build()) {
|
||||
HttpGet request = new HttpGet(clientPage.toString() + "/unsecured/clean");
|
||||
httpClient.execute(request).close();
|
||||
}
|
||||
}
|
||||
|
||||
// workaround for KEYCLOAK-8660 from https://stackoverflow.com/questions/50917932/what-versions-of-jackson-are-allowed-in-jboss-6-4-20-patch
|
||||
@Before
|
||||
public void fixBrokenDeserializationOnEAP6() throws IOException, CliException, TimeoutException, InterruptedException {
|
||||
if (AppServerTestEnricher.isEAP6AppServer()) {
|
||||
OnlineManagementClient client = AppServerTestEnricher.getManagementClient();
|
||||
Administration administration = new Administration(client);
|
||||
|
||||
client.execute("/system-property=jackson.deserialization.whitelist.packages:add(value=org.keycloak.example.photoz)");
|
||||
administration.reloadIfRequired();
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterPhotozExampleAdapterTest() {
|
||||
this.deployer.undeploy(RESOURCE_SERVER_ID);
|
||||
DroneUtils.removeWebDriver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
|
||||
RealmRepresentation realm = loadRealm(new File(TEST_APPS_HOME_DIR + "/photoz/photoz-realm.json"));
|
||||
|
||||
realm.setAccessTokenLifespan(30 + TOKEN_LIFESPAN_LEEWAY); // seconds
|
||||
|
||||
testRealms.add(realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeAbstractKeycloakTest() throws Exception {
|
||||
super.beforeAbstractKeycloakTest();
|
||||
importResourceServerSettings();
|
||||
}
|
||||
|
||||
protected List<ResourceRepresentation> getResourcesOfUser(String username) throws FileNotFoundException {
|
||||
return getAuthorizationResource().resources().resources().stream().filter(resource -> resource.getOwner().getName().equals(username)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
protected void printUpdatedPolicies() throws FileNotFoundException {
|
||||
log.debug("Check updated policies");
|
||||
for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
|
||||
log.debugf("Policy: %s", policy.getName());
|
||||
for (String key : policy.getConfig().keySet()) {
|
||||
log.debugf("-- key: %s, value: %s", key, policy.getConfig().get(key));
|
||||
}
|
||||
}
|
||||
log.debug("------------------------------");
|
||||
}
|
||||
|
||||
protected void assertOnTestAppUrl(WebDriver jsDriver, Object output, WebElement events) {
|
||||
waitForPageToLoad();
|
||||
assertCurrentUrlStartsWith(clientPage.toString(), jsDriver);
|
||||
}
|
||||
|
||||
protected void assertWasDenied(Map<String, Object> response) {
|
||||
assertThat(response.get("status"), is(equalTo(401L)));
|
||||
}
|
||||
|
||||
protected void assertWasNotDenied(Map<String, Object> response) {
|
||||
assertThat(response.get("status"), is(equalTo(200L)));
|
||||
}
|
||||
|
||||
private void importResourceServerSettings() throws FileNotFoundException {
|
||||
ResourceServerRepresentation authSettings = loadJson(new FileInputStream(new File(TEST_APPS_HOME_DIR + "/photoz/photoz-restful-api-authz-service.json")), ResourceServerRepresentation.class);
|
||||
|
||||
authSettings.getPolicies().stream()
|
||||
.filter(x -> "Only Owner Policy".equals(x.getName()))
|
||||
.forEach(x -> x.getConfig().put("mavenArtifactVersion", System.getProperty("project.version")));
|
||||
|
||||
getAuthorizationResource().importSettings(authSettings);
|
||||
}
|
||||
|
||||
protected AuthorizationResource getAuthorizationResource() throws FileNotFoundException {
|
||||
return getClientResource(RESOURCE_SERVER_ID).authorization();
|
||||
}
|
||||
|
||||
protected ClientResource getClientResource(String clientId) {
|
||||
ClientsResource clients = this.realmsResouce().realm(REALM_NAME).clients();
|
||||
ClientRepresentation resourceServer = clients.findByClientId(clientId).get(0);
|
||||
return clients.get(resourceServer.getId());
|
||||
}
|
||||
|
||||
protected void loginToClientPage(UserRepresentation user, String... scopes) throws InterruptedException {
|
||||
log.debugf("--logging in as '%s' with password: '%s'; scopes: %s", user.getUsername(), user.getCredentials().get(0).getValue(), Arrays.toString(scopes));
|
||||
|
||||
if (testExecutor.isLoggedIn()) {
|
||||
testExecutor.logout(this::assertOnTestAppUrl, logoutConfirmPage);
|
||||
jsDriver.manage().deleteAllCookies();
|
||||
|
||||
jsDriver.navigate().to(testRealmLoginPage.toString());
|
||||
jsDriver.manage().deleteAllCookies();
|
||||
}
|
||||
|
||||
clientPage.navigateTo();
|
||||
testExecutor.init(defaultArguments(), this::assertInitNotAuth)
|
||||
.login(this::assertOnLoginPage)
|
||||
.loginFormWithScopesWithPossibleConsentPage(user, this::assertOnTestAppUrl, oAuthGrantPage, scopes)
|
||||
.init(defaultArguments(), this::assertSuccessfullyLoggedIn);
|
||||
|
||||
new WebDriverWait(jsDriver, 10).until(this::isLoaded);
|
||||
}
|
||||
|
||||
public boolean isLoaded(WebDriver w) {
|
||||
JavascriptExecutor jsExecutor = (JavascriptExecutor) w;
|
||||
|
||||
Map<String, Object> o = (Map<String, Object>) jsExecutor.executeScript("return window.authorization.config");
|
||||
|
||||
return o != null && o.containsKey("token_endpoint");
|
||||
}
|
||||
|
||||
protected void setManageAlbumScopeRequired() {
|
||||
ClientScopeRepresentation clientScope = new ClientScopeRepresentation();
|
||||
|
||||
clientScope.setName("manage-albums");
|
||||
clientScope.setProtocol("openid-connect");
|
||||
|
||||
ProtocolMapperRepresentation mapper = new ProtocolMapperRepresentation();
|
||||
|
||||
mapper.setName("manage-albums");
|
||||
mapper.setProtocol("openid-connect");
|
||||
mapper.setProtocolMapper(UserClientRoleMappingMapper.PROVIDER_ID);
|
||||
|
||||
Map<String, String> config = new HashMap<>();
|
||||
config.put("access.token.claim", "true");
|
||||
config.put("id.token.claim", "true");
|
||||
config.put("userinfo.token.claim", "true");
|
||||
config.put(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID, "photoz-restful-api");
|
||||
|
||||
mapper.setConfig(config);
|
||||
|
||||
clientScope.setProtocolMappers(Arrays.asList(mapper));
|
||||
|
||||
RealmResource realmResource = realmsResouce().realm(REALM_NAME);
|
||||
ClientScopesResource clientScopes = realmResource.clientScopes();
|
||||
Response resp = clientScopes.create(clientScope);
|
||||
Assert.assertEquals(201, resp.getStatus());
|
||||
resp.close();
|
||||
String clientScopeId = ApiUtil.getCreatedId(resp);
|
||||
ClientResource resourceServer = getClientResource(RESOURCE_SERVER_ID);
|
||||
clientScopes.get(clientScopeId).getScopeMappings().clientLevel(resourceServer.toRepresentation().getId()).add(Arrays.asList(resourceServer.roles().get("manage-albums").toRepresentation()));
|
||||
ClientResource html5ClientApp = getClientResource("photoz-html5-client");
|
||||
html5ClientApp.addOptionalClientScope(clientScopeId);
|
||||
html5ClientApp.getScopeMappings().realmLevel().add(Arrays.asList(realmResource.roles().get("user").toRepresentation(), realmResource.roles().get("admin").toRepresentation()));
|
||||
ClientRepresentation clientRep = html5ClientApp.toRepresentation();
|
||||
clientRep.setFullScopeAllowed(false);
|
||||
html5ClientApp.update(clientRep);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redeploy if duplicate resource is present.
|
||||
* KEYCLOAK-18442
|
||||
*
|
||||
* @param name Name of the deployment
|
||||
*/
|
||||
protected void deployIgnoreIfDuplicate(String name) {
|
||||
try {
|
||||
deployer.deploy(name);
|
||||
} catch (Exception e) {
|
||||
//DeploymentException is thrown by an deployer event handler and cannot be explicitly caught
|
||||
//noinspection ConstantConditions
|
||||
if (e instanceof DeploymentException && e.getMessage().contains("Duplicate resource")) {
|
||||
log.warnf("Duplicate resource '%s'. Trying to undeploy and deploy again...", name);
|
||||
deployer.undeploy(name);
|
||||
deployer.deploy(name);
|
||||
return;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,196 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 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.authz.adapter.example;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.testsuite.arquillian.annotation.DisableFeature;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
@DisableFeature(value = Profile.Feature.ACCOUNT2, skipRestart = true) // TODO remove this (KEYCLOAK-16228)
|
||||
public abstract class AbstractPhotozAccountResourcesAdapterTest extends AbstractBasePhotozExampleAdapterTest {
|
||||
|
||||
@Test
|
||||
public void testOwnerSharingResource() throws Exception {
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.createAlbum(ALICE_ALBUM_NAME, true);
|
||||
clientPage.accountShareResource(ALICE_ALBUM_NAME, "jdoe");
|
||||
|
||||
// get back to clientPage and init javascript adapter in order to log out correctly
|
||||
clientPage.navigateTo();
|
||||
testExecutor.init(defaultArguments(), this::assertInitNotAuth)
|
||||
.login()
|
||||
.init(defaultArguments(), this::assertSuccessfullyLoggedIn);
|
||||
|
||||
loginToClientPage(jdoeUser);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.createAlbum(ALICE_ALBUM_NAME, true);
|
||||
clientPage.accountShareRemoveScope(ALICE_ALBUM_NAME, "jdoe", "album:delete");
|
||||
|
||||
// get back to clientPage and init javascript adapter in order to log out correctly
|
||||
clientPage.navigateTo();
|
||||
testExecutor.init(defaultArguments(), this::assertInitNotAuth)
|
||||
.login(this::assertOnTestAppUrl)
|
||||
.init(defaultArguments(), this::assertSuccessfullyLoggedIn);
|
||||
|
||||
loginToClientPage(jdoeUser);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.accountRevokeResource(ALICE_ALBUM_NAME, "jdoe");
|
||||
|
||||
// get back to clientPage and init javascript adapter in order to log out correctly
|
||||
clientPage.navigateTo();
|
||||
testExecutor.init(defaultArguments(), this::assertInitNotAuth)
|
||||
.login()
|
||||
.init(defaultArguments(), this::assertSuccessfullyLoggedIn);
|
||||
|
||||
loginToClientPage(jdoeUser);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestResourceToOwner() throws Exception {
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.createAlbum(ALICE_ALBUM_NAME, true);
|
||||
|
||||
loginToClientPage(jdoeUser);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.accountGrantResource(ALICE_ALBUM_NAME, "jdoe");
|
||||
|
||||
// get back to clientPage and init javascript adapter in order to log out correctly
|
||||
clientPage.navigateTo();
|
||||
|
||||
testExecutor.init(defaultArguments(), this::assertInitNotAuth)
|
||||
.login()
|
||||
.init(defaultArguments(), this::assertSuccessfullyLoggedIn);
|
||||
|
||||
loginToClientPage(jdoeUser);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.createAlbum(ALICE_ALBUM_NAME, true);
|
||||
|
||||
loginToClientPage(jdoeUser);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.accountGrantRemoveScope(ALICE_ALBUM_NAME, "jdoe", "album:delete");
|
||||
|
||||
// get back to clientPage and init javascript adapter in order to navigate to accountPage again
|
||||
clientPage.navigateTo();
|
||||
testExecutor.init(defaultArguments(), this::assertInitNotAuth)
|
||||
.login(this::assertOnTestAppUrl)
|
||||
.init(defaultArguments(), this::assertSuccessfullyLoggedIn);
|
||||
clientPage.accountGrantResource(ALICE_ALBUM_NAME, "jdoe");
|
||||
|
||||
// get back to clientPage and init javascript adapter in order to log out correctly
|
||||
clientPage.navigateTo();
|
||||
testExecutor.init(defaultArguments(), this::assertInitNotAuth)
|
||||
.login()
|
||||
.init(defaultArguments(), this::assertSuccessfullyLoggedIn);
|
||||
|
||||
|
||||
loginToClientPage(jdoeUser);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCsrfGrantAccess() throws Exception {
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.createAlbum(ALICE_ALBUM_NAME, true);
|
||||
|
||||
loginToClientPage(jdoeUser);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
|
||||
clientPage.accountMyResources();
|
||||
clientPage.executeScript("document.forms[0].stateChecker.value = 'invalid'");
|
||||
clientPage.grantResource(ALICE_ALBUM_NAME, "jdoe");
|
||||
clientPage.assertError();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCsrfRevokeResource() throws Exception {
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.createAlbum(ALICE_ALBUM_NAME, true);
|
||||
|
||||
loginToClientPage(jdoeUser);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
|
||||
clientPage.accountGrantResource(ALICE_ALBUM_NAME, "jdoe");
|
||||
|
||||
clientPage.navigateTo();
|
||||
testExecutor.init(defaultArguments(), this::assertInitNotAuth)
|
||||
.login(this::assertOnTestAppUrl)
|
||||
.init(defaultArguments(), this::assertSuccessfullyLoggedIn);
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
clientPage.accountMyResource(ALICE_ALBUM_NAME);
|
||||
clientPage.executeScript("document.forms[0].stateChecker.value = 'invalid'");
|
||||
clientPage.revokeResource(ALICE_ALBUM_NAME, "jdoe");
|
||||
clientPage.assertError();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCrfCheckSharingResource() throws Exception {
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.createAlbum(ALICE_ALBUM_NAME, true);
|
||||
clientPage.accountMyResource(ALICE_ALBUM_NAME);
|
||||
|
||||
clientPage.executeScript("document.forms['shareForm'].stateChecker.value = 'invalid'");
|
||||
clientPage.shareResource("jdoe");
|
||||
clientPage.assertError();
|
||||
|
||||
clientPage.navigateTo();
|
||||
testExecutor.init(defaultArguments(), this::assertInitNotAuth)
|
||||
.login()
|
||||
.init(defaultArguments(), this::assertSuccessfullyLoggedIn);
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.accountMyResource(ALICE_ALBUM_NAME);
|
||||
clientPage.shareResource("jdoe");
|
||||
|
||||
clientPage.navigateTo();
|
||||
testExecutor.init(defaultArguments(), this::assertInitNotAuth)
|
||||
.login(this::assertOnTestAppUrl)
|
||||
.init(defaultArguments(), this::assertSuccessfullyLoggedIn);
|
||||
loginToClientPage(jdoeUser);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
}
|
||||
}
|
|
@ -1,477 +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.testsuite.authz.adapter.example;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.anyOf;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.AuthorizationResource;
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.admin.client.resource.PoliciesResource;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.admin.client.resource.ResourcesResource;
|
||||
import org.keycloak.admin.client.resource.RoleResource;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.admin.client.resource.UsersResource;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.testsuite.arquillian.annotation.UncaughtServerErrorExpected;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public abstract class AbstractPhotozExampleAdapterTest extends AbstractBasePhotozExampleAdapterTest {
|
||||
|
||||
@Test
|
||||
public void testUserCanCreateAndDeleteAlbum() throws Exception {
|
||||
loginToClientPage(aliceUser);
|
||||
|
||||
clientPage.createAlbum(ALICE_ALBUM_NAME);
|
||||
log.debug("Check if alice has resources stored");
|
||||
assertThat(getResourcesOfUser("alice"), is(not(empty())));
|
||||
|
||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
log.debug("Check if alice has resources deleted");
|
||||
assertThat(getResourcesOfUser("alice"), is(empty()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@UncaughtServerErrorExpected
|
||||
public void createAlbumWithInvalidUser() throws Exception {
|
||||
loginToClientPage(aliceUser);
|
||||
|
||||
clientPage.createAlbumWithInvalidUser(ALICE_ALBUM_NAME, response -> {
|
||||
assertThat(response.get("status"), is(equalTo(500L)));
|
||||
assertThat(response.get("res"), is(equalTo("Could not register protected resource.")));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathConfigInvalidation() throws Exception {
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.createAlbum(ALICE_ALBUM_NAME);
|
||||
|
||||
loginToClientPage(adminUser);
|
||||
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
||||
|
||||
log.debug("Check if alice has resources stored");
|
||||
assertThat(getResourcesOfUser("alice"), is(not(empty())));
|
||||
|
||||
log.debug("Adding applyPolicies \"Only Owner Policy\" to \"Delete Album Permission\" policies.");
|
||||
for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
|
||||
if ("Delete Album Permission".equals(policy.getName())) {
|
||||
policy.getConfig().put("applyPolicies", "[\"Only Owner Policy\"]");
|
||||
getAuthorizationResource().policies().policy(policy.getId()).update(policy);
|
||||
}
|
||||
}
|
||||
printUpdatedPolicies();
|
||||
|
||||
loginToClientPage(adminUser);
|
||||
|
||||
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||
|
||||
log.debug("Check if alice has resources stored");
|
||||
assertThat(getResourcesOfUser("alice"), is(not(empty())));
|
||||
|
||||
log.debug("Adding applyPolicies \"Only Owner and Administrators Policy\" to \"Delete Album Permission\" policies.");
|
||||
for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
|
||||
if ("Delete Album Permission".equals(policy.getName())) {
|
||||
policy.getConfig().put("applyPolicies", "[\"Only Owner and Administrators Policy\"]");
|
||||
getAuthorizationResource().policies().policy(policy.getId()).update(policy);
|
||||
}
|
||||
}
|
||||
printUpdatedPolicies();
|
||||
|
||||
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
|
||||
log.debug("Check if alice has resources deleted");
|
||||
assertThat(getResourcesOfUser("alice"), is(empty()));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRegularUserCanNotAccessAdminResources() throws Exception {
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.navigateToAdminAlbum(this::assertWasDenied);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAdminOnlyFromSpecificAddress() throws Exception {
|
||||
loginToClientPage(adminUser);
|
||||
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
||||
|
||||
log.debug("Changing codes \"127.0.0.1\" to \"127.3.3.3\" of \"Only From a Specific Client Address\" policies.");
|
||||
for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
|
||||
if ("Administration Policy".equals(policy.getName())) {
|
||||
policy.setPolicies(new HashSet<>());
|
||||
policy.getPolicies().add("Any Admin Policy");
|
||||
policy.getPolicies().add("Deny From a Specific Client Address");
|
||||
getAuthorizationResource().policies().policy(policy.getId()).update(policy);
|
||||
}
|
||||
}
|
||||
printUpdatedPolicies();
|
||||
|
||||
loginToClientPage(adminUser);
|
||||
clientPage.navigateToAdminAlbum(this::assertWasDenied);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAdminWithoutPermissionsToTypedResource() throws Exception {
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.createAlbum(ALICE_ALBUM_NAME);
|
||||
|
||||
loginToClientPage(adminUser);
|
||||
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
||||
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
|
||||
PoliciesResource policiesResource = getAuthorizationResource().policies();
|
||||
List<PolicyRepresentation> policies = policiesResource.policies();
|
||||
for (PolicyRepresentation policy : policies) {
|
||||
if ("Album Resource Permission".equals(policy.getName())) {
|
||||
policy.getConfig().put("applyPolicies", "[\"Any User Policy\"]");
|
||||
policiesResource.policy(policy.getId()).update(policy);
|
||||
}
|
||||
if ("Any User Policy".equals(policy.getName())) {
|
||||
ClientResource resourceServerClient = getClientResource(RESOURCE_SERVER_ID);
|
||||
RoleResource manageAlbumRole = resourceServerClient.roles().get("manage-albums");
|
||||
RoleRepresentation roleRepresentation = manageAlbumRole.toRepresentation();
|
||||
List<Map<String, Object>> roles = JsonSerialization.readValue(policy.getConfig().get("roles"), List.class);
|
||||
|
||||
roles = roles.stream().filter((Map map) -> !map.get("id").equals(roleRepresentation.getId())).collect(Collectors.toList());
|
||||
|
||||
policy.getConfig().put("roles", JsonSerialization.writeValueAsString(roles));
|
||||
|
||||
policiesResource.policy(policy.getId()).update(policy);
|
||||
}
|
||||
}
|
||||
printUpdatedPolicies();
|
||||
|
||||
loginToClientPage(adminUser); // Clear cache
|
||||
|
||||
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
||||
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||
|
||||
for (PolicyRepresentation policy : policies) {
|
||||
if ("Album Resource Permission".equals(policy.getName())) {
|
||||
policy.getConfig().put("applyPolicies", "[\"Any User Policy\", \"Administration Policy\"]");
|
||||
policiesResource.policy(policy.getId()).update(policy);
|
||||
}
|
||||
}
|
||||
printUpdatedPolicies();
|
||||
|
||||
loginToClientPage(adminUser); // Clear cache
|
||||
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
assertThat(getResourcesOfUser("alice"), is(empty()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAdminWithoutPermissionsToDeleteAlbum() throws Exception {
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.createAlbum(ALICE_ALBUM_NAME);
|
||||
|
||||
loginToClientPage(adminUser);
|
||||
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
|
||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
assertThat(getResourcesOfUser("alice"), is(empty()));
|
||||
|
||||
PoliciesResource policiesResource = getAuthorizationResource().policies();
|
||||
List<PolicyRepresentation> policies = policiesResource.policies();
|
||||
for (PolicyRepresentation policy : policies) {
|
||||
if ("Delete Album Permission".equals(policy.getName())) {
|
||||
policy.getConfig().put("applyPolicies", "[\"Only Owner Policy\"]");
|
||||
policiesResource.policy(policy.getId()).update(policy);
|
||||
}
|
||||
}
|
||||
printUpdatedPolicies();
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.createAlbum(ALICE_ALBUM_NAME);
|
||||
|
||||
loginToClientPage(adminUser);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
assertThat(getResourcesOfUser("alice"), is(not(empty())));
|
||||
|
||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||
|
||||
for (PolicyRepresentation policy : policies) {
|
||||
if ("Delete Album Permission".equals(policy.getName())) {
|
||||
policy.getConfig().put("applyPolicies", "[\"Only Owner and Administrators Policy\"]");
|
||||
policiesResource.policy(policy.getId()).update(policy);
|
||||
}
|
||||
}
|
||||
printUpdatedPolicies();
|
||||
|
||||
loginToClientPage(adminUser); // Clear cache
|
||||
|
||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
assertThat(getResourcesOfUser("alice"), is(empty()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientRoleRepresentingUserConsent() throws Exception {
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.createAlbum(ALICE_ALBUM_NAME);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
|
||||
RealmResource realmResource = realmsResouce().realm(REALM_NAME);
|
||||
UsersResource usersResource = realmResource.users();
|
||||
List<UserRepresentation> users = usersResource.search("alice", null, null, null, null, null);
|
||||
|
||||
assertFalse(users.isEmpty());
|
||||
|
||||
UserRepresentation userRepresentation = users.get(0);
|
||||
UserResource userResource = usersResource.get(userRepresentation.getId());
|
||||
|
||||
ClientResource html5ClientApp = getClientResource("photoz-html5-client");
|
||||
ClientRepresentation clientRepresentation = html5ClientApp.toRepresentation();
|
||||
|
||||
userResource.revokeConsent(clientRepresentation.getClientId());
|
||||
|
||||
setManageAlbumScopeRequired();
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||
|
||||
loginToClientPage(aliceUser, "manage-albums");
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientRoleNotRequired() throws Exception {
|
||||
loginToClientPage(aliceUser);
|
||||
|
||||
clientPage.createAlbum(ALICE_ALBUM_NAME);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
|
||||
UsersResource usersResource = realmsResouce().realm(REALM_NAME).users();
|
||||
List<UserRepresentation> users = usersResource.search("alice", null, null, null, null, null);
|
||||
|
||||
assertFalse(users.isEmpty());
|
||||
|
||||
UserRepresentation userRepresentation = users.get(0);
|
||||
UserResource userResource = usersResource.get(userRepresentation.getId());
|
||||
|
||||
ClientResource html5ClientApp = getClientResource("photoz-html5-client");
|
||||
|
||||
userResource.revokeConsent(html5ClientApp.toRepresentation().getClientId());
|
||||
|
||||
ClientResource resourceServerClient = getClientResource(RESOURCE_SERVER_ID);
|
||||
RoleResource manageAlbumRole = resourceServerClient.roles().get("manage-albums");
|
||||
RoleRepresentation roleRepresentation = manageAlbumRole.toRepresentation();
|
||||
|
||||
setManageAlbumScopeRequired();
|
||||
|
||||
manageAlbumRole.update(roleRepresentation);
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||
|
||||
for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
|
||||
if ("Any User Policy".equals(policy.getName())) {
|
||||
List<Map<String, Object>> roles = JsonSerialization.readValue(policy.getConfig().get("roles"), List.class);
|
||||
|
||||
roles.forEach(role -> {
|
||||
String roleId = (String) role.get("id");
|
||||
if (roleId.equals(manageAlbumRole.toRepresentation().getId())) {
|
||||
role.put("required", false);
|
||||
}
|
||||
});
|
||||
|
||||
policy.getConfig().put("roles", JsonSerialization.writeValueAsString(roles));
|
||||
getAuthorizationResource().policies().policy(policy.getId()).update(policy);
|
||||
}
|
||||
}
|
||||
printUpdatedPolicies();
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverridePermissionFromResourceParent() throws Exception {
|
||||
loginToClientPage(aliceUser);
|
||||
String resourceName = "My-Resource-Instance";
|
||||
clientPage.createAlbum(resourceName);
|
||||
|
||||
clientPage.viewAlbum(resourceName, this::assertWasNotDenied);
|
||||
clientPage.deleteAlbum(resourceName, this::assertWasNotDenied);
|
||||
|
||||
clientPage.createAlbum(resourceName);
|
||||
|
||||
loginToClientPage(adminUser);
|
||||
|
||||
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
||||
clientPage.viewAlbum(resourceName, this::assertWasNotDenied);
|
||||
clientPage.deleteAlbum(resourceName, this::assertWasNotDenied);
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.createAlbum(resourceName);
|
||||
|
||||
AuthorizationResource authorizationResource = getAuthorizationResource();
|
||||
authorizationResource.resources().resources().forEach(resource -> {
|
||||
if (resource.getName().equals(resourceName)) {
|
||||
try {
|
||||
PolicyRepresentation resourceInstancePermission = new PolicyRepresentation();
|
||||
|
||||
resourceInstancePermission.setName(resourceName + "Permission");
|
||||
resourceInstancePermission.setType("resource");
|
||||
|
||||
Map<String, String> config = new HashMap<>();
|
||||
|
||||
config.put("resources", JsonSerialization.writeValueAsString(Arrays.asList(resource.getId())));
|
||||
config.put("applyPolicies", JsonSerialization.writeValueAsString(Arrays.asList("Only Owner Policy")));
|
||||
|
||||
resourceInstancePermission.setConfig(config);
|
||||
authorizationResource.policies().create(resourceInstancePermission);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Error creating policy.", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
printUpdatedPolicies();
|
||||
|
||||
loginToClientPage(adminUser);
|
||||
|
||||
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
||||
clientPage.viewAlbum(resourceName, this::assertWasDenied);
|
||||
clientPage.deleteAlbum(resourceName, this::assertWasDenied);
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.deleteAlbum(resourceName, this::assertWasNotDenied);
|
||||
assertThat(getResourcesOfUser("alice"), is(empty()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInheritPermissionFromResourceParent() throws Exception {
|
||||
loginToClientPage(aliceUser);
|
||||
|
||||
final String RESOURCE_NAME = "My-Resource-Instance";
|
||||
clientPage.createAlbum(RESOURCE_NAME);
|
||||
clientPage.viewAlbum(RESOURCE_NAME, this::assertWasNotDenied);
|
||||
clientPage.deleteAlbum(RESOURCE_NAME, this::assertWasNotDenied);
|
||||
|
||||
clientPage.createAlbum(RESOURCE_NAME);
|
||||
|
||||
loginToClientPage(adminUser);
|
||||
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
||||
clientPage.viewAlbum(RESOURCE_NAME, this::assertWasNotDenied);
|
||||
clientPage.deleteAlbum(RESOURCE_NAME, this::assertWasNotDenied);
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.createAlbum(RESOURCE_NAME);
|
||||
|
||||
ResourcesResource resourcesResource = getAuthorizationResource().resources();
|
||||
resourcesResource.resources().forEach(resource -> {
|
||||
if (resource.getName().equals(RESOURCE_NAME)) {
|
||||
try {
|
||||
PolicyRepresentation resourceInstancePermission = new PolicyRepresentation();
|
||||
|
||||
resourceInstancePermission.setName(RESOURCE_NAME + "Permission");
|
||||
resourceInstancePermission.setType("resource");
|
||||
|
||||
Map<String, String> config = new HashMap<>();
|
||||
|
||||
config.put("resources", JsonSerialization.writeValueAsString(Arrays.asList(resource.getId())));
|
||||
config.put("applyPolicies", JsonSerialization.writeValueAsString(Arrays.asList("Only Owner Policy")));
|
||||
|
||||
resourceInstancePermission.setConfig(config);
|
||||
getAuthorizationResource().policies().create(resourceInstancePermission);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Error creating policy.", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
loginToClientPage(adminUser);
|
||||
|
||||
clientPage.viewAlbum(RESOURCE_NAME, this::assertWasDenied);
|
||||
clientPage.deleteAlbum(RESOURCE_NAME, this::assertWasDenied);
|
||||
|
||||
resourcesResource.resources().forEach(resource -> {
|
||||
if (resource.getName().equals(RESOURCE_NAME)) {
|
||||
resource.setScopes(resource.getScopes().stream().filter(scope -> !scope.getName().equals("album:view")).collect(Collectors.toSet()));
|
||||
resourcesResource.resource(resource.getId()).update(resource);
|
||||
}
|
||||
});
|
||||
|
||||
loginToClientPage(adminUser);
|
||||
|
||||
clientPage.viewAlbum(RESOURCE_NAME, this::assertWasNotDenied);
|
||||
clientPage.deleteAlbum(RESOURCE_NAME, this::assertWasDenied);
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
clientPage.deleteAlbum(RESOURCE_NAME, this::assertWasNotDenied);
|
||||
List<ResourceRepresentation> resources = resourcesResource.resources();
|
||||
assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
|
||||
}
|
||||
|
||||
//KEYCLOAK-3777
|
||||
|
||||
@Test
|
||||
public void testEntitlementRequest() throws Exception {
|
||||
loginToClientPage(adminUser);
|
||||
|
||||
clientPage.requestEntitlements((driver1, output, events) -> assertThat((String) output, containsString("admin:manage")));
|
||||
|
||||
loginToClientPage(adminUser);
|
||||
clientPage.requestEntitlement((driver1, output, events) -> {
|
||||
assertThat((String) output, not(containsString("admin:manage")));
|
||||
assertThat((String) output, containsString("album:view"));
|
||||
assertThat((String) output, containsString("album:delete"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResourceProtectedWithAnyScope() throws Exception {
|
||||
loginToClientPage(aliceUser);
|
||||
|
||||
clientPage.requestResourceProtectedAllScope(this::assertWasDenied);
|
||||
clientPage.requestResourceProtectedAnyScope(response -> {
|
||||
assertThat(response.get("status"), anyOf(is(equalTo(404L)), is(equalTo(0L)))); // PhantomJS returns 0 and chrome 404
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
package org.keycloak.testsuite.authz.adapter.example;
|
||||
|
||||
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.testsuite.Assert;
|
||||
import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
|
||||
import org.keycloak.testsuite.auth.page.login.OAuthGrant;
|
||||
import org.keycloak.testsuite.auth.page.login.OIDCLogin;
|
||||
import org.keycloak.testsuite.pages.LogoutConfirmPage;
|
||||
import org.keycloak.testsuite.util.JavascriptBrowser;
|
||||
import org.keycloak.testsuite.util.UserBuilder;
|
||||
import org.keycloak.testsuite.util.javascript.JSObjectBuilder;
|
||||
import org.keycloak.testsuite.util.javascript.JavascriptStateValidator;
|
||||
import org.keycloak.testsuite.util.javascript.ResponseValidator;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.keycloak.testsuite.util.ServerURLs.AUTH_SERVER_SSL_REQUIRED;
|
||||
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
||||
|
||||
/**
|
||||
* @author mhajas
|
||||
*/
|
||||
public abstract class AbstractPhotozJavascriptExecutorTest extends AbstractExampleAdapterTest {
|
||||
|
||||
@FunctionalInterface
|
||||
interface QuadFunction<T, U, V, W> {
|
||||
void apply(T a, U b, V c, W d);
|
||||
}
|
||||
|
||||
protected static final String REALM_NAME = "photoz";
|
||||
|
||||
@Page
|
||||
@JavascriptBrowser
|
||||
protected OIDCLogin jsDriverTestRealmLoginPage;
|
||||
|
||||
@Page
|
||||
@JavascriptBrowser
|
||||
protected LogoutConfirmPage logoutConfirmPage;
|
||||
|
||||
@Page
|
||||
@JavascriptBrowser
|
||||
private OAuthGrant oAuthGrantPage;
|
||||
|
||||
@Drone
|
||||
@JavascriptBrowser
|
||||
protected WebDriver jsDriver;
|
||||
|
||||
protected UserRepresentation aliceUser = UserBuilder.create().username("alice").password("alice").build();
|
||||
|
||||
protected UserRepresentation adminUser = UserBuilder.create().username("admin").password("admin").build();
|
||||
|
||||
protected UserRepresentation jdoeUser = UserBuilder.create().username("jdoe").password("jdoe").build();
|
||||
|
||||
@BeforeClass
|
||||
public static void checkIfTLSIsTurnedOn() {
|
||||
Assume.assumeTrue(AUTH_SERVER_SSL_REQUIRED);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setDefaultValues() {
|
||||
jsDriverTestRealmLoginPage.setAuthRealm(REALM_NAME);
|
||||
}
|
||||
|
||||
protected <T> JavascriptStateValidator buildFunction(QuadFunction<T, WebDriver, Object, WebElement> f, T x) {
|
||||
return (y,z,w) -> f.apply(x, y, z, w);
|
||||
}
|
||||
|
||||
public void assertOutputContains(String value, WebDriver driver1, Object output, WebElement events) {
|
||||
if (output instanceof WebElement) {
|
||||
waitUntilElement((WebElement) output).text().contains(value);
|
||||
} else {
|
||||
Assert.assertThat((String) output, containsString(value));
|
||||
}
|
||||
}
|
||||
|
||||
protected JSObjectBuilder defaultArguments() {
|
||||
return JSObjectBuilder.create().defaultSettings();
|
||||
}
|
||||
|
||||
protected void assertSuccessfullyLoggedIn(WebDriver driver1, Object output, WebElement events) {
|
||||
buildFunction(this::assertOutputContains, "Init Success (Authenticated)").validate(driver1, output, events);
|
||||
}
|
||||
|
||||
protected void assertInitNotAuth(WebDriver driver1, Object output, WebElement events) {
|
||||
buildFunction(this::assertOutputContains, "Init Success (Not Authenticated)").validate(driver1, output, events);
|
||||
}
|
||||
|
||||
protected void assertOnLoginPage(WebDriver driver1, Object output, WebElement events) {
|
||||
waitUntilElement(By.tagName("body")).is().present();
|
||||
try {
|
||||
assertCurrentUrlStartsWith(jsDriverTestRealmLoginPage, driver1);
|
||||
} catch (AssertionError e) {
|
||||
System.out.println("Test");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
protected JavascriptStateValidator all(JavascriptStateValidator[] toValidate) {
|
||||
return ((driver1, output, events) -> {
|
||||
for (JavascriptStateValidator val : toValidate) {
|
||||
val.validate(driver1, output, events);
|
||||
}
|
||||
});
|
||||
}
|
||||
protected ResponseValidator all(ResponseValidator[] toValidate) {
|
||||
return ((response) -> {
|
||||
for (ResponseValidator val : toValidate) {
|
||||
val.validate(response);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,180 +0,0 @@
|
|||
/*
|
||||
* Copyright 2018 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.testsuite.authz.adapter.example;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.keycloak.testsuite.utils.io.IOUtil.loadRealm;
|
||||
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.jboss.arquillian.container.test.api.Deployment;
|
||||
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.AuthorizationResource;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.testsuite.adapter.page.PhotozClientAuthzTestApp;
|
||||
import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
|
||||
import org.keycloak.testsuite.util.javascript.ResponseValidator;
|
||||
import org.keycloak.testsuite.utils.arquillian.ContainerConstants;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_WILDFLY)
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_EAP)
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_EAP6)
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_EAP71)
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_UNDERTOW)
|
||||
public class LifespanAdapterTest extends AbstractPhotozExampleAdapterTest {
|
||||
|
||||
@Deployment(name = PhotozClientAuthzTestApp.DEPLOYMENT_NAME)
|
||||
public static WebArchive deploymentClient() throws IOException {
|
||||
return exampleDeployment(PhotozClientAuthzTestApp.DEPLOYMENT_NAME);
|
||||
}
|
||||
|
||||
@Deployment(name = RESOURCE_SERVER_ID, managed = false, testable = false)
|
||||
public static WebArchive deploymentResourceServer() throws IOException {
|
||||
return exampleDeployment(RESOURCE_SERVER_ID,
|
||||
webArchive -> webArchive.addAsWebInfResource(new File(TEST_APPS_HOME_DIR + "/photoz/keycloak-cache-lifespan-authz-service.json"), "keycloak.json"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
|
||||
RealmRepresentation realm = loadRealm(new File(TEST_APPS_HOME_DIR + "/photoz/photoz-realm.json"));
|
||||
realm.setAccessTokenLifespan(70); // must increase lifespan of access token in order to use bigger offset in test cases
|
||||
testRealms.add(realm);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathConfigInvalidation() throws Exception {
|
||||
loginToClientPage(aliceUser);
|
||||
assertSuccess();
|
||||
|
||||
ResourceRepresentation resource = getAuthorizationResource().resources().findByName("Profile Resource").get(0);
|
||||
AuthorizationResource authorizationResource = getAuthorizationResource();
|
||||
|
||||
authorizationResource.resources().resource(resource.getId()).remove();
|
||||
assertThat(getAuthorizationResource().resources().findByName("Profile Resource").isEmpty(), Matchers.is(true));
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
|
||||
// should throw an error because the resource was removed and cache entry did not expire yet
|
||||
assertFailure();
|
||||
|
||||
setTimeOffsetOfAdapter(40);
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
assertSuccess();
|
||||
setTimeOffsetOfAdapter(0);
|
||||
|
||||
try (Response response = authorizationResource.resources().create(resource)) {
|
||||
resource = response.readEntity(ResourceRepresentation.class);
|
||||
}
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
assertSuccess();
|
||||
|
||||
RealmResource realm = this.realmsResouce().realm(REALM_NAME);
|
||||
UserRepresentation userRepresentation = realm.users().search(aliceUser.getUsername()).get(0);
|
||||
UserResource userResource = realm.users().get(userRepresentation.getId());
|
||||
|
||||
userRepresentation.setEmail("alice@anotherdomain.org");
|
||||
|
||||
userResource.update(userRepresentation);
|
||||
loginToClientPage(aliceUser);
|
||||
assertTicket();
|
||||
|
||||
try {
|
||||
PolicyRepresentation resourceInstancePermission = new PolicyRepresentation();
|
||||
|
||||
resourceInstancePermission.setName("View User Permission");
|
||||
resourceInstancePermission.setType("resource");
|
||||
|
||||
Map<String, String> config = new HashMap<>();
|
||||
|
||||
config.put("resources", JsonSerialization.writeValueAsString(Collections.singletonList(resource.getId())));
|
||||
config.put("applyPolicies", JsonSerialization.writeValueAsString(Collections.singletonList("Only From @keycloak.org or Admin")));
|
||||
|
||||
resourceInstancePermission.setConfig(config);
|
||||
authorizationResource.policies().create(resourceInstancePermission);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Error creating policy.", e);
|
||||
}
|
||||
|
||||
loginToClientPage(aliceUser);
|
||||
// should throw an error because the resource was removed and cache entry did not expire yet
|
||||
assertFailure();
|
||||
|
||||
userRepresentation.setEmail("alice@keycloak.org");
|
||||
|
||||
userResource.update(userRepresentation);
|
||||
loginToClientPage(aliceUser);
|
||||
assertSuccess();
|
||||
}
|
||||
|
||||
private void assertSuccess() {
|
||||
assertState(true);
|
||||
}
|
||||
|
||||
private void assertFailure() {
|
||||
assertState(false);
|
||||
}
|
||||
|
||||
private void assertState(boolean state) {
|
||||
clientPage.viewProfile((ResponseValidator) response -> {
|
||||
Object res = response.get("res");
|
||||
assertThat(res, Matchers.notNullValue());
|
||||
Matcher<String> matcher = Matchers.containsString("userName");
|
||||
assertThat(res.toString(), state ? matcher : Matchers.not(matcher));
|
||||
});
|
||||
}
|
||||
|
||||
private void assertTicket() {
|
||||
clientPage.viewProfile((ResponseValidator) response -> {
|
||||
Object headers = response.get("responseHeaders");
|
||||
assertThat(headers, Matchers.notNullValue());
|
||||
|
||||
List<String> headersList = Arrays.asList(headers.toString().split("\r\n"));
|
||||
String wwwAuthenticate = headersList.stream()
|
||||
.filter(s -> s.toLowerCase().startsWith("www-authenticate:"))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
assertThat(wwwAuthenticate, Matchers.notNullValue());
|
||||
assertThat(wwwAuthenticate, Matchers.containsString("UMA"));
|
||||
});
|
||||
}
|
||||
|
||||
public void setTimeOffsetOfAdapter(int offset) {
|
||||
this.driver.navigate().to(clientPage.getInjectedUrl() + "timeOffset.jsp?offset=" + offset);
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Copyright 2019 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.authz.adapter.example;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.jboss.arquillian.container.test.api.Deployment;
|
||||
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||
import org.keycloak.testsuite.adapter.page.PhotozClientAuthzTestApp;
|
||||
import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
|
||||
import org.keycloak.testsuite.utils.arquillian.ContainerConstants;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_WILDFLY)
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_EAP)
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_EAP6)
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_EAP71)
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_UNDERTOW)
|
||||
public class PhotozAccountResourcesAdapterTest extends AbstractPhotozAccountResourcesAdapterTest {
|
||||
|
||||
@Deployment(name = PhotozClientAuthzTestApp.DEPLOYMENT_NAME)
|
||||
public static WebArchive deploymentClient() throws IOException {
|
||||
return exampleDeployment(PhotozClientAuthzTestApp.DEPLOYMENT_NAME);
|
||||
}
|
||||
|
||||
@Deployment(name = RESOURCE_SERVER_ID, managed = false, testable = false)
|
||||
public static WebArchive deploymentResourceServer() throws IOException {
|
||||
return exampleDeployment(RESOURCE_SERVER_ID,
|
||||
webArchive -> webArchive.addAsWebInfResource(new File(TEST_APPS_HOME_DIR + "/photoz/keycloak-lazy-load-path-authz-service.json"), "keycloak.json"));
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Copyright 2018 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.testsuite.authz.adapter.example;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import org.jboss.arquillian.container.test.api.Deployment;
|
||||
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||
import org.keycloak.testsuite.adapter.page.PhotozClientAuthzTestApp;
|
||||
import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
|
||||
import org.keycloak.testsuite.utils.arquillian.ContainerConstants;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_WILDFLY)
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_EAP)
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_EAP6)
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_EAP71)
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_UNDERTOW)
|
||||
public class PhotozExampleLazyLoadPathsAdapterTest extends AbstractPhotozExampleAdapterTest {
|
||||
|
||||
@Deployment(name = PhotozClientAuthzTestApp.DEPLOYMENT_NAME)
|
||||
public static WebArchive deploymentClient() throws IOException {
|
||||
return exampleDeployment(PhotozClientAuthzTestApp.DEPLOYMENT_NAME);
|
||||
}
|
||||
|
||||
@Deployment(name = RESOURCE_SERVER_ID, managed = false, testable = false)
|
||||
public static WebArchive deploymentResourceServer() throws IOException {
|
||||
return exampleDeployment(RESOURCE_SERVER_ID,
|
||||
webArchive -> webArchive.addAsWebInfResource(new File(TEST_APPS_HOME_DIR + "/photoz/keycloak-lazy-load-path-authz-service.json"), "keycloak.json"));
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* Copyright 2018 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.testsuite.authz.adapter.example;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.jboss.arquillian.container.test.api.Deployment;
|
||||
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||
import org.keycloak.testsuite.adapter.page.PhotozClientAuthzTestApp;
|
||||
import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
|
||||
import org.keycloak.testsuite.utils.arquillian.ContainerConstants;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_WILDFLY)
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_EAP)
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_EAP6)
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_EAP71)
|
||||
@AppServerContainer(ContainerConstants.APP_SERVER_UNDERTOW)
|
||||
public class PhotozExampleNoLazyLoadPathsAdapterTest extends AbstractPhotozExampleAdapterTest {
|
||||
|
||||
@Deployment(name = PhotozClientAuthzTestApp.DEPLOYMENT_NAME)
|
||||
public static WebArchive deploymentClient() throws IOException {
|
||||
return exampleDeployment(PhotozClientAuthzTestApp.DEPLOYMENT_NAME);
|
||||
}
|
||||
|
||||
@Deployment(name = RESOURCE_SERVER_ID, managed = false, testable = false)
|
||||
public static WebArchive deploymentResourceServer() throws IOException {
|
||||
return exampleDeployment(RESOURCE_SERVER_ID);
|
||||
}
|
||||
|
||||
}
|
|
@ -271,18 +271,6 @@
|
|||
<version>${project.version}</version>
|
||||
<type>war</type>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.keycloak.testsuite</groupId>
|
||||
<artifactId>photoz-html5-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>war</type>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.keycloak.testsuite</groupId>
|
||||
<artifactId>photoz-restful-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>war</type>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.keycloak.testsuite</groupId>
|
||||
<artifactId>servlet-authz-app</artifactId>
|
||||
|
|
|
@ -348,18 +348,6 @@
|
|||
<version>${project.version}</version>
|
||||
<type>war</type>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.keycloak.testsuite</groupId>
|
||||
<artifactId>photoz-html5-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>war</type>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.keycloak.testsuite</groupId>
|
||||
<artifactId>photoz-restful-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>war</type>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.keycloak.testsuite</groupId>
|
||||
<artifactId>servlet-authz-app</artifactId>
|
||||
|
|
Loading…
Reference in a new issue