[KEYCLOAK-4755] - AuthZ UI Tests

This commit is contained in:
Pedro Igor 2017-04-13 15:54:52 -03:00
parent 4344ceefc2
commit a415ea3670
24 changed files with 1421 additions and 4 deletions

View file

@ -76,6 +76,8 @@ public class Client extends Clients {
private WebElement installationLink;
@FindBy(linkText = "Service Account Roles")
private WebElement serviceAccountRoles;
@FindBy(linkText = "Authorization")
private WebElement authorizationLink;
public void settings() {
settingsLink.click();
@ -104,6 +106,10 @@ public class Client extends Clients {
public void installation() {
installationLink.click();
}
public void authorization() {
authorizationLink.click();
}
public boolean isServiceAccountRolesDisplayed() {
try {

View file

@ -0,0 +1,135 @@
/*
* 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.console.page.clients.authorization;
import org.jboss.arquillian.graphene.fragment.Root;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.testsuite.console.page.clients.Client;
import org.keycloak.testsuite.console.page.clients.authorization.permission.Permissions;
import org.keycloak.testsuite.console.page.clients.authorization.policy.Policies;
import org.keycloak.testsuite.console.page.clients.authorization.resource.Resources;
import org.keycloak.testsuite.console.page.clients.authorization.scope.Scopes;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
/**
*
* @author tkyjovsk
*/
public class Authorization extends Client {
@FindBy(id = "authz-tabs")
protected AuthorizationTabLinks authorizationTabLinks;
@Page
private AuthorizationSettingsForm authorizationSettingsForm;
@Page
private Resources resources;
@Page
private Scopes scopes;
@Page
private Permissions permissions;
@Page
private Policies policies;
public AuthorizationSettingsForm settings() {
return authorizationSettingsForm;
}
public AuthorizationTab authorizationTabs() {
return new AuthorizationTab(authorizationTabLinks);
}
@Override
public String getUriFragment() {
return super.getUriFragment() + "/authz/resource-server";
}
public class AuthorizationTab {
private final AuthorizationTabLinks links;
public AuthorizationTab(AuthorizationTabLinks links) {
this.links = links;
}
public Resources resources() {
links.resources();
return resources;
}
public Scopes scopes() {
links.scopes();
return scopes;
}
public Permissions permissions() {
links.permissions();
return permissions;
}
public Policies policies() {
links.policies();
return policies;
}
}
public class AuthorizationTabLinks {
@Root
private WebElement root;
@FindBy(linkText = "Settings")
private WebElement settingsLink;
@FindBy(linkText = "Resources")
private WebElement resourcesLink;
@FindBy(linkText = "Authorization Scopes")
private WebElement scopesLink;
@FindBy(linkText = "Permissions")
private WebElement permissionsLink;
@FindBy(linkText = "Policies")
private WebElement policiesLink;
public void settings() {
settingsLink.click();
}
public void resources() {
resourcesLink.click();
}
private void scopes() {
scopesLink.click();
}
private void permissions() {
permissionsLink.click();
}
private void policies() {
policiesLink.click();
}
}
}

View file

@ -0,0 +1,62 @@
/*
* 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.console.page.clients.authorization;
import static org.keycloak.testsuite.util.WaitUtils.pause;
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.testsuite.console.page.clients.CreateClientForm;
import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
import org.keycloak.testsuite.page.Form;
import org.keycloak.testsuite.util.Timer;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.Select;
/**
* @author tkyjovsk
*/
public class AuthorizationSettingsForm extends Form {
@FindBy(id = "server.policyEnforcementMode")
private Select enforcementMode;
@FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='server.allowRemoteResourceManagement']]")
private OnOffSwitch allowRemoteResourceManagement;
public void setEnforcementMode(PolicyEnforcerConfig.EnforcementMode mode) {
enforcementMode.selectByValue(mode.name());
}
public PolicyEnforcerConfig.EnforcementMode getEnforcementMode() {
return PolicyEnforcerConfig.EnforcementMode.valueOf(enforcementMode.getFirstSelectedOption().getAttribute("value"));
}
public void setAllowRemoteResourceManagement(boolean enable) {
allowRemoteResourceManagement.setOn(enable);
}
public boolean isAllowRemoteResourceManagement() {
return allowRemoteResourceManagement.isOn();
}
}

View file

@ -0,0 +1,33 @@
/*
* 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.console.page.clients.authorization.permission;
import org.keycloak.testsuite.page.Form;
import org.openqa.selenium.support.FindBy;
/**
* @author tkyjovsk
*/
public class Permissions extends Form {
@FindBy(css = "table[class*='table']")
private PermissionsTable table;
public PermissionsTable permissions() {
return table;
}
}

View file

@ -0,0 +1,77 @@
/*
* 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.console.page.clients.authorization.permission;
import static org.openqa.selenium.By.tagName;
import java.util.ArrayList;
import java.util.List;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.testsuite.console.page.fragment.DataTable;
import org.openqa.selenium.WebElement;
/**
*
* @author tkyjovsk
*/
public class PermissionsTable extends DataTable {
public PolicyRepresentation findByName(String name) {
search(name);
List<PolicyRepresentation> result = getTableRows();
if (result.isEmpty()) {
return null;
} else {
assert 1 == result.size();
return result.get(0);
}
}
public boolean contains(String name) {
for (PolicyRepresentation representation : getTableRows()) {
if (name.equals(representation.getName())) {
return true;
}
}
return false;
}
public List<PolicyRepresentation> getTableRows() {
List<PolicyRepresentation> rows = new ArrayList<>();
for (WebElement row : rows()) {
PolicyRepresentation representation = toRepresentation(row);
if (representation != null) {
rows.add(representation);
}
}
return rows;
}
public PolicyRepresentation toRepresentation(WebElement row) {
PolicyRepresentation representation = null;
List<WebElement> tds = row.findElements(tagName("td"));
if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) {
representation = new PolicyRepresentation();
representation.setName(tds.get(0).getText());
representation.setDescription(tds.get(1).getText());
representation.setType(tds.get(2).getText());
}
return representation;
}
}

View file

@ -0,0 +1,34 @@
/*
* 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.console.page.clients.authorization.policy;
import org.keycloak.testsuite.console.page.clients.authorization.permission.PermissionsTable;
import org.keycloak.testsuite.page.Form;
import org.openqa.selenium.support.FindBy;
/**
* @author tkyjovsk
*/
public class Policies extends Form {
@FindBy(css = "table[class*='table']")
private PermissionsTable table;
public PermissionsTable policies() {
return table;
}
}

View file

@ -0,0 +1,77 @@
/*
* 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.console.page.clients.authorization.policy;
import static org.openqa.selenium.By.tagName;
import java.util.ArrayList;
import java.util.List;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.testsuite.console.page.fragment.DataTable;
import org.openqa.selenium.WebElement;
/**
*
* @author tkyjovsk
*/
public class PoliciesTable extends DataTable {
public PolicyRepresentation findByName(String name) {
search(name);
List<PolicyRepresentation> result = getTableRows();
if (result.isEmpty()) {
return null;
} else {
assert 1 == result.size();
return result.get(0);
}
}
public boolean contains(String name) {
for (PolicyRepresentation representation : getTableRows()) {
if (name.equals(representation.getName())) {
return true;
}
}
return false;
}
public List<PolicyRepresentation> getTableRows() {
List<PolicyRepresentation> rows = new ArrayList<>();
for (WebElement row : rows()) {
PolicyRepresentation representation = toRepresentation(row);
if (representation != null) {
rows.add(representation);
}
}
return rows;
}
public PolicyRepresentation toRepresentation(WebElement row) {
PolicyRepresentation representation = null;
List<WebElement> tds = row.findElements(tagName("td"));
if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) {
representation = new PolicyRepresentation();
representation.setName(tds.get(0).getText());
representation.setDescription(tds.get(1).getText());
representation.setType(tds.get(2).getText());
}
return representation;
}
}

View file

@ -0,0 +1,41 @@
/*
* 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.console.page.clients.authorization.resource;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class Resource {
@Page
private ResourceForm form;
public ResourceForm form() {
return form;
}
public ResourceRepresentation toRepresentation() {
return form.toRepresentation();
}
public void update(ResourceRepresentation expected) {
form().populate(expected);
}
}

View file

@ -0,0 +1,163 @@
/*
* 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.console.page.clients.authorization.resource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.jboss.arquillian.graphene.fragment.Root;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.testsuite.page.Form;
import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
/**
* @author tkyjovsk
*/
public class ResourceForm extends Form {
@FindBy(id = "name")
private WebElement name;
@FindBy(id = "type")
private WebElement type;
@FindBy(id = "uri")
private WebElement uri;
@FindBy(id = "iconUri")
private WebElement iconUri;
@FindBy(id = "resource.owner.name")
private WebElement owner;
@FindBy(xpath = "//i[contains(@class,'pficon-delete')]")
private WebElement deleteButton;
@FindBy(xpath = ACTIVE_DIV_XPATH + "/button[text()='Delete']")
private WebElement confirmDelete;
@FindBy(id = "s2id_scopes")
private ScopesInput scopesInput;
public void populate(ResourceRepresentation expected) {
setInputValue(name, expected.getName());
setInputValue(type, expected.getType());
setInputValue(uri, expected.getUri());
setInputValue(iconUri, expected.getIconUri());
Set<ScopeRepresentation> scopes = expected.getScopes();
for (ScopeRepresentation scope : scopes) {
scopesInput.select(scope.getName());
}
Set<ScopeRepresentation> selection = scopesInput.getSelected();
for (ScopeRepresentation selected : selection) {
boolean isSelected = false;
for (ScopeRepresentation scope : scopes) {
if (selected.getName().equals(scope.getName())) {
isSelected = true;
break;
}
}
if (!isSelected) {
scopesInput.unSelect(selected.getName(), driver);
}
}
save();
}
public void delete() {
deleteButton.click();
confirmDelete.click();
}
public ResourceRepresentation toRepresentation() {
ResourceRepresentation representation = new ResourceRepresentation();
representation.setName(getInputValue(name));
representation.setType(getInputValue(type));
representation.setUri(getInputValue(uri));
representation.setIconUri(getInputValue(iconUri));
representation.setScopes(scopesInput.getSelected());
return representation;
}
public class ScopesInput {
@Root
private WebElement root;
@FindBy(xpath = "//input[contains(@class,'select2-input')]")
private WebElement search;
@FindBy(xpath = "//div[contains(@class,'select2-result-label')]")
private List<WebElement> result;
@FindBy(xpath = "//li[contains(@class,'select2-search-choice')]")
private List<WebElement> selection;
public void select(String name) {
setInputValue(search, name);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (WebElement result : result) {
if (result.getText().equalsIgnoreCase(name)) {
result.click();
return;
}
}
}
public Set<ScopeRepresentation> getSelected() {
HashSet<ScopeRepresentation> values = new HashSet<>();
for (WebElement selected : selection) {
values.add(new ScopeRepresentation(selected.findElements(By.tagName("div")).get(0).getText()));
}
return values;
}
public void unSelect(String name, WebDriver driver) {
for (WebElement selected : selection) {
if (name.equals(selected.findElements(By.tagName("div")).get(0).getText())) {
WebElement element = selected.findElement(By.xpath("//a[contains(@class,'select2-search-choice-close')]"));
JavascriptExecutor executor = (JavascriptExecutor) driver;
executor.executeScript("arguments[0].click();", element);
WaitUtils.pause(1000);
return;
}
}
}
}
}

View file

@ -0,0 +1,86 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.page.clients.authorization.resource;
import static org.openqa.selenium.By.tagName;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.testsuite.page.Form;
import org.keycloak.testsuite.util.WaitUtils;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
/**
* @author tkyjovsk
*/
public class Resources extends Form {
@FindBy(css = "table[class*='table']")
private ResourcesTable table;
@FindBy(linkText = "Create")
private WebElement create;
@Page
private Resource resource;
public ResourcesTable resources() {
return table;
}
public void create(ResourceRepresentation representation) {
create.click();
resource.form().populate(representation);
}
public void update(String name, ResourceRepresentation representation) {
for (WebElement row : resources().rows()) {
ResourceRepresentation actual = resources().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
row.findElements(tagName("a")).get(0).click();
WaitUtils.waitForPageToLoad(driver);
resource.form().populate(representation);
return;
}
}
}
public void delete(String name) {
for (WebElement row : resources().rows()) {
ResourceRepresentation actual = resources().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
row.findElements(tagName("a")).get(0).click();
WaitUtils.waitForPageToLoad(driver);
resource.form().delete();
return;
}
}
}
public Resource name(String name) {
for (WebElement row : resources().rows()) {
ResourceRepresentation actual = resources().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
row.findElements(tagName("a")).get(0).click();
WaitUtils.waitForPageToLoad(driver);
return resource;
}
}
return null;
}
}

