[KEYCLOAK-11154] - Unstable Photoz Adapter Tests
This commit is contained in:
parent
78ee5adfe8
commit
3f2a38936c
5 changed files with 496 additions and 391 deletions
|
@ -188,7 +188,6 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
|
||||||
|
|
||||||
public void accountPage() {
|
public void accountPage() {
|
||||||
testExecutor.openAccountPage(null);
|
testExecutor.openAccountPage(null);
|
||||||
waitForPageToLoad();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void accountMyResources() {
|
public void accountMyResources() {
|
||||||
|
@ -196,7 +195,6 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
|
||||||
WebElement myResources = driver.findElement(By.xpath("//a[text() = 'My Resources']"));
|
WebElement myResources = driver.findElement(By.xpath("//a[text() = 'My Resources']"));
|
||||||
waitUntilElement(myResources).is().clickable();
|
waitUntilElement(myResources).is().clickable();
|
||||||
myResources.click();
|
myResources.click();
|
||||||
waitForPageToLoad();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void accountMyResource(String name) {
|
public void accountMyResource(String name) {
|
||||||
|
@ -204,7 +202,6 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
|
||||||
WebElement myResource = driver.findElement(By.id("detail-" + name));
|
WebElement myResource = driver.findElement(By.id("detail-" + name));
|
||||||
waitUntilElement(myResource).is().clickable();
|
waitUntilElement(myResource).is().clickable();
|
||||||
myResource.click();
|
myResource.click();
|
||||||
waitForPageToLoad();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void accountGrantResource(String name, String requester) {
|
public void accountGrantResource(String name, String requester) {
|
||||||
|
@ -212,7 +209,6 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
|
||||||
WebElement grantResource = driver.findElement(By.id("grant-" + name + "-" + requester));
|
WebElement grantResource = driver.findElement(By.id("grant-" + name + "-" + requester));
|
||||||
waitUntilElement(grantResource).is().clickable();
|
waitUntilElement(grantResource).is().clickable();
|
||||||
grantResource.click();
|
grantResource.click();
|
||||||
waitForPageToLoad();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void accountGrantRemoveScope(String name, String requester, String scope) {
|
public void accountGrantRemoveScope(String name, String requester, String scope) {
|
||||||
|
@ -220,7 +216,6 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
|
||||||
WebElement grantRemoveScope = driver.findElement(By.id("grant-remove-scope-" + name + "-" + requester + "-" + scope));
|
WebElement grantRemoveScope = driver.findElement(By.id("grant-remove-scope-" + name + "-" + requester + "-" + scope));
|
||||||
waitUntilElement(grantRemoveScope).is().clickable();
|
waitUntilElement(grantRemoveScope).is().clickable();
|
||||||
grantRemoveScope.click();
|
grantRemoveScope.click();
|
||||||
waitForPageToLoad();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void accountRevokeResource(String name, String requester) {
|
public void accountRevokeResource(String name, String requester) {
|
||||||
|
@ -228,7 +223,6 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
|
||||||
WebElement revokeResource = driver.findElement(By.id("revoke-" + name + "-" + requester));
|
WebElement revokeResource = driver.findElement(By.id("revoke-" + name + "-" + requester));
|
||||||
waitUntilElement(revokeResource).is().clickable();
|
waitUntilElement(revokeResource).is().clickable();
|
||||||
revokeResource.click();
|
revokeResource.click();
|
||||||
waitForPageToLoad();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void accountShareResource(String name, String user) {
|
public void accountShareResource(String name, String user) {
|
||||||
|
@ -241,7 +235,6 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
|
||||||
WebElement shareButton = driver.findElement(By.id("share-button"));
|
WebElement shareButton = driver.findElement(By.id("share-button"));
|
||||||
waitUntilElement(shareButton).is().clickable();
|
waitUntilElement(shareButton).is().clickable();
|
||||||
shareButton.click();
|
shareButton.click();
|
||||||
waitForPageToLoad();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void accountShareRemoveScope(String name, String user, String scope) {
|
public void accountShareRemoveScope(String name, String user, String scope) {
|
||||||
|
@ -255,13 +248,10 @@ public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
|
||||||
WebElement shareRemoveScope = driver.findElement(By.id("share-remove-scope-" + name + "-" + scope));
|
WebElement shareRemoveScope = driver.findElement(By.id("share-remove-scope-" + name + "-" + scope));
|
||||||
waitUntilElement(shareRemoveScope).is().clickable();
|
waitUntilElement(shareRemoveScope).is().clickable();
|
||||||
shareRemoveScope.click();
|
shareRemoveScope.click();
|
||||||
waitForPageToLoad();
|
|
||||||
|
|
||||||
WebElement shareButton = driver.findElement(By.id("share-button"));
|
WebElement shareButton = driver.findElement(By.id("share-button"));
|
||||||
waitUntilElement(shareButton).is().clickable();
|
waitUntilElement(shareButton).is().clickable();
|
||||||
shareButton.click();
|
shareButton.click();
|
||||||
|
|
||||||
waitForPageToLoad();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void accountDenyResource(String name) {
|
public void accountDenyResource(String name) {
|
||||||
|
|
|
@ -0,0 +1,287 @@
|
||||||
|
/*
|
||||||
|
* 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.adapter.example.authorization;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
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 javax.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.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.Test;
|
||||||
|
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.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.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.RoleRepresentation;
|
||||||
|
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.adapter.page.PhotozClientAuthzTestApp;
|
||||||
|
import org.keycloak.testsuite.admin.ApiUtil;
|
||||||
|
import org.keycloak.testsuite.arquillian.AppServerTestEnricher;
|
||||||
|
import org.keycloak.testsuite.arquillian.annotation.UncaughtServerErrorExpected;
|
||||||
|
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.keycloak.util.JsonSerialization;
|
||||||
|
import org.openqa.selenium.JavascriptExecutor;
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefaultPageUriParameters() {
|
||||||
|
super.setDefaultPageUriParameters();
|
||||||
|
testRealmPage.setAuthRealm(REALM_NAME);
|
||||||
|
oAuthGrantPage.setAuthRealm(REALM_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void beforePhotozExampleAdapterTest() throws Exception {
|
||||||
|
DroneUtils.addWebDriver(jsDriver);
|
||||||
|
this.deployer.deploy(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")).isEqualTo(401L);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void assertWasNotDenied(Map<String, Object> response) {
|
||||||
|
assertThat(response.get("status")).isEqualTo(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 {0} with password: {1}; scopes: {2}", user.getUsername(), user.getCredentials().get(0).getValue(), Arrays.toString(scopes));
|
||||||
|
|
||||||
|
if (testExecutor.isLoggedIn()) {
|
||||||
|
testExecutor.logout(this::assertOnTestAppUrl);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
* 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.adapter.example.authorization;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,193 +16,39 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.adapter.example.authorization;
|
package org.keycloak.testsuite.adapter.example.authorization;
|
||||||
|
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import static org.junit.Assert.assertFalse;
|
||||||
import org.apache.http.impl.client.HttpClientBuilder;
|
import static org.junit.Assert.assertTrue;
|
||||||
import org.apache.http.impl.client.LaxRedirectStrategy;
|
|
||||||
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.Test;
|
|
||||||
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.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.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.RoleRepresentation;
|
|
||||||
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.adapter.page.PhotozClientAuthzTestApp;
|
|
||||||
import org.keycloak.testsuite.admin.ApiUtil;
|
|
||||||
import org.keycloak.testsuite.arquillian.AppServerTestEnricher;
|
|
||||||
import org.keycloak.testsuite.arquillian.annotation.UncaughtServerErrorExpected;
|
|
||||||
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.keycloak.util.JsonSerialization;
|
|
||||||
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;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import org.junit.Test;
|
||||||
import static org.junit.Assert.assertFalse;
|
import org.keycloak.admin.client.resource.AuthorizationResource;
|
||||||
import static org.junit.Assert.assertTrue;
|
import org.keycloak.admin.client.resource.ClientResource;
|
||||||
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
|
import org.keycloak.admin.client.resource.PoliciesResource;
|
||||||
import static org.keycloak.testsuite.utils.io.IOUtil.loadJson;
|
import org.keycloak.admin.client.resource.RealmResource;
|
||||||
import static org.keycloak.testsuite.utils.io.IOUtil.loadRealm;
|
import org.keycloak.admin.client.resource.ResourcesResource;
|
||||||
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
|
import org.keycloak.admin.client.resource.RoleResource;
|
||||||
|
import org.keycloak.admin.client.resource.UserResource;
|
||||||
import javax.ws.rs.core.Response;
|
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>
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractPhotozExampleAdapterTest extends AbstractPhotozJavascriptExecutorTest {
|
public abstract class AbstractPhotozExampleAdapterTest extends AbstractBasePhotozExampleAdapterTest {
|
||||||
|
|
||||||
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
|
|
||||||
private PhotozClientAuthzTestApp clientPage;
|
|
||||||
|
|
||||||
@Page
|
|
||||||
@JavascriptBrowser
|
|
||||||
private OAuthGrant oAuthGrantPage;
|
|
||||||
|
|
||||||
private JavascriptTestExecutorWithAuthorization testExecutor;
|
|
||||||
|
|
||||||
@FindBy(id = "output")
|
|
||||||
@JavascriptBrowser
|
|
||||||
protected WebElement outputArea;
|
|
||||||
|
|
||||||
@FindBy(id = "events")
|
|
||||||
@JavascriptBrowser
|
|
||||||
protected WebElement eventsArea;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setDefaultPageUriParameters() {
|
|
||||||
super.setDefaultPageUriParameters();
|
|
||||||
testRealmPage.setAuthRealm(REALM_NAME);
|
|
||||||
oAuthGrantPage.setAuthRealm(REALM_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void beforePhotozExampleAdapterTest() throws Exception {
|
|
||||||
DroneUtils.addWebDriver(jsDriver);
|
|
||||||
this.deployer.deploy(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();
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<ResourceRepresentation> getResourcesOfUser(String username) throws FileNotFoundException {
|
|
||||||
return getAuthorizationResource().resources().resources().stream().filter(resource -> resource.getOwner().getName().equals(username)).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
private 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("------------------------------");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertOnTestAppUrl(WebDriver jsDriver, Object output, WebElement events) {
|
|
||||||
waitForPageToLoad();
|
|
||||||
assertCurrentUrlStartsWith(clientPage.toString(), jsDriver);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertWasDenied(Map<String, Object> response) {
|
|
||||||
assertThat(response.get("status")).isEqualTo(401L);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertWasNotDenied(Map<String, Object> response) {
|
|
||||||
assertThat(response.get("status")).isEqualTo(200L);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUserCanCreateAndDeleteAlbum() throws Exception {
|
public void testUserCanCreateAndDeleteAlbum() throws Exception {
|
||||||
loginToClientPage(aliceUser);
|
loginToClientPage(aliceUser);
|
||||||
|
@ -309,10 +155,12 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractPhotozJav
|
||||||
|
|
||||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||||
|
|
||||||
for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
|
PoliciesResource policiesResource = getAuthorizationResource().policies();
|
||||||
|
List<PolicyRepresentation> policies = policiesResource.policies();
|
||||||
|
for (PolicyRepresentation policy : policies) {
|
||||||
if ("Album Resource Permission".equals(policy.getName())) {
|
if ("Album Resource Permission".equals(policy.getName())) {
|
||||||
policy.getConfig().put("applyPolicies", "[\"Any User Policy\"]");
|
policy.getConfig().put("applyPolicies", "[\"Any User Policy\"]");
|
||||||
getAuthorizationResource().policies().policy(policy.getId()).update(policy);
|
policiesResource.policy(policy.getId()).update(policy);
|
||||||
}
|
}
|
||||||
if ("Any User Policy".equals(policy.getName())) {
|
if ("Any User Policy".equals(policy.getName())) {
|
||||||
ClientResource resourceServerClient = getClientResource(RESOURCE_SERVER_ID);
|
ClientResource resourceServerClient = getClientResource(RESOURCE_SERVER_ID);
|
||||||
|
@ -324,7 +172,7 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractPhotozJav
|
||||||
|
|
||||||
policy.getConfig().put("roles", JsonSerialization.writeValueAsString(roles));
|
policy.getConfig().put("roles", JsonSerialization.writeValueAsString(roles));
|
||||||
|
|
||||||
getAuthorizationResource().policies().policy(policy.getId()).update(policy);
|
policiesResource.policy(policy.getId()).update(policy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printUpdatedPolicies();
|
printUpdatedPolicies();
|
||||||
|
@ -334,23 +182,19 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractPhotozJav
|
||||||
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
||||||
|
|
||||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||||
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
|
||||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||||
|
|
||||||
for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
|
for (PolicyRepresentation policy : policies) {
|
||||||
if ("Album Resource Permission".equals(policy.getName())) {
|
if ("Album Resource Permission".equals(policy.getName())) {
|
||||||
policy.getConfig().put("applyPolicies", "[\"Any User Policy\", \"Administration Policy\"]");
|
policy.getConfig().put("applyPolicies", "[\"Any User Policy\", \"Administration Policy\"]");
|
||||||
getAuthorizationResource().policies().policy(policy.getId()).update(policy);
|
policiesResource.policy(policy.getId()).update(policy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printUpdatedPolicies();
|
printUpdatedPolicies();
|
||||||
|
|
||||||
loginToClientPage(adminUser); // Clear cache
|
loginToClientPage(adminUser); // Clear cache
|
||||||
|
|
||||||
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
|
||||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||||
|
|
||||||
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
|
||||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||||
assertThat(getResourcesOfUser("alice")).isEmpty();
|
assertThat(getResourcesOfUser("alice")).isEmpty();
|
||||||
}
|
}
|
||||||
|
@ -366,11 +210,13 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractPhotozJav
|
||||||
|
|
||||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||||
assertThat(getResourcesOfUser("alice")).isEmpty();
|
assertThat(getResourcesOfUser("alice")).isEmpty();
|
||||||
|
|
||||||
for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
|
PoliciesResource policiesResource = getAuthorizationResource().policies();
|
||||||
|
List<PolicyRepresentation> policies = policiesResource.policies();
|
||||||
|
for (PolicyRepresentation policy : policies) {
|
||||||
if ("Delete Album Permission".equals(policy.getName())) {
|
if ("Delete Album Permission".equals(policy.getName())) {
|
||||||
policy.getConfig().put("applyPolicies", "[\"Only Owner Policy\"]");
|
policy.getConfig().put("applyPolicies", "[\"Only Owner Policy\"]");
|
||||||
getAuthorizationResource().policies().policy(policy.getId()).update(policy);
|
policiesResource.policy(policy.getId()).update(policy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printUpdatedPolicies();
|
printUpdatedPolicies();
|
||||||
|
@ -379,24 +225,21 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractPhotozJav
|
||||||
clientPage.createAlbum(ALICE_ALBUM_NAME);
|
clientPage.createAlbum(ALICE_ALBUM_NAME);
|
||||||
|
|
||||||
loginToClientPage(adminUser);
|
loginToClientPage(adminUser);
|
||||||
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
|
||||||
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
clientPage.viewAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||||
assertThat(getResourcesOfUser("alice")).isNotEmpty();
|
assertThat(getResourcesOfUser("alice")).isNotEmpty();
|
||||||
|
|
||||||
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
|
||||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasDenied);
|
||||||
|
|
||||||
for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
|
for (PolicyRepresentation policy : policies) {
|
||||||
if ("Delete Album Permission".equals(policy.getName())) {
|
if ("Delete Album Permission".equals(policy.getName())) {
|
||||||
policy.getConfig().put("applyPolicies", "[\"Only Owner and Administrators Policy\"]");
|
policy.getConfig().put("applyPolicies", "[\"Only Owner and Administrators Policy\"]");
|
||||||
getAuthorizationResource().policies().policy(policy.getId()).update(policy);
|
policiesResource.policy(policy.getId()).update(policy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printUpdatedPolicies();
|
printUpdatedPolicies();
|
||||||
|
|
||||||
loginToClientPage(adminUser); // Clear cache
|
loginToClientPage(adminUser); // Clear cache
|
||||||
|
|
||||||
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
|
||||||
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
clientPage.deleteAlbum(ALICE_ALBUM_NAME, this::assertWasNotDenied);
|
||||||
assertThat(getResourcesOfUser("alice")).isEmpty();
|
assertThat(getResourcesOfUser("alice")).isEmpty();
|
||||||
}
|
}
|
||||||
|
@ -501,7 +344,8 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractPhotozJav
|
||||||
loginToClientPage(aliceUser);
|
loginToClientPage(aliceUser);
|
||||||
clientPage.createAlbum(resourceName);
|
clientPage.createAlbum(resourceName);
|
||||||
|
|
||||||
getAuthorizationResource().resources().resources().forEach(resource -> {
|
AuthorizationResource authorizationResource = getAuthorizationResource();
|
||||||
|
authorizationResource.resources().resources().forEach(resource -> {
|
||||||
if (resource.getName().equals(resourceName)) {
|
if (resource.getName().equals(resourceName)) {
|
||||||
try {
|
try {
|
||||||
PolicyRepresentation resourceInstancePermission = new PolicyRepresentation();
|
PolicyRepresentation resourceInstancePermission = new PolicyRepresentation();
|
||||||
|
@ -515,7 +359,7 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractPhotozJav
|
||||||
config.put("applyPolicies", JsonSerialization.writeValueAsString(Arrays.asList("Only Owner Policy")));
|
config.put("applyPolicies", JsonSerialization.writeValueAsString(Arrays.asList("Only Owner Policy")));
|
||||||
|
|
||||||
resourceInstancePermission.setConfig(config);
|
resourceInstancePermission.setConfig(config);
|
||||||
getAuthorizationResource().policies().create(resourceInstancePermission);
|
authorizationResource.policies().create(resourceInstancePermission);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException("Error creating policy.", e);
|
throw new RuntimeException("Error creating policy.", e);
|
||||||
}
|
}
|
||||||
|
@ -577,7 +421,6 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractPhotozJav
|
||||||
|
|
||||||
loginToClientPage(adminUser);
|
loginToClientPage(adminUser);
|
||||||
|
|
||||||
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
|
||||||
clientPage.viewAlbum(RESOURCE_NAME, this::assertWasDenied);
|
clientPage.viewAlbum(RESOURCE_NAME, this::assertWasDenied);
|
||||||
clientPage.deleteAlbum(RESOURCE_NAME, this::assertWasDenied);
|
clientPage.deleteAlbum(RESOURCE_NAME, this::assertWasDenied);
|
||||||
|
|
||||||
|
@ -590,7 +433,6 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractPhotozJav
|
||||||
|
|
||||||
loginToClientPage(adminUser);
|
loginToClientPage(adminUser);
|
||||||
|
|
||||||
clientPage.navigateToAdminAlbum(this::assertWasNotDenied);
|
|
||||||
clientPage.viewAlbum(RESOURCE_NAME, this::assertWasNotDenied);
|
clientPage.viewAlbum(RESOURCE_NAME, this::assertWasNotDenied);
|
||||||
clientPage.deleteAlbum(RESOURCE_NAME, this::assertWasDenied);
|
clientPage.deleteAlbum(RESOURCE_NAME, this::assertWasDenied);
|
||||||
|
|
||||||
|
@ -606,10 +448,10 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractPhotozJav
|
||||||
public void testEntitlementRequest() throws Exception {
|
public void testEntitlementRequest() throws Exception {
|
||||||
loginToClientPage(adminUser);
|
loginToClientPage(adminUser);
|
||||||
|
|
||||||
clientPage.requestEntitlements((driver1, output, events) -> assertThat((String)output).contains("admin:manage"));
|
clientPage.requestEntitlements((driver1, output, events) -> assertThat((String) output).contains("admin:manage"));
|
||||||
|
|
||||||
loginToClientPage(adminUser);
|
loginToClientPage(adminUser);
|
||||||
clientPage.requestEntitlement((driver1, output, events) -> assertThat((String)output)
|
clientPage.requestEntitlement((driver1, output, events) -> assertThat((String) output)
|
||||||
.doesNotContain("admin:manage")
|
.doesNotContain("admin:manage")
|
||||||
.contains("album:view")
|
.contains("album:view")
|
||||||
.contains("album:delete")
|
.contains("album:delete")
|
||||||
|
@ -625,187 +467,4 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractPhotozJav
|
||||||
assertThat(response.get("status")).isIn(404L, 0L); // PhantomJS returns 0 and chrome 404
|
assertThat(response.get("status")).isIn(404L, 0L); // PhantomJS returns 0 and chrome 404
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@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 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
private AuthorizationResource getAuthorizationResource() throws FileNotFoundException {
|
|
||||||
return getClientResource(RESOURCE_SERVER_ID).authorization();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ClientResource getClientResource(String clientId) {
|
|
||||||
ClientsResource clients = this.realmsResouce().realm(REALM_NAME).clients();
|
|
||||||
ClientRepresentation resourceServer = clients.findByClientId(clientId).get(0);
|
|
||||||
return clients.get(resourceServer.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loginToClientPage(UserRepresentation user, String... scopes) throws InterruptedException {
|
|
||||||
log.debugf("--logging in as {0} with password: {1}; scopes: {2}", user.getUsername(), user.getCredentials().get(0).getValue(), Arrays.toString(scopes));
|
|
||||||
|
|
||||||
if (testExecutor.isLoggedIn()) {
|
|
||||||
testExecutor.logout(this::assertOnTestAppUrl);
|
|
||||||
jsDriver.manage().deleteAllCookies();
|
|
||||||
|
|
||||||
jsDriver.navigate().to(testRealmLoginPage.toString());
|
|
||||||
waitForPageToLoad();
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
private 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* 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.adapter.example.authorization;
|
||||||
|
|
||||||
|
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_WILDFLY_DEPRECATED)
|
||||||
|
@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"));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue