/** * Copyright (c) 2009-2011 VMware, Inc. All Rights Reserved. * * 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 com.springsource.insight.plugin.spring.security; import java.util.Collection; import java.util.UUID; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import com.springsource.insight.collection.ObscuredValueSetMarker; import com.springsource.insight.intercept.endpoint.EndPointAnalysis; import com.springsource.insight.intercept.operation.Operation; import com.springsource.insight.intercept.operation.OperationList; import com.springsource.insight.intercept.operation.OperationMap; /** * */ public class UserDetailsManagerCollectionAspectTest extends SpringSecurityCollectionTestSupport { private final TestingUserDetailsManager manager = new TestingUserDetailsManager(); private static final ObscuredValueSetMarker marker = new ObscuredValueSetMarker(); public UserDetailsManagerCollectionAspectTest() { super(); } @BeforeClass public static void setupObscuringMarker() { UserDetailsManagerCollectionAspect.aspectOf().setSensitiveValueMarker(marker); } @Override @Before public void setUp() { super.setUp(); // making sure again marker.clear(); manager.clearUsers(); } @Override @After public void restore() { super.restore(); marker.clear(); manager.clearUsers(); } /* * NOTE: we are using a mock on purpose in order to ensure that the aspect * intercepts the {@link UserDetailsService} call(s) as well as the * {@link UserDetailsManager} ones since UserDetailsManager extends UserDetailsService */ @Test public void testLoadUserByUsername() { final String USERNAME = "testLoadUserByUsername"; manager.addUser(createUser(USERNAME)); UserDetails result = manager.loadUserByUsername(USERNAME); assertNotNull("Mismatched loaded user instances", result); // the result is created by the UserDetailsOperationCollector Operation op = assertOperationResult("loadUserByUsername", result, UserDetailsOperationCollector.RESULT_MAP_NAME); assertExtractedUsername(op, USERNAME); assertScoreValue(op, SpringSecurityDefinitions.SECURITY_OPERATION_ENDPOINT_SCORE); } @Test public void testCreateUser() { UserDetails user = createUser("testCreateUser"); manager.createUser(user); assertOperationResult("createUser", user, "userDetails"); } @Test public void testUpdateUser() { manager.addUser(createUser("testUpdateUser")); UserDetails user = createUser("testUpdateUser"); manager.updateUser(user); assertOperationResult("updateUser", user, "userDetails"); } @Test public void testDeleteUser() { final String USERNAME = "testDeleteUser"; manager.addUser(createUser(USERNAME)); manager.deleteUser(USERNAME); assertExtractedUsername("deleteUser", USERNAME); } @Test public void testUserExists() { final String USERNAME = "testUserExists"; manager.userExists(USERNAME); Operation op = assertExtractedUsername("userExists", USERNAME); assertScoreValue(op, SpringSecurityDefinitions.SECURITY_OPERATION_ENDPOINT_SCORE); } @Test public void testChangePassword() { UserDetails user = createUser("testChangePassword"); manager.addUser(user); manager.setCurrentUser(user.getUsername()); String oldPassword = user.getPassword(), newPassword = UUID.randomUUID().toString(); manager.changePassword(oldPassword, newPassword); Operation op = assertOperationAction("changePassword"); assertEquals("Mismatched old password", oldPassword, op.get("oldPassword", String.class)); assertObscuredString("oldPassword", oldPassword); assertEquals("Mismatched new password", newPassword, op.get("newPassword", String.class)); assertObscuredString("newPassword", newPassword); } protected Operation assertExtractedUsername(String actionName, String username) { return assertExtractedUsername(assertOperationAction(actionName), username); } protected Operation assertExtractedUsername(Operation op, String username) { assertNotNull("No operation extracted", op); assertEquals("Mismatched operation type", SpringSecurityDefinitions.USER_OP, op.getType()); assertEquals("Mismatched username value", username, op.get("username", String.class)); assertObscuredString("username", username); return op; } protected void assertObscuredString(String type, String value) { assertTrue("Not obscured - " + type, marker.contains(value)); } protected Operation assertOperationResult(String actionName, UserDetails details, String mapName) { Operation op = assertOperationAction(actionName); assertUserDetails(op.get(mapName, OperationMap.class), details); assertObscuredDetails(details, marker); return op; } protected void assertObscuredDetails(UserDetails details, Collection<?> obscuredValues) { assertTrue("Username not obscured", obscuredValues.contains(details.getUsername())); assertTrue("Password not obscured", obscuredValues.contains(details.getPassword())); } protected Operation assertOperationAction(String actionName) { Operation op = getLastEntered(); assertNotNull("No operation extracted", op); assertEquals("Mismatched operation type", SpringSecurityDefinitions.USER_OP, op.getType()); assertEquals("Mismatched action name", actionName, op.get("action", String.class)); return op; } protected OperationMap assertUserDetails(OperationMap mapValue, UserDetails details) { if (mapValue == null) { // OK if null - just means no extra information collected return null; } assertEquals("Mismatched username", details.getUsername(), mapValue.get("username", String.class)); assertEquals("Mismatched password", details.getPassword(), mapValue.get("password", String.class)); assertEquals("Mismatched accountNonExpired", Boolean.valueOf(details.isAccountNonExpired()), mapValue.get("accountNonExpired", Boolean.class)); assertEquals("Mismatched accountNonLocked", Boolean.valueOf(details.isAccountNonLocked()), mapValue.get("accountNonLocked", Boolean.class)); assertEquals("Mismatched credentialsNonExpired", Boolean.valueOf(details.isCredentialsNonExpired()), mapValue.get("credentialsNonExpired", Boolean.class)); assertEquals("Mismatched enabled", Boolean.valueOf(details.isEnabled()), mapValue.get("enabled", Boolean.class)); assertGrantedAuthoritiesInstances(mapValue.get(ObscuringOperationCollector.GRANTED_AUTHS_LIST_NAME, OperationList.class), details.getAuthorities()); return mapValue; } protected Operation assertScoreValue(Operation op, int expected) { assertNotNull("No operation extracted", op); Number actual = op.get(EndPointAnalysis.SCORE_FIELD, Number.class); assertNotNull("No score value set", actual); assertEquals("Mismatched score value", expected, actual.intValue()); return op; } @Override public UserDetailsManagerCollectionAspect getAspect() { return UserDetailsManagerCollectionAspect.aspectOf(); } private User createUser(String username) { return new User(username, UUID.randomUUID().toString(), true, true, true, true, AuthorityUtils.createAuthorityList(String.valueOf(System.nanoTime()))); } }