View file

@ -0,0 +1,80 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.page.clients.authorization.resource;
import static org.openqa.selenium.By.tagName;
import java.util.ArrayList;
import java.util.List;
import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.testsuite.console.page.fragment.DataTable;
import org.openqa.selenium.WebElement;
/**
*
* @author tkyjovsk
*/
public class ResourcesTable extends DataTable {
public ResourceRepresentation findByName(String name) {
search(name);
List<ResourceRepresentation> result = getTableRows();
if (result.isEmpty()) {
return null;
} else {
assert 1 == result.size();
return result.get(0);
}
}
public boolean contains(String name) {
for (ResourceRepresentation representation : getTableRows()) {
if (name.equals(representation.getName())) {
return true;
}
}
return false;
}
public List<ResourceRepresentation> getTableRows() {
List<ResourceRepresentation> rows = new ArrayList<>();
for (WebElement row : rows()) {
ResourceRepresentation representation = toRepresentation(row);
if (representation != null) {
rows.add(representation);
}
}
return rows;
}
public ResourceRepresentation toRepresentation(WebElement row) {
ResourceRepresentation representation = null;
List<WebElement> tds = row.findElements(tagName("td"));
if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) {
representation = new ResourceRepresentation();
representation.setName(tds.get(0).getText());
representation.setType(tds.get(1).getText());
representation.setUri(tds.get(2).getText());
ResourceOwnerRepresentation owner = new ResourceOwnerRepresentation();
owner.setName(tds.get(3).getText());
representation.setOwner(owner);
}
return representation;
}
}

