/* * Copyright 2013 Robert von Burg <eitch@eitchnet.ch> * * 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 li.strolch.privilege.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.fail; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import li.strolch.privilege.base.AccessDeniedException; import li.strolch.privilege.base.PrivilegeException; import li.strolch.privilege.handler.PrivilegeHandler; import li.strolch.privilege.i18n.PrivilegeMessages; import li.strolch.privilege.model.Certificate; import li.strolch.privilege.model.PrivilegeRep; import li.strolch.privilege.model.Restrictable; import li.strolch.privilege.model.RoleRep; import li.strolch.privilege.model.UserRep; import li.strolch.privilege.model.UserState; import li.strolch.privilege.test.model.TestRestrictable; import li.strolch.privilege.test.model.TestSystemUserAction; import li.strolch.privilege.test.model.TestSystemUserActionDeny; import li.strolch.utils.helper.ArraysHelper; /** * JUnit for performing Privilege tests. This JUnit is by no means complete, but checks the bare minimum.br /> * * TODO add more tests, especially with deny and allow lists * * @author Robert von Burg <eitch@eitchnet.ch> */ @SuppressWarnings("nls") public class PrivilegeTest extends AbstractPrivilegeTest { private static final String ROLE_PRIVILEGE_ADMIN = "PrivilegeAdmin"; private static final String PRIVILEGE_USER_ACCESS = "UserAccessPrivilege"; private static final String ADMIN = "admin"; private static final byte[] PASS_ADMIN = "admin".getBytes(); private static final String BOB = "bob"; private static final String TED = "ted"; private static final String SYSTEM_USER_ADMIN = "system_admin"; private static final String SYSTEM_USER_ADMIN2 = "system_admin2"; private static final byte[] PASS_BOB = "admin1".getBytes(); private static final String ROLE_APP_USER = "AppUser"; private static final String ROLE_MY = "MyRole"; private static final String ROLE_MY2 = "MyRole2"; private static final String ROLE_CHANGE_PW = "changePw"; private static final String ROLE_TEMP = "temp"; private static final String ROLE_USER = "user"; private static final byte[] PASS_DEF = "def".getBytes(); private static final byte[] PASS_BAD = "123".getBytes(); private static final byte[] PASS_TED = "12345".getBytes(); private static final Logger logger = LoggerFactory.getLogger(PrivilegeTest.class); @Rule public ExpectedException exception = ExpectedException.none(); @BeforeClass public static void init() throws Exception { removeConfigs(PrivilegeTest.class.getSimpleName()); prepareConfigs(PrivilegeTest.class.getSimpleName(), "PrivilegeConfig.xml", "PrivilegeUsers.xml", "PrivilegeRoles.xml"); } @AfterClass public static void destroy() throws Exception { removeConfigs(PrivilegeTest.class.getSimpleName()); } @Before public void setup() throws Exception { initialize(PrivilegeTest.class.getSimpleName(), "PrivilegeConfig.xml"); } @Test public void testAuthenticationOk() throws Exception { try { login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); } finally { logout(); } } public void testFailAuthenticationNOk() throws Exception { this.exception.expect(AccessDeniedException.class); this.exception.expectMessage("blabla"); try { login(ADMIN, ArraysHelper.copyOf(PASS_BAD)); } finally { logout(); } } public void testFailAuthenticationPWNull() throws Exception { this.exception.expect(PrivilegeException.class); this.exception.expectMessage("blabla"); try { login(ADMIN, null); } finally { logout(); } } @Test public void testAddRoleTemp() throws Exception { try { login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); RoleRep roleRep = new RoleRep(ROLE_TEMP, new ArrayList<>()); Certificate certificate = this.ctx.getCertificate(); privilegeHandler.addRole(certificate, roleRep); privilegeHandler.persist(certificate); } finally { logout(); } } @Test public void testPerformRestrictableAsAdmin() throws Exception { try { login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); // see if admin can perform restrictable Restrictable restrictable = new TestRestrictable(); this.ctx.validateAction(restrictable); } finally { logout(); } } /** * Tests if an action can be performed as a system user */ @Test public void testPerformSystemRestrictable() throws Exception { // create the action to be performed as a system user and then perform the action TestSystemUserAction action = new TestSystemUserAction(); privilegeHandler.runAsSystem(SYSTEM_USER_ADMIN, action); } /** * Checks that the system user can not perform a valid action, but illegal privilege */ @Test public void testPerformSystemRestrictableFailPrivilege() throws Exception { this.exception.expect(PrivilegeException.class); this.exception.expectMessage( "User system_admin does not have the privilege li.strolch.privilege.handler.SystemUserAction"); try { // create the action to be performed as a system user TestSystemUserActionDeny action = new TestSystemUserActionDeny(); // and then perform the action privilegeHandler.runAsSystem(SYSTEM_USER_ADMIN, action); } finally { logout(); } } /** * Checks that the system user can not perform a valid action, but illegal privilege */ @Test public void testPerformSystemRestrictableFailNoAdditionalPrivilege() throws Exception { this.exception.expect(PrivilegeException.class); this.exception.expectMessage( "User system_admin2 does not have the privilege li.strolch.privilege.handler.SystemUserAction needed for Restrictable li.strolch.privilege.test.model.TestSystemUserActionDeny"); try { // create the action to be performed as a system user TestSystemUserActionDeny action = new TestSystemUserActionDeny(); // and then perform the action privilegeHandler.runAsSystem(SYSTEM_USER_ADMIN2, action); } finally { logout(); } } /** * System user may not login */ @Test public void testLoginSystemUser() throws Exception { this.exception.expect(AccessDeniedException.class); this.exception.expectMessage("User system_admin is a system user and may not login!"); try { login(SYSTEM_USER_ADMIN, SYSTEM_USER_ADMIN.getBytes()); } finally { logout(); } } @Test public void testPrivilegeContext() { try { login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); Restrictable restrictable = new TestRestrictable(); this.ctx.validateAction(restrictable); } finally { logout(); } } @Test public void shouldUpdateAdmin() { try { login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); Certificate certificate = this.ctx.getCertificate(); // validate name is not yet set UserRep user = privilegeHandler.getUser(certificate, ADMIN); assertNotEquals("The", user.getFirstname()); assertNotEquals("Admin", user.getLastname()); // let's add a new user bob UserRep userRep = new UserRep(null, ADMIN, "The", "Admin", null, null, null, null); privilegeHandler.updateUser(certificate, userRep); user = privilegeHandler.getUser(certificate, ADMIN); assertEquals("The", user.getFirstname()); assertEquals("Admin", user.getLastname()); } finally { logout(); } } @Test public void shouldFailUpdateInexistantUser() { exception.expect(PrivilegeException.class); exception.expectMessage("User bob does not exist"); try { login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); Certificate certificate = this.ctx.getCertificate(); // let's add a new user bob UserRep userRep = new UserRep(null, BOB, null, null, null, null, null, null); privilegeHandler.updateUser(certificate, userRep); } finally { logout(); } } @Test public void shouldFailUpdateAdminNoChanges() { exception.expect(PrivilegeException.class); exception.expectMessage("All updateable fields are empty for update of user admin"); try { login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); Certificate certificate = this.ctx.getCertificate(); // let's add a new user bob UserRep userRep = new UserRep(null, ADMIN, null, null, null, null, null, null); privilegeHandler.updateUser(certificate, userRep); } finally { logout(); } } @Test public void shouldQueryUsers() { try { login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); Certificate certificate = this.ctx.getCertificate(); UserRep selectorRep = new UserRep(null, ADMIN, null, null, null, null, null, null); List<UserRep> users = privilegeHandler.queryUsers(certificate, selectorRep); assertEquals(1, users.size()); assertEquals(ADMIN, users.get(0).getUsername()); } finally { logout(); } } @Test public void shouldQueryUsersByRoles() { try { login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); Certificate certificate = this.ctx.getCertificate(); UserRep selectorRep = new UserRep(null, null, null, null, null, new HashSet<>(Arrays.asList("PrivilegeAdmin")), null, null); List<UserRep> users = privilegeHandler.queryUsers(certificate, selectorRep); assertEquals(1, users.size()); assertEquals(ADMIN, users.get(0).getUsername()); } finally { logout(); } } @Test public void shouldQueryUsersByRoles2() { try { login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); Certificate certificate = this.ctx.getCertificate(); UserRep selectorRep = new UserRep(null, null, null, null, null, new HashSet<>(Arrays.asList(ROLE_TEMP)), null, null); List<UserRep> users = privilegeHandler.queryUsers(certificate, selectorRep); assertEquals(0, users.size()); } finally { logout(); } } @Test public void shouldDetectPrivilegeConflict1() { exception.expect(PrivilegeException.class); exception.expectMessage("User admin has conflicts for privilege "); try { login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); Certificate certificate = this.ctx.getCertificate(); PrivilegeRep privilegeRep = new PrivilegeRep(PrivilegeHandler.PRIVILEGE_ACTION, "DefaultPrivilege", true, Collections.emptySet(), Collections.emptySet()); privilegeHandler.addOrReplacePrivilegeOnRole(certificate, ROLE_APP_USER, privilegeRep); } finally { logout(); } } @Test public void shouldDetectPrivilegeConflict2() { exception.expect(PrivilegeException.class); exception.expectMessage("User admin has conflicts for privilege "); try { login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); Certificate certificate = this.ctx.getCertificate(); privilegeHandler.addRoleToUser(certificate, ADMIN, ROLE_MY); privilegeHandler.addRoleToUser(certificate, ADMIN, ROLE_MY2); } finally { logout(); } } /** * This test performs multiple tests which are dependent on each other as the following is done: * <ul> * <li>add user bob</li> * <li>fail to auth as bob as user is not enabled</li> * <li>enable bob</li> * <li>fail to auth as bot as bob has no role</li> * <li>add role user to bob</li> * <li>auth as bob</li> * <li>fail to add user ted as bob as bob is not admin</li> * <li>add admin role to bob</li> * <li>add user ted as bob</li> * <li>fail to auth as ted as ted has no password</li> * <li>set ted's password as bob</li> * <li>ted changes own password</li> * <li>auth as ted</li> * <li>fail to perform restrictable as bob as no app role</li> * <li>add app role to bob</li> * <li>perform restrictable as bob</li> * </ul> */ @Test public void testUserStory() throws Exception { addBobAsAdmin(); failAuthAsBobNotEnabled(); enableBob(); addRoleUser(); addRoleUserToBob(); authAsBob(); failAddTedAsBobNotAdmin(); addRoleAdminToBob(); addTedAsBob(); failAuthAsTedNoPass(); setPassForTedAsBob(); failSetSystemStateTed(); failTedChangesPwAndLocale(); addChangePwRoleToTed(); tedChangesOwnPassAndLocale(); failTedChangesOtherPwStateAndLocale(); authAsTed(); failPerformRestrictableAsBobNoRoleApp(); addRoleAppToBob(); performRestrictableAsBob(); } private void failSetSystemStateTed() { try { // testEnableUserBob login(BOB, ArraysHelper.copyOf(PASS_BOB)); Certificate certificate = this.ctx.getCertificate(); try { privilegeHandler.setUserState(certificate, TED, UserState.SYSTEM); fail("Should not be able to set user state to SYSTEM"); } catch (AccessDeniedException e) { // ok } } finally { logout(); } } private void failTedChangesOtherPwStateAndLocale() { try { // testTedChangesOwnPwd login(TED, ArraysHelper.copyOf(PASS_TED)); Certificate certificate = this.ctx.getCertificate(); try { privilegeHandler.setUserPassword(certificate, BOB, ArraysHelper.copyOf(PASS_TED)); fail("Should not be able to set password of other user, as missing privilege"); } catch (AccessDeniedException e) { // ok } try { privilegeHandler.setUserLocale(certificate, BOB, Locale.FRENCH); fail("Should not be able to set locale of other user, as missing privilege"); } catch (AccessDeniedException e) { // ok } try { privilegeHandler.setUserState(certificate, BOB, UserState.DISABLED); fail("Should not be able to set state of other user, as missing privilege"); } catch (AccessDeniedException e) { // ok } } finally { logout(); } } private void failTedChangesPwAndLocale() { try { // testTedChangesOwnPwd login(TED, ArraysHelper.copyOf(PASS_DEF)); Certificate certificate = this.ctx.getCertificate(); try { privilegeHandler.setUserPassword(certificate, TED, ArraysHelper.copyOf(PASS_TED)); fail("Should not be able to set password, as missing privilege"); } catch (AccessDeniedException e) { // ok } try { privilegeHandler.setUserLocale(certificate, TED, Locale.FRENCH); fail("Should not be able to set locale, as missing privilege"); } catch (AccessDeniedException e) { // ok } try { privilegeHandler.setUserState(certificate, TED, UserState.ENABLED); fail("Should not be able to set state, as missing privilege"); } catch (AccessDeniedException e) { // ok } } finally { logout(); } } private void addChangePwRoleToTed() { try { // add role user login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); PrivilegeRep passwordRep = new PrivilegeRep(PrivilegeHandler.PRIVILEGE_SET_USER_PASSWORD, PRIVILEGE_USER_ACCESS, false, Collections.emptySet(), Collections.emptySet()); PrivilegeRep localeRep = new PrivilegeRep(PrivilegeHandler.PRIVILEGE_SET_USER_LOCALE, PRIVILEGE_USER_ACCESS, false, Collections.emptySet(), Collections.emptySet()); RoleRep roleRep = new RoleRep(ROLE_CHANGE_PW, Arrays.asList(passwordRep, localeRep)); Certificate certificate = this.ctx.getCertificate(); privilegeHandler.addRole(certificate, roleRep); privilegeHandler.addRoleToUser(certificate, TED, ROLE_CHANGE_PW); logger.info("Added " + ROLE_CHANGE_PW + " to " + TED); privilegeHandler.persist(certificate); } finally { logout(); } } private void performRestrictableAsBob() { try { // testPerformRestrictableAsBob // Tests if the user bob, who now has AppUser role can perform restrictable login(BOB, ArraysHelper.copyOf(PASS_BOB)); // see if bob can perform restrictable Restrictable restrictable = new TestRestrictable(); this.ctx.validateAction(restrictable); } finally { logout(); } } private void addRoleAppToBob() { try { // testAddAppRoleToBob login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); Certificate certificate = this.ctx.getCertificate(); privilegeHandler.addRoleToUser(certificate, BOB, ROLE_APP_USER); logger.info("Added " + ROLE_APP_USER + " to " + BOB); privilegeHandler.persist(certificate); } finally { logout(); } } private void failPerformRestrictableAsBobNoRoleApp() { try { // testFailPerformRestrictableAsBob // Tests if the user bob, who does not have AppUser role can perform restrictable // this will fail as bob does not have role app login(BOB, ArraysHelper.copyOf(PASS_BOB)); // see if bob can perform restrictable Restrictable restrictable = new TestRestrictable(); this.ctx.validateAction(restrictable); fail("Should fail as bob does not have role app"); } catch (AccessDeniedException e) { String msg = "User bob does not have the privilege li.strolch.privilege.test.model.TestRestrictable needed for Restrictable li.strolch.privilege.test.model.TestRestrictable"; assertEquals(msg, e.getLocalizedMessage()); } finally { logout(); } } private void authAsTed() { try { // testAuthAsTed login(TED, ArraysHelper.copyOf(PASS_TED)); } finally { logout(); } } private void tedChangesOwnPassAndLocale() { try { // testTedChangesOwnPwd login(TED, ArraysHelper.copyOf(PASS_DEF)); Certificate certificate = this.ctx.getCertificate(); privilegeHandler.setUserPassword(certificate, TED, ArraysHelper.copyOf(PASS_TED)); privilegeHandler.setUserLocale(certificate, TED, Locale.FRENCH); } finally { logout(); } } private void setPassForTedAsBob() { try { // testSetTedPwdAsBob login(BOB, ArraysHelper.copyOf(PASS_BOB)); // set ted's password to default Certificate certificate = this.ctx.getCertificate(); privilegeHandler.setUserPassword(certificate, TED, ArraysHelper.copyOf(PASS_DEF)); privilegeHandler.persist(certificate); } finally { logout(); } } private void failAuthAsTedNoPass() { try { // testFailAuthAsTedNoPass // Will fail because user ted has no password login(TED, ArraysHelper.copyOf(PASS_TED)); fail("User Ted may not authenticate because the user has no password!"); } catch (PrivilegeException e) { String msg = "User ted has no password and may not login!"; assertEquals(msg, e.getMessage()); } finally { logout(); } } private void addTedAsBob() { try { UserRep userRep; // testAddUserTedAsBob login(BOB, ArraysHelper.copyOf(PASS_BOB)); // let's add a new user ted HashSet<String> roles = new HashSet<>(); roles.add(ROLE_USER); userRep = new UserRep(null, TED, "Ted", "Newman", UserState.ENABLED, roles, null, new HashMap<String, String>()); Certificate certificate = this.ctx.getCertificate(); privilegeHandler.addUser(certificate, userRep, null); logger.info("Added user " + TED); privilegeHandler.persist(certificate); } finally { logout(); } } private void addRoleAdminToBob() { try { // testAddAdminRoleToBob login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); Certificate certificate = this.ctx.getCertificate(); privilegeHandler.addRoleToUser(certificate, BOB, ROLE_PRIVILEGE_ADMIN); logger.info("Added " + ROLE_PRIVILEGE_ADMIN + " to " + ADMIN); privilegeHandler.persist(certificate); } finally { logout(); } } private void failAddTedAsBobNotAdmin() { Certificate certificate = null; try { UserRep userRep; // testFailAddUserTedAsBob // Will fail because user bob does not have admin rights // auth as Bob login(BOB, ArraysHelper.copyOf(PASS_BOB)); // let's add a new user Ted userRep = new UserRep("1", TED, "Ted", "And then Some", UserState.NEW, new HashSet<String>(), null, new HashMap<String, String>()); certificate = this.ctx.getCertificate(); privilegeHandler.addUser(certificate, userRep, null); fail("User bob may not add a user as bob does not have admin rights!"); } catch (PrivilegeException e) { String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.noprivilege.user"), //$NON-NLS-1$ BOB, PrivilegeHandler.PRIVILEGE_ADD_USER); assertEquals(msg, e.getMessage()); } finally { logout(); } } private void authAsBob() { try { // testAuthAsBob login(BOB, ArraysHelper.copyOf(PASS_BOB)); } finally { logout(); } } private void addRoleUserToBob() { try { // testAddRoleUserToBob login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); Certificate certificate = this.ctx.getCertificate(); privilegeHandler.addRoleToUser(certificate, BOB, ROLE_USER); privilegeHandler.persist(certificate); logout(); } finally { logout(); } } private void addRoleUser() { try { // add role user login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); RoleRep roleRep = new RoleRep(ROLE_USER, new ArrayList<>()); Certificate certificate = this.ctx.getCertificate(); privilegeHandler.addRole(certificate, roleRep); privilegeHandler.persist(certificate); } finally { logout(); } } private void enableBob() { try { // testEnableUserBob login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); Certificate certificate = this.ctx.getCertificate(); privilegeHandler.setUserState(certificate, BOB, UserState.ENABLED); privilegeHandler.persist(certificate); } finally { logout(); } } private void failAuthAsBobNotEnabled() { try { // testFailAuthAsBob // Will fail because user bob is not yet enabled privilegeHandler.authenticate(BOB, ArraysHelper.copyOf(PASS_BOB)); fail("User Bob may not authenticate because the user is not yet enabled!"); } catch (PrivilegeException e) { String msg = "User bob does not have state ENABLED and can not login!"; assertEquals(msg, e.getMessage()); } finally { logout(); } } private void addBobAsAdmin() { try { login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN)); // let's add a new user bob UserRep userRep = new UserRep(null, BOB, "Bob", "Newman", UserState.NEW, new HashSet<>(Arrays.asList(ROLE_MY)), null, new HashMap<String, String>()); Certificate certificate = this.ctx.getCertificate(); privilegeHandler.addUser(certificate, userRep, null); logger.info("Added user " + BOB); // set bob's password privilegeHandler.setUserPassword(certificate, BOB, ArraysHelper.copyOf(PASS_BOB)); logger.info("Set Bob's password"); privilegeHandler.persist(certificate); } finally { logout(); } } }