KEYCLOAK-9014 Fix displayed applications

This commit is contained in:
Hynek Mlnarik 2018-12-05 22:01:48 +01:00 committed by Hynek Mlnařík
parent 8204509b0c
commit dad12635f6
15 changed files with 353 additions and 115 deletions

View file

@ -29,6 +29,13 @@ public interface OrderedModel {
class OrderedModelComparator<OM extends OrderedModel> implements Comparator<OM> { class OrderedModelComparator<OM extends OrderedModel> implements Comparator<OM> {
public static final OrderedModelComparator INSTANCE = new OrderedModelComparator();
@SuppressWarnings("unchecked")
public static <T extends OrderedModel> OrderedModelComparator<T> getInstance() {
return INSTANCE;
}
@Override @Override
public int compare(OM o1, OM o2) { public int compare(OM o1, OM o2) {
int o1order = parseOrder(o1); int o1order = parseOrder(o1);

View file

@ -18,13 +18,11 @@
package org.keycloak.forms.account.freemarker.model; package org.keycloak.forms.account.freemarker.model;
import org.keycloak.common.util.MultivaluedHashMap; import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.forms.login.freemarker.model.OAuthGrantBean;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientScopeModel; import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.Constants; import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.OrderedModel; import org.keycloak.models.OrderedModel;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.UserConsentModel; import org.keycloak.models.UserConsentModel;
@ -39,7 +37,6 @@ import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -47,36 +44,44 @@ import java.util.stream.Collectors;
*/ */
public class ApplicationsBean { public class ApplicationsBean {
private List<ApplicationEntry> applications = new LinkedList<ApplicationEntry>(); private List<ApplicationEntry> applications = new LinkedList<>();
public ApplicationsBean(KeycloakSession session, RealmModel realm, UserModel user) { public ApplicationsBean(KeycloakSession session, RealmModel realm, UserModel user) {
Set<ClientModel> offlineClients = new UserSessionManager(session).findClientsWithOfflineToken(realm, user); Set<ClientModel> offlineClients = new UserSessionManager(session).findClientsWithOfflineToken(realm, user);
for (ClientModel client : getApplications(session, realm, user)) { for (ClientModel client : getApplications(session, realm, user)) {
Set<RoleModel> availableRoles = new HashSet<>(); if (isAdminClient(client) && ! AdminPermissions.realms(session, realm, user).isAdmin()) {
continue;
}
// Construct scope parameter with all optional scopes to see all potentially available roles // Construct scope parameter with all optional scopes to see all potentially available roles
Set<ClientScopeModel> allClientScopes = new HashSet<>(client.getClientScopes(true, true).values()); Set<ClientScopeModel> allClientScopes = new HashSet<>(client.getClientScopes(true, true).values());
allClientScopes.addAll(client.getClientScopes(false, true).values()); allClientScopes.addAll(client.getClientScopes(false, true).values());
allClientScopes.add(client); allClientScopes.add(client);
availableRoles = TokenManager.getAccess(user, client, allClientScopes); Set<RoleModel> availableRoles = TokenManager.getAccess(user, client, allClientScopes);
// Don't show applications, which user doesn't have access into (any available roles)
// unless this is can be changed by approving/revoking consent
if (! isAdminClient(client) && availableRoles.isEmpty() && ! client.isConsentRequired()) {
continue;
}
List<RoleModel> realmRolesAvailable = new LinkedList<>(); List<RoleModel> realmRolesAvailable = new LinkedList<>();
MultivaluedHashMap<String, ClientRoleEntry> resourceRolesAvailable = new MultivaluedHashMap<>(); MultivaluedHashMap<String, ClientRoleEntry> resourceRolesAvailable = new MultivaluedHashMap<>();
processRoles(availableRoles, realmRolesAvailable, resourceRolesAvailable); processRoles(availableRoles, realmRolesAvailable, resourceRolesAvailable);
List<ClientScopeModel> orderedScopes = new ArrayList<>(); List<ClientScopeModel> orderedScopes = new LinkedList<>();
if (client.isConsentRequired()) { if (client.isConsentRequired()) {
UserConsentModel consent = session.users().getConsentByClient(realm, user.getId(), client.getId()); UserConsentModel consent = session.users().getConsentByClient(realm, user.getId(), client.getId());
if (consent != null) { if (consent != null) {
orderedScopes.addAll(consent.getGrantedClientScopes()); orderedScopes.addAll(consent.getGrantedClientScopes());
orderedScopes.sort(new OrderedModel.OrderedModelComparator<>());
} }
} }
List<String> clientScopesGranted = orderedScopes.stream() List<String> clientScopesGranted = orderedScopes.stream()
.sorted(OrderedModel.OrderedModelComparator.getInstance())
.map(ClientScopeModel::getConsentScreenText) .map(ClientScopeModel::getConsentScreenText)
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -89,6 +94,11 @@ public class ApplicationsBean {
} }
} }
public static boolean isAdminClient(ClientModel client) {
return client.getClientId().equals(Constants.ADMIN_CLI_CLIENT_ID)
|| client.getClientId().equals(Constants.ADMIN_CONSOLE_CLIENT_ID);
}
private Set<ClientModel> getApplications(KeycloakSession session, RealmModel realm, UserModel user) { private Set<ClientModel> getApplications(KeycloakSession session, RealmModel realm, UserModel user) {
Set<ClientModel> clients = new HashSet<>(); Set<ClientModel> clients = new HashSet<>();
@ -98,11 +108,6 @@ public class ApplicationsBean {
continue; continue;
} }
if (client.getClientId().equals(Constants.ADMIN_CLI_CLIENT_ID)
|| client.getClientId().equals(Constants.ADMIN_CONSOLE_CLIENT_ID)) {
if (!AdminPermissions.realms(session, realm, user).isAdmin()) continue;
}
clients.add(client); clients.add(client);
} }

View file

@ -3,10 +3,14 @@ package org.keycloak.testsuite.updaters;
import org.keycloak.admin.client.Keycloak; import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.resource.ClientResource; import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.ClientsResource; import org.keycloak.admin.client.resource.ClientsResource;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import java.io.Closeable; import org.keycloak.representations.idm.ClientScopeRepresentation;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
@ -14,29 +18,40 @@ import static org.junit.Assert.assertThat;
* *
* @author hmlnarik * @author hmlnarik
*/ */
public class ClientAttributeUpdater { public class ClientAttributeUpdater extends ServerResourceUpdater<ClientAttributeUpdater, ClientResource, ClientRepresentation> {
private final ClientResource clientResource; private final RealmResource realmResource;
private final ClientRepresentation rep;
private final ClientRepresentation origRep;
public static ClientAttributeUpdater forClient(Keycloak adminClient, String realm, String clientId) { public static ClientAttributeUpdater forClient(Keycloak adminClient, String realm, String clientId) {
ClientsResource clients = adminClient.realm(realm).clients(); RealmResource realmRes = adminClient.realm(realm);
ClientsResource clients = realmRes.clients();
List<ClientRepresentation> foundClients = clients.findByClientId(clientId); List<ClientRepresentation> foundClients = clients.findByClientId(clientId);
assertThat(foundClients, hasSize(1)); assertThat(foundClients, hasSize(1));
ClientResource clientRes = clients.get(foundClients.get(0).getId()); ClientResource clientRes = clients.get(foundClients.get(0).getId());
return new ClientAttributeUpdater(clientRes); return new ClientAttributeUpdater(clientRes, realmRes);
} }
public ClientAttributeUpdater(ClientResource clientResource) { private ClientAttributeUpdater(ClientResource resource, RealmResource realmResource) {
this.clientResource = clientResource; super(resource, resource::toRepresentation, resource::update);
this.origRep = clientResource.toRepresentation();
this.rep = clientResource.toRepresentation();
if (this.rep.getAttributes() == null) { if (this.rep.getAttributes() == null) {
this.rep.setAttributes(new HashMap<>()); this.rep.setAttributes(new HashMap<>());
} }
this.realmResource = realmResource;
}
@Override
protected void performUpdate(ClientRepresentation from, ClientRepresentation to) {
super.performUpdate(from, to);
updateViaAddRemove(from.getDefaultClientScopes(), to.getDefaultClientScopes(), this::getConversionForScopeNameToId, resource::addDefaultClientScope, resource::removeDefaultClientScope);
updateViaAddRemove(from.getOptionalClientScopes(), to.getOptionalClientScopes(), this::getConversionForScopeNameToId, resource::addOptionalClientScope, resource::removeOptionalClientScope);
}
private Function<String, String> getConversionForScopeNameToId() {
Map<String, String> scopeNameToIdMap = realmResource.clientScopes().findAll().stream()
.collect(Collectors.toMap(ClientScopeRepresentation::getName, ClientScopeRepresentation::getId));
return scopeNameToIdMap::get;
} }
public ClientAttributeUpdater setClientId(String clientId) { public ClientAttributeUpdater setClientId(String clientId) {
@ -64,9 +79,27 @@ public class ClientAttributeUpdater {
return this; return this;
} }
public Closeable update() { public ClientAttributeUpdater setFullScopeAllowed(Boolean fullScopeAllowed) {
clientResource.update(rep); rep.setFullScopeAllowed(fullScopeAllowed);
return this;
return () -> clientResource.update(origRep);
} }
public ClientAttributeUpdater setDefaultClientScopes(List<String> defaultClientScopes) {
rep.setDefaultClientScopes(defaultClientScopes);
return this;
}
public ClientAttributeUpdater setOptionalClientScopes(List<String> optionalClientScopes) {
rep.setOptionalClientScopes(optionalClientScopes);
return this;
}
public RoleScopeUpdater realmRoleScope() {
return new RoleScopeUpdater(resource.getScopeMappings().realmLevel());
}
public RoleScopeUpdater clientRoleScope(String clientUUID) {
return new RoleScopeUpdater(resource.getScopeMappings().clientLevel(clientUUID));
}
} }

View file

@ -2,35 +2,22 @@ package org.keycloak.testsuite.updaters;
import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import java.io.Closeable;
import java.util.HashMap; import java.util.HashMap;
import java.util.function.Consumer; import java.util.List;
/** /**
* *
* @author hmlnarik * @author hmlnarik
*/ */
public class RealmAttributeUpdater { public class RealmAttributeUpdater extends ServerResourceUpdater<ServerResourceUpdater, RealmResource, RealmRepresentation> {
private final RealmResource realmResource; public RealmAttributeUpdater(RealmResource resource) {
super(resource, resource::toRepresentation, resource::update);
private final RealmRepresentation rep;
private final RealmRepresentation origRep;
public RealmAttributeUpdater(RealmResource realmResource) {
this.realmResource = realmResource;
this.origRep = realmResource.toRepresentation();
this.rep = realmResource.toRepresentation();
if (this.rep.getAttributes() == null) { if (this.rep.getAttributes() == null) {
this.rep.setAttributes(new HashMap<>()); this.rep.setAttributes(new HashMap<>());
} }
} }
public RealmAttributeUpdater updateWith(Consumer<RealmRepresentation> updater) {
updater.accept(this.rep);
return this;
}
public RealmAttributeUpdater setAttribute(String name, String value) { public RealmAttributeUpdater setAttribute(String name, String value) {
this.rep.getAttributes().put(name, value); this.rep.getAttributes().put(name, value);
return this; return this;
@ -51,9 +38,9 @@ public class RealmAttributeUpdater {
return this; return this;
} }
public Closeable update() { public RealmAttributeUpdater setDefaultDefaultClientScopes(List<String> defaultClientScopes) {
realmResource.update(rep); rep.setDefaultDefaultClientScopes(defaultClientScopes);
return this;
return () -> realmResource.update(origRep);
} }
} }

View file

@ -0,0 +1,63 @@
/*
* Copyright 2018 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.updaters;
import org.keycloak.admin.client.resource.RoleScopeResource;
import org.keycloak.representations.idm.RoleRepresentation;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
*
* @author hmlnarik
*/
public class RoleScopeUpdater extends ServerResourceUpdater<RoleScopeUpdater, RoleScopeResource, List<RoleRepresentation>> {
public RoleScopeUpdater(RoleScopeResource resource) {
super(resource, resource::listAll, null);
this.updater = this::update;
}
public RoleScopeUpdater add(RoleRepresentation representation) {
rep.add(representation);
return this;
}
public RoleScopeUpdater remove(RoleRepresentation representation) {
rep.add(representation);
return this;
}
private void update(List<RoleRepresentation> expectedRoles) {
List<RoleRepresentation> currentRoles = resource.listAll();
Set<String> currentRoleIds = currentRoles.stream().map(RoleRepresentation::getId).collect(Collectors.toSet());
Set<String> expectedRoleIds = expectedRoles.stream().map(RoleRepresentation::getId).collect(Collectors.toSet());
List<RoleRepresentation> toAdd = expectedRoles.stream()
.filter(role -> ! currentRoleIds.contains(role.getId()))
.collect(Collectors.toList());
List<RoleRepresentation> toRemove = currentRoles.stream()
.filter(role -> ! expectedRoleIds.contains(role.getId()))
.collect(Collectors.toList());
resource.add(toAdd);
resource.remove(toRemove);
}
}

View file

@ -0,0 +1,112 @@
/*
* Copyright 2018 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.updaters;
import java.io.Closeable;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
*
* @author hmlnarik
*/
public abstract class ServerResourceUpdater<T extends ServerResourceUpdater, Res, Rep> implements Closeable {
protected final Res resource;
protected final Rep rep;
protected final Rep origRep;
protected Consumer<Rep> updater;
protected boolean updated = false;
public ServerResourceUpdater(Res resource, Supplier<Rep> representationGenerator, Consumer<Rep> updater) {
this.resource = resource;
this.updater = updater;
// origRep and rep need to be two different instances
this.origRep = representationGenerator.get();
this.rep = representationGenerator.get();
}
public Res getResource() {
return resource;
}
public T update() {
performUpdate(origRep, rep);
this.updated = true;
return (T) this;
}
protected void performUpdate(Rep from, Rep to) {
updater.accept(to);
}
public T updateWith(Consumer<Rep> representationUpdater) {
representationUpdater.accept(this.rep);
return (T) this;
}
@Override
public void close() throws IOException {
if (! this.updated) {
throw new IOException("Attempt to revert changes that were never applied - have you called " + this.getClass().getName() + ".update()?");
}
performUpdate(rep, origRep);
}
/**
* This function performs a set of single {@code add} and {@code remove} operations that represent the changes needed to
* get collection {@code from} to the state of collection {@code to}. Since this is intended to work on collections of
* names of objects but the {@code add} and {@code remove} functions operate on IDs of those objects, a conversion
* is performed.
*
* @param <T> Type of the objects in the collections (e.g. names)
* @param <V> Type of the objects required by add/remove functions (e.g. IDs)
* @param from Initial collection
* @param to Target collection
* @param client2ServerConvertorGenerator Producer of the convertor. If not needed, just use {@code () -> Functions::identity}.
* This is intentionally a lazy-evaluated function variable because the conversion map often needs to be obtained from the
* server which can be slow operation. This function is called only if the two collections differ.
* @param add Function to add
* @param remove Function to remove
*/
public static <T, V> void updateViaAddRemove(Collection<T> from, Collection<T> to, Supplier<Function<T, V>> client2ServerConvertorGenerator, Consumer<V> add, Consumer<V> remove) {
if (Objects.equals(from, to)) {
return;
}
Function<T, V> client2ServerConvertor = client2ServerConvertorGenerator.get();
Set<V> current = from == null ? Collections.EMPTY_SET : from.stream().map(client2ServerConvertor).collect(Collectors.toSet());
Set<V> expected = to == null ? Collections.EMPTY_SET : to.stream().map(client2ServerConvertor).collect(Collectors.toSet());
expected.stream()
.filter(role -> ! current.contains(role))
.forEach(add);
current.stream()
.filter(role -> ! expected.contains(role))
.forEach(remove);
}
}

View file

@ -1,29 +1,37 @@
package org.keycloak.testsuite.updaters; package org.keycloak.testsuite.updaters;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.ClientsResource;
import org.keycloak.admin.client.resource.UserResource; import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
import java.io.Closeable;
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.stream.Collectors; import java.util.stream.Collectors;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertThat;
/** /**
* *
* @author hmlnarik * @author hmlnarik
*/ */
public class UserAttributeUpdater { public class UserAttributeUpdater extends ServerResourceUpdater<UserAttributeUpdater, UserResource, UserRepresentation> {
private final UserResource userResource; public static UserAttributeUpdater forUserByUsername(Keycloak adminClient, String realm, String userName) {
UsersResource users = adminClient.realm(realm).users();
List<UserRepresentation> foundUsers = users.search(userName);
assertThat(foundUsers, hasSize(1));
UserResource userRes = users.get(foundUsers.get(0).getId());
private final UserRepresentation rep; return new UserAttributeUpdater(userRes);
private final UserRepresentation origRep; }
public UserAttributeUpdater(UserResource userResource) { public UserAttributeUpdater(UserResource resource) {
this.userResource = userResource; super(resource, resource::toRepresentation, resource::update);
this.origRep = userResource.toRepresentation();
this.rep = userResource.toRepresentation();
if (this.rep.getAttributes() == null) { if (this.rep.getAttributes() == null) {
this.rep.setAttributes(new HashMap<>()); this.rep.setAttributes(new HashMap<>());
} }
@ -49,12 +57,6 @@ public class UserAttributeUpdater {
return this; return this;
} }
public Closeable update() {
userResource.update(rep);
return () -> userResource.update(origRep);
}
public UserAttributeUpdater setRequiredActions(UserModel.RequiredAction... requiredAction) { public UserAttributeUpdater setRequiredActions(UserModel.RequiredAction... requiredAction) {
rep.setRequiredActions(Arrays.stream(requiredAction) rep.setRequiredActions(Arrays.stream(requiredAction)
.map(action -> action.name()) .map(action -> action.name())
@ -62,4 +64,12 @@ public class UserAttributeUpdater {
); );
return this; return this;
} }
public RoleScopeUpdater realmRoleScope() {
return new RoleScopeUpdater(resource.roles().realmLevel());
}
public RoleScopeUpdater clientRoleScope(String clientUUID) {
return new RoleScopeUpdater(resource.roles().clientLevel(clientUUID));
}
} }

View file

@ -57,11 +57,16 @@ import org.keycloak.testsuite.pages.AppPage.RequestType;
import org.keycloak.testsuite.pages.ErrorPage; import org.keycloak.testsuite.pages.ErrorPage;
import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.pages.RegisterPage; import org.keycloak.testsuite.pages.RegisterPage;
import org.keycloak.testsuite.updaters.ClientAttributeUpdater;
import org.keycloak.testsuite.updaters.RoleScopeUpdater;
import org.keycloak.testsuite.util.IdentityProviderBuilder; import org.keycloak.testsuite.util.IdentityProviderBuilder;
import org.keycloak.testsuite.util.OAuthClient; import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.testsuite.util.RealmBuilder; import org.keycloak.testsuite.util.RealmBuilder;
import org.keycloak.testsuite.util.UIUtils; import org.keycloak.testsuite.util.UIUtils;
import org.keycloak.testsuite.util.UserBuilder; import org.keycloak.testsuite.util.UserBuilder;
import java.io.Closeable;
import java.io.IOException;
import java.util.Collections;
import org.openqa.selenium.By; import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriver;
@ -86,6 +91,9 @@ import static org.junit.Assert.assertTrue;
*/ */
public class AccountFormServiceTest extends AbstractTestRealmKeycloakTest { public class AccountFormServiceTest extends AbstractTestRealmKeycloakTest {
public static final String ROOT_URL_CLIENT = "root-url-client";
public static final String REALM_NAME = "test";
@Override @Override
public void configureTestRealm(RealmRepresentation testRealm) { public void configureTestRealm(RealmRepresentation testRealm) {
//UserRepresentation user = findUserInRealmRep(testRealm, "test-user@localhost"); //UserRepresentation user = findUserInRealmRep(testRealm, "test-user@localhost");
@ -1067,7 +1075,50 @@ public class AccountFormServiceTest extends AbstractTestRealmKeycloakTest {
events.clear(); events.clear();
} }
@Test
public void applicationsVisibilityNoScopesNoConsent() throws Exception {
try (ClientAttributeUpdater cau = ClientAttributeUpdater.forClient(adminClient, REALM_NAME, ROOT_URL_CLIENT)
.setConsentRequired(false)
.setFullScopeAllowed(false)
.setDefaultClientScopes(Collections.EMPTY_LIST)
.setOptionalClientScopes(Collections.EMPTY_LIST)
.update();
RoleScopeUpdater rsu = cau.realmRoleScope().update()) {
applicationsPage.open();
loginPage.login("john-doh@localhost", "password");
applicationsPage.assertCurrent();
Map<String, AccountApplicationsPage.AppEntry> apps = applicationsPage.getApplications();
Assert.assertThat(apps.keySet(), containsInAnyOrder(
/* "root-url-client", */ "Account", "test-app", "test-app-scope", "third-party", "test-app-authz", "My Named Test App", "Test App Named - ${client_account}", "direct-grant"));
rsu.add(testRealm().roles().get("user").toRepresentation())
.update();
driver.navigate().refresh();
apps = applicationsPage.getApplications();
Assert.assertThat(apps.keySet(), containsInAnyOrder(
"root-url-client", "Account", "test-app", "test-app-scope", "third-party", "test-app-authz", "My Named Test App", "Test App Named - ${client_account}", "direct-grant"));
}
}
@Test
public void applicationsVisibilityNoScopesAndConsent() throws Exception {
try (ClientAttributeUpdater cau = ClientAttributeUpdater.forClient(adminClient, REALM_NAME, ROOT_URL_CLIENT)
.setConsentRequired(true)
.setFullScopeAllowed(false)
.setDefaultClientScopes(Collections.EMPTY_LIST)
.setOptionalClientScopes(Collections.EMPTY_LIST)
.update()) {
applicationsPage.open();
loginPage.login("john-doh@localhost", "password");
applicationsPage.assertCurrent();
Map<String, AccountApplicationsPage.AppEntry> apps = applicationsPage.getApplications();
Assert.assertThat(apps.keySet(), containsInAnyOrder(
"root-url-client", "Account", "test-app", "test-app-scope", "third-party", "test-app-authz", "My Named Test App", "Test App Named - ${client_account}", "direct-grant"));
}
}
// More tests (including revoke) are in OAuthGrantTest and OfflineTokenTest // More tests (including revoke) are in OAuthGrantTest and OfflineTokenTest
@Test @Test
@ -1076,19 +1127,19 @@ public class AccountFormServiceTest extends AbstractTestRealmKeycloakTest {
loginPage.login("test-user@localhost", "password"); loginPage.login("test-user@localhost", "password");
events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=applications").assertEvent(); events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=applications").assertEvent();
Assert.assertTrue(applicationsPage.isCurrent()); applicationsPage.assertCurrent();
Map<String, AccountApplicationsPage.AppEntry> apps = applicationsPage.getApplications(); Map<String, AccountApplicationsPage.AppEntry> apps = applicationsPage.getApplications();
Assert.assertThat(apps.keySet(), containsInAnyOrder("root-url-client", "Account", "Broker", "test-app", "test-app-scope", "third-party", "test-app-authz", "My Named Test App", "Test App Named - ${client_account}", "direct-grant")); Assert.assertThat(apps.keySet(), containsInAnyOrder("root-url-client", "Account", "Broker", "test-app", "test-app-scope", "third-party", "test-app-authz", "My Named Test App", "Test App Named - ${client_account}", "direct-grant"));
AccountApplicationsPage.AppEntry accountEntry = apps.get("Account"); AccountApplicationsPage.AppEntry accountEntry = apps.get("Account");
Assert.assertEquals(4, accountEntry.getRolesAvailable().size()); Assert.assertThat(accountEntry.getRolesAvailable(), containsInAnyOrder(
Assert.assertTrue(accountEntry.getRolesAvailable().contains("Manage account links in Account")); "Manage account links in Account",
Assert.assertTrue(accountEntry.getRolesAvailable().contains("Manage account in Account")); "Manage account in Account",
Assert.assertTrue(accountEntry.getRolesAvailable().contains("View profile in Account")); "View profile in Account",
Assert.assertTrue(accountEntry.getRolesAvailable().contains("Offline access")); "Offline access"
Assert.assertEquals(1, accountEntry.getClientScopesGranted().size()); ));
Assert.assertTrue(accountEntry.getClientScopesGranted().contains("Full Access")); Assert.assertThat(accountEntry.getClientScopesGranted(), containsInAnyOrder("Full Access"));
Assert.assertEquals("http://localhost:8180/auth/realms/test/account", accountEntry.getHref()); Assert.assertEquals("http://localhost:8180/auth/realms/test/account", accountEntry.getHref());
AccountApplicationsPage.AppEntry testAppEntry = apps.get("test-app"); AccountApplicationsPage.AppEntry testAppEntry = apps.get("test-app");

View file

@ -24,6 +24,7 @@ import org.keycloak.testsuite.pages.OAuthGrantPage;
import org.keycloak.testsuite.util.ClientManager; import org.keycloak.testsuite.util.ClientManager;
import org.keycloak.testsuite.utils.io.IOUtil; import org.keycloak.testsuite.utils.io.IOUtil;
import org.keycloak.util.TokenUtil; import org.keycloak.util.TokenUtil;
import org.hamcrest.Matchers;
import org.openqa.selenium.By; import org.openqa.selenium.By;
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST; import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
@ -181,8 +182,8 @@ public class OfflineServletsAdapterTest extends AbstractServletsAdapterTest {
accountAppPage.open(); accountAppPage.open();
AccountApplicationsPage.AppEntry offlineClient = accountAppPage.getApplications().get("offline-client"); AccountApplicationsPage.AppEntry offlineClient = accountAppPage.getApplications().get("offline-client");
Assert.assertTrue(offlineClient.getClientScopesGranted().contains(OAuthGrantPage.OFFLINE_ACCESS_CONSENT_TEXT)); Assert.assertThat(offlineClient.getClientScopesGranted(), Matchers.hasItem(OAuthGrantPage.OFFLINE_ACCESS_CONSENT_TEXT));
Assert.assertTrue(offlineClient.getAdditionalGrants().contains("Offline Token")); Assert.assertThat(offlineClient.getAdditionalGrants(), Matchers.hasItem("Offline Token"));
//This was necessary to be introduced, otherwise other testcases will fail //This was necessary to be introduced, otherwise other testcases will fail
offlineTokenPage.logout(); offlineTokenPage.logout();

View file

@ -818,8 +818,7 @@ public class SAMLServletAdapterTest extends AbstractServletsAdapterTest {
@Test @Test
public void salesPostEncSignedAssertionsAndDocumentTest() throws Exception { public void salesPostEncSignedAssertionsAndDocumentTest() throws Exception {
ClientRepresentation salesPostEncClient = testRealmResource().clients().findByClientId(SalesPostEncServlet.CLIENT_NAME).get(0); try (Closeable client = ClientAttributeUpdater.forClient(adminClient, testRealmPage.getAuthRealm(), SalesPostEncServlet.CLIENT_NAME)
try (Closeable client = new ClientAttributeUpdater(testRealmResource().clients().get(salesPostEncClient.getId()))
.setAttribute(SamlConfigAttributes.SAML_ASSERTION_SIGNATURE, "true") .setAttribute(SamlConfigAttributes.SAML_ASSERTION_SIGNATURE, "true")
.setAttribute(SamlConfigAttributes.SAML_SERVER_SIGNATURE, "true") .setAttribute(SamlConfigAttributes.SAML_SERVER_SIGNATURE, "true")
.update()) { .update()) {
@ -831,8 +830,7 @@ public class SAMLServletAdapterTest extends AbstractServletsAdapterTest {
@Test @Test
public void salesPostEncRejectConsent() throws Exception { public void salesPostEncRejectConsent() throws Exception {
ClientRepresentation salesPostEncClient = testRealmResource().clients().findByClientId(SalesPostEncServlet.CLIENT_NAME).get(0); try (Closeable client = ClientAttributeUpdater.forClient(adminClient, testRealmPage.getAuthRealm(), SalesPostEncServlet.CLIENT_NAME)
try (Closeable client = new ClientAttributeUpdater(testRealmResource().clients().get(salesPostEncClient.getId()))
.setConsentRequired(true) .setConsentRequired(true)
.update()) { .update()) {
new SamlClientBuilder() new SamlClientBuilder()
@ -853,8 +851,7 @@ public class SAMLServletAdapterTest extends AbstractServletsAdapterTest {
@Test @Test
public void salesPostRejectConsent() throws Exception { public void salesPostRejectConsent() throws Exception {
ClientRepresentation salesPostClient = testRealmResource().clients().findByClientId(SalesPostServlet.CLIENT_NAME).get(0); try (Closeable client = ClientAttributeUpdater.forClient(adminClient, testRealmPage.getAuthRealm(), SalesPostServlet.CLIENT_NAME)
try (Closeable client = new ClientAttributeUpdater(testRealmResource().clients().get(salesPostClient.getId()))
.setConsentRequired(true) .setConsentRequired(true)
.update()) { .update()) {
new SamlClientBuilder() new SamlClientBuilder()

View file

@ -117,14 +117,6 @@ public class KcSamlSignedBrokerTest extends KcSamlBrokerTest {
} }
public void withSignedEncryptedAssertions(Runnable testBody, boolean signedAssertion, boolean encryptedAssertion) throws Exception { public void withSignedEncryptedAssertions(Runnable testBody, boolean signedAssertion, boolean encryptedAssertion) throws Exception {
ClientRepresentation client = adminClient.realm(bc.providerRealmName())
.clients()
.findByClientId(bc.getIDPClientIdInProviderRealm(suiteContext))
.get(0);
final ClientResource clientResource = realmsResouce().realm(bc.providerRealmName()).clients().get(client.getId());
Assert.assertThat(clientResource, Matchers.notNullValue());
String providerCert = KeyUtils.getActiveKey(adminClient.realm(bc.providerRealmName()).keys().getKeyMetadata(), Algorithm.RS256).getCertificate(); String providerCert = KeyUtils.getActiveKey(adminClient.realm(bc.providerRealmName()).keys().getKeyMetadata(), Algorithm.RS256).getCertificate();
Assert.assertThat(providerCert, Matchers.notNullValue()); Assert.assertThat(providerCert, Matchers.notNullValue());
@ -138,7 +130,7 @@ public class KcSamlSignedBrokerTest extends KcSamlBrokerTest {
.setAttribute(SAMLIdentityProviderConfig.WANT_AUTHN_REQUESTS_SIGNED, "false") .setAttribute(SAMLIdentityProviderConfig.WANT_AUTHN_REQUESTS_SIGNED, "false")
.setAttribute(SAMLIdentityProviderConfig.SIGNING_CERTIFICATE_KEY, providerCert) .setAttribute(SAMLIdentityProviderConfig.SIGNING_CERTIFICATE_KEY, providerCert)
.update(); .update();
Closeable clientUpdater = new ClientAttributeUpdater(clientResource) Closeable clientUpdater = ClientAttributeUpdater.forClient(adminClient, bc.providerRealmName(), bc.getIDPClientIdInProviderRealm(suiteContext))
.setAttribute(SamlConfigAttributes.SAML_ENCRYPT, Boolean.toString(encryptedAssertion)) .setAttribute(SamlConfigAttributes.SAML_ENCRYPT, Boolean.toString(encryptedAssertion))
.setAttribute(SamlConfigAttributes.SAML_ENCRYPTION_CERTIFICATE_ATTRIBUTE, consumerCert) .setAttribute(SamlConfigAttributes.SAML_ENCRYPTION_CERTIFICATE_ATTRIBUTE, consumerCert)
.setAttribute(SamlConfigAttributes.SAML_SERVER_SIGNATURE, "false") // only sign assertions .setAttribute(SamlConfigAttributes.SAML_SERVER_SIGNATURE, "false") // only sign assertions
@ -269,14 +261,6 @@ public class KcSamlSignedBrokerTest extends KcSamlBrokerTest {
@Test @Test
public void testWithExpiredBrokerCertificate() throws Exception { public void testWithExpiredBrokerCertificate() throws Exception {
ClientRepresentation client = adminClient.realm(bc.providerRealmName())
.clients()
.findByClientId(bc.getIDPClientIdInProviderRealm(suiteContext))
.get(0);
final ClientResource clientResource = realmsResouce().realm(bc.providerRealmName()).clients().get(client.getId());
Assert.assertThat(clientResource, Matchers.notNullValue());
try (Closeable idpUpdater = new IdentityProviderAttributeUpdater(identityProviderResource) try (Closeable idpUpdater = new IdentityProviderAttributeUpdater(identityProviderResource)
.setAttribute(SAMLIdentityProviderConfig.VALIDATE_SIGNATURE, Boolean.toString(true)) .setAttribute(SAMLIdentityProviderConfig.VALIDATE_SIGNATURE, Boolean.toString(true))
.setAttribute(SAMLIdentityProviderConfig.WANT_ASSERTIONS_SIGNED, Boolean.toString(true)) .setAttribute(SAMLIdentityProviderConfig.WANT_ASSERTIONS_SIGNED, Boolean.toString(true))
@ -284,7 +268,7 @@ public class KcSamlSignedBrokerTest extends KcSamlBrokerTest {
.setAttribute(SAMLIdentityProviderConfig.WANT_AUTHN_REQUESTS_SIGNED, "true") .setAttribute(SAMLIdentityProviderConfig.WANT_AUTHN_REQUESTS_SIGNED, "true")
.setAttribute(SAMLIdentityProviderConfig.SIGNING_CERTIFICATE_KEY, AbstractSamlTest.SAML_CLIENT_SALES_POST_SIG_EXPIRED_CERTIFICATE) .setAttribute(SAMLIdentityProviderConfig.SIGNING_CERTIFICATE_KEY, AbstractSamlTest.SAML_CLIENT_SALES_POST_SIG_EXPIRED_CERTIFICATE)
.update(); .update();
Closeable clientUpdater = new ClientAttributeUpdater(clientResource) Closeable clientUpdater = ClientAttributeUpdater.forClient(adminClient, bc.providerRealmName(), bc.getIDPClientIdInProviderRealm(suiteContext))
.setAttribute(SamlConfigAttributes.SAML_ENCRYPT, Boolean.toString(false)) .setAttribute(SamlConfigAttributes.SAML_ENCRYPT, Boolean.toString(false))
.setAttribute(SamlConfigAttributes.SAML_SERVER_SIGNATURE, "true") .setAttribute(SamlConfigAttributes.SAML_SERVER_SIGNATURE, "true")
.setAttribute(SamlConfigAttributes.SAML_ASSERTION_SIGNATURE, Boolean.toString(true)) .setAttribute(SamlConfigAttributes.SAML_ASSERTION_SIGNATURE, Boolean.toString(true))

View file

@ -244,11 +244,8 @@ public class LogoutTest extends AbstractTestRealmKeycloakTest {
// KEYCLOAK-5982 // KEYCLOAK-5982
@Test @Test
public void testLogoutWhenAccountClientRenamed() throws IOException { public void testLogoutWhenAccountClientRenamed() throws IOException {
// Rename client "account"
ClientResource accountClient = ApiUtil.findClientByClientId(adminClient.realm("test"), Constants.ACCOUNT_MANAGEMENT_CLIENT_ID);
// Temporarily rename client "account" . Revert it back after the test // Temporarily rename client "account" . Revert it back after the test
try (Closeable accountClientUpdater = new ClientAttributeUpdater(accountClient) try (Closeable accountClientUpdater = ClientAttributeUpdater.forClient(adminClient, "test", Constants.ACCOUNT_MANAGEMENT_CLIENT_ID)
.setClientId("account-changed") .setClientId("account-changed")
.update()) { .update()) {

View file

@ -1011,10 +1011,8 @@ public class ResetPasswordTest extends AbstractTestRealmKeycloakTest {
// KEYCLOAK-5982 // KEYCLOAK-5982
@Test @Test
public void resetPasswordLinkOpenedInNewBrowserAndAccountClientRenamed() throws IOException, MessagingException { public void resetPasswordLinkOpenedInNewBrowserAndAccountClientRenamed() throws IOException, MessagingException {
ClientResource accountClient = ApiUtil.findClientByClientId(adminClient.realm("test"), Constants.ACCOUNT_MANAGEMENT_CLIENT_ID);
// Temporarily rename client "account" . Revert it back after the test // Temporarily rename client "account" . Revert it back after the test
try (Closeable accountClientUpdater = new ClientAttributeUpdater(accountClient) try (Closeable accountClientUpdater = ClientAttributeUpdater.forClient(adminClient, "test", Constants.ACCOUNT_MANAGEMENT_CLIENT_ID)
.setClientId("account-changed") .setClientId("account-changed")
.update()) { .update()) {

View file

@ -59,12 +59,7 @@ public class IncludeOneTimeUseConditionTest extends AbstractSamlTest
private void testOneTimeUseConditionIncluded(Boolean oneTimeUseConditionShouldBeIncluded) throws IOException private void testOneTimeUseConditionIncluded(Boolean oneTimeUseConditionShouldBeIncluded) throws IOException
{ {
ClientsResource clients = adminClient.realm(REALM_NAME).clients(); try (Closeable c = ClientAttributeUpdater.forClient(adminClient, REALM_NAME, SAML_CLIENT_ID_SALES_POST)
List<ClientRepresentation> foundClients = clients.findByClientId(SAML_CLIENT_ID_SALES_POST);
assertThat(foundClients, hasSize(1));
ClientResource clientRes = clients.get(foundClients.get(0).getId());
try (Closeable c = new ClientAttributeUpdater(clientRes)
.setAttribute(SamlConfigAttributes.SAML_ONETIMEUSE_CONDITION, oneTimeUseConditionShouldBeIncluded.toString()) .setAttribute(SamlConfigAttributes.SAML_ONETIMEUSE_CONDITION, oneTimeUseConditionShouldBeIncluded.toString())
.update()) { .update()) {

View file

@ -16,7 +16,6 @@
*/ */
package org.keycloak.testsuite.saml; package org.keycloak.testsuite.saml;
import org.keycloak.admin.client.resource.ClientsResource;
import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.broker.saml.SAMLIdentityProviderConfig; import org.keycloak.broker.saml.SAMLIdentityProviderConfig;
import org.keycloak.broker.saml.SAMLIdentityProviderFactory; import org.keycloak.broker.saml.SAMLIdentityProviderFactory;
@ -361,10 +360,9 @@ public class LogoutTest extends AbstractSamlTest {
@Test @Test
public void testLogoutPropagatesToSamlIdentityProvider() throws IOException { public void testLogoutPropagatesToSamlIdentityProvider() throws IOException {
final RealmResource realm = adminClient.realm(REALM_NAME); final RealmResource realm = adminClient.realm(REALM_NAME);
final ClientsResource clients = realm.clients();
try ( try (
Closeable sales = new ClientAttributeUpdater(clients.get(salesRep.getId())) Closeable sales = ClientAttributeUpdater.forClient(adminClient, REALM_NAME, SAML_CLIENT_ID_SALES_POST)
.setFrontchannelLogout(true) .setFrontchannelLogout(true)
.removeAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_POST_ATTRIBUTE) .removeAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_POST_ATTRIBUTE)
.setAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_ATTRIBUTE, "http://url") .setAttribute(SamlProtocol.SAML_SINGLE_LOGOUT_SERVICE_URL_REDIRECT_ATTRIBUTE, "http://url")