View file

@ -0,0 +1,32 @@
/*
* 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.console.page.clients.authorization.scope;
import org.jboss.arquillian.graphene.page.Page;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class Scope {
@Page
private ScopeForm form;
public ScopeForm form() {
return form;
}
}

View file

@ -0,0 +1,51 @@
/*
* 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.console.page.clients.authorization.scope;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.testsuite.page.Form;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
/**
* @author tkyjovsk
*/
public class ScopeForm extends Form {
@FindBy(id = "name")
private WebElement name;
@FindBy(id = "iconUri")
private WebElement iconUri;
@FindBy(xpath = "//i[contains(@class,'pficon-delete')]")
private WebElement deleteButton;
@FindBy(xpath = ACTIVE_DIV_XPATH + "/button[text()='Delete']")
private WebElement confirmDelete;
public void populate(ScopeRepresentation expected) {
setInputValue(name, expected.getName());
setInputValue(iconUri, expected.getIconUri());
save();
}
public void delete() {
deleteButton.click();
confirmDelete.click();
}
}

View file

@ -0,0 +1,69 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.page.clients.authorization.scope;
import static org.openqa.selenium.By.tagName;
import org.jboss.arquillian.graphene.page.Page;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.testsuite.page.Form;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
/**
* @author tkyjovsk
*/
public class Scopes extends Form {
@FindBy(css = "table[class*='table']")
private ScopesTable table;
@FindBy(linkText = "Create")
private WebElement create;
@Page
private Scope scope;
public ScopesTable scopes() {
return table;
}
public void create(ScopeRepresentation representation) {
create.click();
scope.form().populate(representation);
}
public void update(String name, ScopeRepresentation representation) {
for (WebElement row : scopes().rows()) {
ScopeRepresentation actual = scopes().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
row.findElements(tagName("a")).get(0).click();
scope.form().populate(representation);
}
}
}
public void delete(String name) {
for (WebElement row : scopes().rows()) {
ScopeRepresentation actual = scopes().toRepresentation(row);
if (actual.getName().equalsIgnoreCase(name)) {
row.findElements(tagName("a")).get(0).click();
scope.form().delete();
}
}
}
}

