/*
* 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.model;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.keycloak.models.ClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.RealmManager;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class CompositeRolesModelTest extends AbstractModelTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Before
@Override
public void before() throws Exception {
super.before();
RealmManager manager = realmManager;
RealmRepresentation rep = AbstractModelTest.loadJson("model/testcomposites.json");
rep.setId("TestComposites");
manager.importRealm(rep);
}
@Test
public void testNoClientID() throws IOException {
RealmManager manager = realmManager;
RealmRepresentation rep = AbstractModelTest.loadJson("model/testrealm-noclient-id.json");
rep.setId("TestNoClientID");
expectedException.expect(RuntimeException.class);
expectedException.expectMessage("Unknown client specification in scope mappings: some-client");
manager.importRealm(rep);
}
@Test
public void testComposites() {
Set<RoleModel> requestedRoles = getRequestedRoles("APP_COMPOSITE_APPLICATION", "APP_COMPOSITE_USER");
Assert.assertEquals(5, requestedRoles.size());
assertContains("APP_COMPOSITE_APPLICATION", "APP_COMPOSITE_ROLE", requestedRoles);
assertContains("APP_COMPOSITE_APPLICATION", "APP_COMPOSITE_CHILD", requestedRoles);
assertContains("APP_COMPOSITE_APPLICATION", "APP_ROLE_2", requestedRoles);
assertContains("APP_ROLE_APPLICATION", "APP_ROLE_1", requestedRoles);
assertContains("realm", "REALM_ROLE_1", requestedRoles);
requestedRoles = getRequestedRoles("APP_COMPOSITE_APPLICATION", "REALM_APP_COMPOSITE_USER");
Assert.assertEquals(4, requestedRoles.size());
assertContains("APP_ROLE_APPLICATION", "APP_ROLE_1", requestedRoles);
requestedRoles = getRequestedRoles("REALM_COMPOSITE_1_APPLICATION", "REALM_COMPOSITE_1_USER");
Assert.assertEquals(1, requestedRoles.size());
assertContains("realm", "REALM_COMPOSITE_1", requestedRoles);
requestedRoles = getRequestedRoles("REALM_COMPOSITE_2_APPLICATION", "REALM_COMPOSITE_1_USER");
Assert.assertEquals(3, requestedRoles.size());
assertContains("realm", "REALM_COMPOSITE_1", requestedRoles);
assertContains("realm", "REALM_COMPOSITE_CHILD", requestedRoles);
assertContains("realm", "REALM_ROLE_4", requestedRoles);
requestedRoles = getRequestedRoles("REALM_ROLE_1_APPLICATION", "REALM_COMPOSITE_1_USER");
Assert.assertEquals(1, requestedRoles.size());
assertContains("realm", "REALM_ROLE_1", requestedRoles);
requestedRoles = getRequestedRoles("REALM_COMPOSITE_1_APPLICATION", "REALM_ROLE_1_USER");
Assert.assertEquals(1, requestedRoles.size());
assertContains("realm", "REALM_ROLE_1", requestedRoles);
}
// Same algorithm as in TokenManager.createAccessCode
private Set<RoleModel> getRequestedRoles(String applicationName, String username) {
Set<RoleModel> requestedRoles = new HashSet<RoleModel>();
RealmModel realm = realmManager.getRealm("TestComposites");
UserModel user = realmManager.getSession().users().getUserByUsername(username, realm);
ClientModel application = realm.getClientByClientId(applicationName);
Set<RoleModel> roleMappings = user.getRoleMappings();
Set<RoleModel> scopeMappings = application.getScopeMappings();
Set<RoleModel> appRoles = application.getRoles();
if (appRoles != null) scopeMappings.addAll(appRoles);
for (RoleModel role : roleMappings) {
if (role.getContainer().equals(application)) requestedRoles.add(role);
for (RoleModel desiredRole : scopeMappings) {
Set<RoleModel> visited = new HashSet<RoleModel>();
applyScope(role, desiredRole, visited, requestedRoles);
}
}
return requestedRoles;
}
private static void applyScope(RoleModel role, RoleModel scope, Set<RoleModel> visited, Set<RoleModel> requested) {
if (visited.contains(scope)) return;
visited.add(scope);
if (role.hasRole(scope)) {
requested.add(scope);
return;
}
if (!scope.isComposite()) return;
for (RoleModel contained : scope.getComposites()) {
applyScope(role, contained, visited, requested);
}
}
private RoleModel getRole(String appName, String roleName) {
RealmModel realm = realmManager.getRealm("TestComposites");
if ("realm".equals(appName)) {
return realm.getRole(roleName);
} else {
return realm.getClientByClientId(appName).getRole(roleName);
}
}
private void assertContains(String appName, String roleName, Set<RoleModel> requestedRoles) {
RoleModel expectedRole = getRole(appName, roleName);
Assert.assertTrue(requestedRoles.contains(expectedRole));
// Check if requestedRole has correct role container
for (RoleModel role : requestedRoles) {
if (role.equals(expectedRole)) {
Assert.assertEquals(role.getContainer(), expectedRole.getContainer());
}
}
}
}