View file

@ -0,0 +1,74 @@
/*
* 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.console.page.clients.authorization.scope;
import static org.openqa.selenium.By.tagName;
import java.util.ArrayList;
import java.util.List;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.testsuite.console.page.fragment.DataTable;
import org.openqa.selenium.WebElement;
/**
*
* @author tkyjovsk
*/
public class ScopesTable extends DataTable {
public ScopeRepresentation findByName(String name) {
search(name);
List<ScopeRepresentation> result = getTableRows();
if (result.isEmpty()) {
return null;
} else {
assert 1 == result.size();
return result.get(0);
}
}
public boolean contains(String name) {
for (ScopeRepresentation representation : getTableRows()) {
if (name.equals(representation.getName())) {
return true;
}
}
return false;
}
public List<ScopeRepresentation> getTableRows() {
List<ScopeRepresentation> rows = new ArrayList<>();
for (WebElement row : rows()) {
ScopeRepresentation representation = toRepresentation(row);
if (representation != null) {
rows.add(representation);
}
}
return rows;
}
public ScopeRepresentation toRepresentation(WebElement row) {
ScopeRepresentation representation = null;
List<WebElement> tds = row.findElements(tagName("td"));
if (!(tds.isEmpty() || tds.get(0).getText().isEmpty())) {
representation = new ScopeRepresentation();
representation.setName(tds.get(0).getText());
}
return representation;
}
}

View file

@ -67,6 +67,12 @@ public class ClientSettingsForm extends CreateClientForm {
@FindBy(xpath = ".//button[contains(@data-ng-click, 'deleteWebOrigin')]")
private List<WebElement> deleteWebOriginIcons;
@FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='authorizationServicesEnabled']]")
private OnOffSwitch authorizationSettingsEnabledSwitch;
@FindBy(xpath = ACTIVE_DIV_XPATH + "/button[text()='Disable Authorization Settings']")
private WebElement confirmDisableAuthorizationSettingsButton;
public enum OidcAccessType {
BEARER_ONLY("bearer-only"), PUBLIC("public"), CONFIDENTIAL("confidential");
@ -212,6 +218,18 @@ public class ClientSettingsForm extends CreateClientForm {
serviceAccountsEnabledSwitch.setOn(serviceAccountsEnabled);
}
public void setAuthorizationSettingsEnabled(boolean enabled) {
authorizationSettingsEnabledSwitch.setOn(enabled);
}
public boolean isAuthorizationSettingsEnabled() {
return authorizationSettingsEnabledSwitch.isOn();
}
public void confirmDisableAuthorizationSettings() {
confirmDisableAuthorizationSettingsButton.click();
}
public class SAMLClientSettingsForm extends Form {
public static final String SAML_ASSERTION_SIGNATURE = "saml.assertion.signature";

View file

@ -0,0 +1,80 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.authorization;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.keycloak.testsuite.auth.page.login.Login.OIDC;
import org.jboss.arquillian.graphene.page.Page;
import org.junit.Before;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.testsuite.console.clients.AbstractClientTest;
import org.keycloak.testsuite.console.page.clients.authorization.Authorization;
import org.keycloak.testsuite.console.page.clients.settings.ClientSettings;
import org.openqa.selenium.By;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public abstract class AbstractAuthorizationSettingsTest extends AbstractClientTest {
@Page
protected ClientSettings clientSettingsPage;
@Page
protected Authorization authorizationPage;
protected ClientRepresentation newClient;
@Before
public void configureTest() {
this.newClient = createResourceServer();
}
private ClientRepresentation createResourceServer() {
ClientRepresentation newClient = createClientRep("oidc-confidetial", OIDC);
createClient(newClient);
newClient.setRedirectUris(TEST_REDIRECT_URIs);
newClient.setAuthorizationServicesEnabled(true);
clientSettingsPage.form().setRedirectUris(TEST_REDIRECT_URIs);
clientSettingsPage.form().setAuthorizationSettingsEnabled(true);
clientSettingsPage.form().save();
assertAlertSuccess();
ClientRepresentation found = findClientByClientId(newClient.getClientId());
assertNotNull("Client " + newClient.getClientId() + " was not found.", found);
newClient.setPublicClient(false);
newClient.setServiceAccountsEnabled(true);
assertClientSettingsEqual(newClient, found);
assertTrue(clientSettingsPage.tabs().getTabs().findElement(By.linkText("Authorization")).isDisplayed());
clientSettingsPage.setId(found.getId());
clientSettingsPage.navigateTo();
authorizationPage.setId(found.getId());
clientSettingsPage.tabs().authorization();
assertTrue(authorizationPage.isCurrent());
return newClient;
}
}

View file

@ -0,0 +1,69 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.console.authorization;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.testsuite.console.page.clients.authorization.AuthorizationSettingsForm;
import org.keycloak.testsuite.console.page.clients.authorization.permission.Permissions;
import org.keycloak.testsuite.console.page.clients.authorization.policy.Policies;
import org.keycloak.testsuite.console.page.clients.authorization.resource.Resources;
import org.keycloak.testsuite.console.page.clients.authorization.scope.Scopes;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class DefaultAuthorizationSettingsTest extends AbstractAuthorizationSettingsTest {
@Test
public void testDefaultSettings() {
AuthorizationSettingsForm settings = authorizationPage.settings();
assertEquals(PolicyEnforcerConfig.EnforcementMode.ENFORCING, settings.getEnforcementMode());
assertEquals(false, settings.isAllowRemoteResourceManagement());
Resources resources = authorizationPage.authorizationTabs().resources();
ResourceRepresentation resource = resources.resources().findByName("Default Resource");
assertNotNull(resource);
assertEquals("urn:oidc-confidetial:resources:default", resource.getType());
assertEquals("/*", resource.getUri());
assertEquals(newClient.getClientId(), resource.getOwner().getName());
Scopes scopes = authorizationPage.authorizationTabs().scopes();
assertTrue(scopes.scopes().getTableRows().isEmpty());
Permissions permissions = authorizationPage.authorizationTabs().permissions();
PolicyRepresentation permission = permissions.permissions().findByName("Default Permission");
assertNotNull(permission);
assertEquals("resource", permission.getType());
Policies policies = authorizationPage.authorizationTabs().policies();
PolicyRepresentation policy = policies.policies().findByName("Default Policy");
assertNotNull(policy);
assertEquals("js", policy.getType());
}
}

View file

@ -0,0 +1,40 @@
/*
* 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.console.authorization;
import static org.junit.Assert.assertFalse;
import org.junit.Test;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class DisableAuthorizationSettingsTest extends AbstractAuthorizationSettingsTest {
@Test
public void testDisableAuthorization() throws InterruptedException {
clientSettingsPage.navigateTo();
clientSettingsPage.form().setAuthorizationSettingsEnabled(false);
clientSettingsPage.form().confirmDisableAuthorizationSettings();
Thread.sleep(1000);
clientSettingsPage.form().save();
assertAlertSuccess();
clientSettingsPage.navigateTo();
assertFalse(clientSettingsPage.form().isAuthorizationSettingsEnabled());
}
}

View file

@ -0,0 +1,120 @@
/*
* 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.console.authorization;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.testsuite.console.page.clients.authorization.resource.Resource;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class ResourceManagementTest extends AbstractAuthorizationSettingsTest {
@Before
@Override
public void configureTest() {
super.configureTest();
for (String scopeName : Arrays.asList("Scope A", "Scope B", "Scope C")) {
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().scopes().create(new ScopeRepresentation(scopeName));
}
authorizationPage.navigateTo();
}
@Test
public void testUpdate() {
ResourceRepresentation expected = createResource();
String previousName = expected.getName();
expected.setName("changed");
expected.setType("changed");
expected.setUri("changed");
expected.setScopes(Arrays.asList("Scope A", "Scope B", "Scope C").stream().map(name -> new ScopeRepresentation(name)).collect(Collectors.toSet()));
authorizationPage.navigateTo();
Resource resource = authorizationPage.authorizationTabs().resources().name(previousName);
resource.update(expected);
assertAlertSuccess();
assertResource(expected);
expected.setScopes(expected.getScopes().stream().filter(scope -> scope.getName().equals("Scope C")).collect(Collectors.toSet()));
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().resources().update(expected.getName(), expected);
assertAlertSuccess();
assertResource(expected);
}
@Test
public void testDelete() {
ResourceRepresentation expected = createResource();
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().resources().delete(expected.getName());
authorizationPage.navigateTo();
assertNull(authorizationPage.authorizationTabs().resources().resources().findByName(expected.getName()));
}
private ResourceRepresentation createResource() {
ResourceRepresentation expected = new ResourceRepresentation();
expected.setName("Test Resource");
expected.setType("Test Type");
expected.setUri("/test/resource");
authorizationPage.authorizationTabs().resources().create(expected);
assertAlertSuccess();
return expected;
}
private void assertResource(ResourceRepresentation expected) {
authorizationPage.navigateTo();
ResourceRepresentation actual = authorizationPage.authorizationTabs().resources().resources().findByName(expected.getName());
assertEquals(expected.getName(), actual.getName());
assertEquals(expected.getType(), actual.getType());
assertEquals(expected.getUri(), actual.getUri());
assertEquals(expected.getIconUri(), actual.getIconUri());
ResourceRepresentation resource = authorizationPage.authorizationTabs().resources().name(expected.getName()).toRepresentation();
Set<ScopeRepresentation> associatedScopes = resource.getScopes();
if (expected.getScopes() != null) {
assertNotNull(associatedScopes);
assertEquals(expected.getScopes().size(), associatedScopes.size());
assertEquals(0, resource.getScopes().stream().filter(actualScope -> !expected.getScopes().stream()
.filter(expectedScope -> actualScope.getName().equals(expectedScope.getName()))
.findFirst().isPresent())
.count());
} else {
assertTrue(associatedScopes.isEmpty());
}
}
}

View file

@ -0,0 +1,70 @@
/*
* 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.console.authorization;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import org.junit.Test;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public class ScopeManagementTest extends AbstractAuthorizationSettingsTest {
@Test
public void testUpdate() {
ScopeRepresentation expected = createScope();
String previousName = expected.getName();
expected.setName("changed");
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().scopes().update(previousName, expected);
assertAlertSuccess();
assertScope(expected);
}
@Test
public void testDelete() {
ScopeRepresentation expected = createScope();
authorizationPage.navigateTo();
authorizationPage.authorizationTabs().scopes().delete(expected.getName());
authorizationPage.navigateTo();
assertNull(authorizationPage.authorizationTabs().scopes().scopes().findByName(expected.getName()));
}
private ScopeRepresentation createScope() {
ScopeRepresentation expected = new ScopeRepresentation();
expected.setName("Test Scope");
authorizationPage.authorizationTabs().scopes().create(expected);
assertAlertSuccess();
return expected;
}
private void assertScope(ScopeRepresentation expected) {
authorizationPage.navigateTo();
ScopeRepresentation actual = authorizationPage.authorizationTabs().scopes().scopes().findByName(expected.getName());
assertEquals(expected.getName(), actual.getName());
assertEquals(expected.getIconUri(), actual.getIconUri());
}
}

View file

@ -44,10 +44,10 @@
<kc-tooltip>{{:: 'authz-resource-uri.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="reqActions">{{:: 'authz-scopes' | translate}}</label>
<label class="col-md-2 control-label" for="scopes">{{:: 'authz-scopes' | translate}}</label>
<div class="col-md-6">
<input type="hidden" ui-select2="scopesUiSelect" id="reqActions" data-ng-model="resource.scopes" data-placeholder="{{:: 'authz-select-scope' | translate}}..." multiple/>
<input type="hidden" ui-select2="scopesUiSelect" id="scopes" data-ng-model="resource.scopes" data-placeholder="{{:: 'authz-select-scope' | translate}}..." multiple/>
</div>
<kc-tooltip>{{:: 'authz-resource-scopes.tooltip' | translate}}</kc-tooltip>

View file

@ -25,7 +25,7 @@
<div class="form-group">
<label class="col-md-2 control-label" for="name">{{:: 'authz-icon-uri' | translate}} </label>
<div class="col-sm-6">
<input class="form-control" type="text" id="name" name="name" data-ng-model="scope.iconUri" autofocus>
<input class="form-control" type="text" id="iconUri" name="name" data-ng-model="scope.iconUri" autofocus>
</div>
<kc-tooltip>{{:: 'authz-icon-uri.tooltip' | translate}}</kc-tooltip>
</div>

View file

@ -2,7 +2,7 @@
<kc-tabs-client></kc-tabs-client>
<ul class="nav nav-tabs nav-tabs-pf" data-ng-hide="create && !path[4]" style="margin-left: 15px">
<ul id="authz-tabs" class="nav nav-tabs nav-tabs-pf" data-ng-hide="create && !path[4]" style="margin-left: 15px">
<li ng-class="{active: !path[6]}"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/">{{:: 'settings' | translate}}</a></li>
<li ng-class="{active: path[6] == 'resource'}" data-ng-hide="create"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/resource">{{:: 'authz-resources' | translate}}</a></li>
<li ng-class="{active: path[6] == 'scope'}" data-ng-hide="create"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/scope">{{:: 'authz-authz-scopes' | translate}}</a></li>