diff --git a/spring-security-core/src/main/java/org/baeldung/methodsecurity/annotation/IsViewer.java b/spring-security-core/src/main/java/org/baeldung/methodsecurity/annotation/IsViewer.java new file mode 100644 index 0000000000..da933fb19f --- /dev/null +++ b/spring-security-core/src/main/java/org/baeldung/methodsecurity/annotation/IsViewer.java @@ -0,0 +1,15 @@ +package org.baeldung.methodsecurity.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.security.access.prepost.PreAuthorize; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@PreAuthorize("hasRole('VIEWER')") +public @interface IsViewer +{ +} \ No newline at end of file diff --git a/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/config/MethodSecurityConfig.java b/spring-security-core/src/main/java/org/baeldung/methodsecurity/config/MethodSecurityConfig.java similarity index 85% rename from spring-security-core/src/main/java/org/baeldung/testmethodsecurity/config/MethodSecurityConfig.java rename to spring-security-core/src/main/java/org/baeldung/methodsecurity/config/MethodSecurityConfig.java index 1b2227f9be..4749c730dc 100644 --- a/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/config/MethodSecurityConfig.java +++ b/spring-security-core/src/main/java/org/baeldung/methodsecurity/config/MethodSecurityConfig.java @@ -1,11 +1,11 @@ -package org.baeldung.testmethodsecurity.config; +package org.baeldung.methodsecurity.config; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration; @Configuration -@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) +@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true) public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration { } diff --git a/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/entity/CustomUser.java b/spring-security-core/src/main/java/org/baeldung/methodsecurity/entity/CustomUser.java similarity index 91% rename from spring-security-core/src/main/java/org/baeldung/testmethodsecurity/entity/CustomUser.java rename to spring-security-core/src/main/java/org/baeldung/methodsecurity/entity/CustomUser.java index b145a82c80..19a7719373 100644 --- a/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/entity/CustomUser.java +++ b/spring-security-core/src/main/java/org/baeldung/methodsecurity/entity/CustomUser.java @@ -1,4 +1,4 @@ -package org.baeldung.testmethodsecurity.entity; +package org.baeldung.methodsecurity.entity; import java.util.Collection; diff --git a/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/repository/UserRoleRepository.java b/spring-security-core/src/main/java/org/baeldung/methodsecurity/repository/UserRoleRepository.java similarity index 71% rename from spring-security-core/src/main/java/org/baeldung/testmethodsecurity/repository/UserRoleRepository.java rename to spring-security-core/src/main/java/org/baeldung/methodsecurity/repository/UserRoleRepository.java index 565b46262d..82e74f0cd0 100644 --- a/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/repository/UserRoleRepository.java +++ b/spring-security-core/src/main/java/org/baeldung/methodsecurity/repository/UserRoleRepository.java @@ -1,11 +1,11 @@ -package org.baeldung.testmethodsecurity.repository; +package org.baeldung.methodsecurity.repository; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import org.baeldung.testmethodsecurity.entity.CustomUser; +import org.baeldung.methodsecurity.entity.CustomUser; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UsernameNotFoundException; @@ -38,4 +38,20 @@ public class UserRoleRepository { throw new UsernameNotFoundException("User "+username+" cannot be found"); } + public boolean isValidUsername(String username){ + return DB_BASED_USER_MAPPING.containsKey(username); + } + + public boolean isValidRole(String roleName){ + return roleName.startsWith("ROLE_"); + } + + public List getAllUsernames(){ + List usernames = new ArrayList<>(); + usernames.add("jane"); + usernames.add("john"); + usernames.add("jack"); + return usernames; + } + } diff --git a/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/service/CustomUserDetailsService.java b/spring-security-core/src/main/java/org/baeldung/methodsecurity/service/CustomUserDetailsService.java similarity index 79% rename from spring-security-core/src/main/java/org/baeldung/testmethodsecurity/service/CustomUserDetailsService.java rename to spring-security-core/src/main/java/org/baeldung/methodsecurity/service/CustomUserDetailsService.java index a5adcd3408..91171468bb 100644 --- a/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/service/CustomUserDetailsService.java +++ b/spring-security-core/src/main/java/org/baeldung/methodsecurity/service/CustomUserDetailsService.java @@ -1,6 +1,6 @@ -package org.baeldung.testmethodsecurity.service; +package org.baeldung.methodsecurity.service; -import org.baeldung.testmethodsecurity.repository.UserRoleRepository; +import org.baeldung.methodsecurity.repository.UserRoleRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; diff --git a/spring-security-core/src/main/java/org/baeldung/methodsecurity/service/UserRoleService.java b/spring-security-core/src/main/java/org/baeldung/methodsecurity/service/UserRoleService.java new file mode 100644 index 0000000000..3afd56110a --- /dev/null +++ b/spring-security-core/src/main/java/org/baeldung/methodsecurity/service/UserRoleService.java @@ -0,0 +1,107 @@ +package org.baeldung.methodsecurity.service; + +import java.util.List; +import java.util.stream.Collectors; + +import javax.annotation.security.RolesAllowed; + +import org.baeldung.methodsecurity.annotation.IsViewer; +import org.baeldung.methodsecurity.entity.CustomUser; +import org.baeldung.methodsecurity.repository.UserRoleRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.annotation.Secured; +import org.springframework.security.access.prepost.PostAuthorize; +import org.springframework.security.access.prepost.PostFilter; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.access.prepost.PreFilter; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; + +@Service +public class UserRoleService { + + @Autowired + UserRoleRepository userRoleRepository; + + @Secured("ROLE_VIEWER") + public String getUsername(){ + SecurityContext securityContext = SecurityContextHolder.getContext(); + return securityContext.getAuthentication().getName(); + } + + @Secured({"ROLE_VIEWER","ROLE_EDITOR"}) + public boolean isValidUsername(String username){ + return userRoleRepository.isValidUsername(username); + } + + @RolesAllowed("ROLE_VIEWER") + public String getUsername2(){ + SecurityContext securityContext = SecurityContextHolder.getContext(); + return securityContext.getAuthentication().getName(); + } + + @RolesAllowed({"ROLE_VIEWER","ROLE_EDITOR"}) + public boolean isValidUsername2(String username){ + return userRoleRepository.isValidUsername(username); + } + + @PreAuthorize("hasRole('ROLE_VIEWER')") + public String getUsernameInUpperCase(){ + return getUsername().toUpperCase(); + } + + @PreAuthorize("hasAuthority('SYS_ADMIN')") + public String getUsernameInLowerCase(){ + return getUsername().toLowerCase(); + } + + @PreAuthorize("hasRole('ROLE_VIEWER') or hasRole('ROLE_EDITOR')") + public boolean isValidUsername3(String username){ + return userRoleRepository.isValidUsername(username); + } + + @PreAuthorize("#username == authentication.principal.username") + public String getMyRoles(String username){ + SecurityContext securityContext = SecurityContextHolder.getContext(); + return securityContext + .getAuthentication() + .getAuthorities() + .stream().map(auth -> auth.getAuthority()) + .collect(Collectors.joining(",")); + } + + @PostAuthorize("returnObject.username == authentication.principal.nickName") + public CustomUser loadUserDetail(String username){ + return userRoleRepository.loadUserByUserName(username); + } + + @PreFilter("filterObject != authentication.principal.username") + public String joinUsernames(List usernames){ + return usernames.stream().collect(Collectors.joining(";")); + } + + @PreFilter(value="filterObject != authentication.principal.username",filterTarget="usernames") + public String joinUsernamesAndRoles(List usernames,List roles){ + return usernames.stream().collect(Collectors.joining(";")) + +":"+roles.stream().collect(Collectors.joining(";")); + } + + @PostFilter("filterObject != authentication.principal.username") + public List getAllUsernamesExceptCurrent(){ + return userRoleRepository.getAllUsernames(); + } + + @IsViewer + public String getUsername4(){ + SecurityContext securityContext = SecurityContextHolder.getContext(); + return securityContext.getAuthentication().getName(); + } + + @PreAuthorize("#username == authentication.principal.username") + @PostAuthorize("returnObject.username == authentication.principal.nickName") + public CustomUser securedLoadUserDetail(String username){ + return userRoleRepository.loadUserByUserName(username); + } + +} diff --git a/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/service/UserRoleService.java b/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/service/UserRoleService.java deleted file mode 100644 index f4dc6cf335..0000000000 --- a/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/service/UserRoleService.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.baeldung.testmethodsecurity.service; - -import org.baeldung.testmethodsecurity.entity.CustomUser; -import org.baeldung.testmethodsecurity.repository.UserRoleRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PostAuthorize; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.stereotype.Service; - -@Service -public class UserRoleService { - - @Autowired - UserRoleRepository userRoleRepository; - - @PreAuthorize("hasRole('ROLE_VIEWER') or hasAuthority('SYS_ADMIN')") - public String getUsername(){ - SecurityContext securityContext = SecurityContextHolder.getContext(); - return securityContext.getAuthentication().getName(); - } - - @PostAuthorize("returnObject.username == authentication.principal.nickName") - public CustomUser loadUserDetail(String username){ - return userRoleRepository.loadUserByUserName(username); - } - -} diff --git a/spring-security-core/src/test/java/org/baeldung/methodsecurity/TestMethodSecurity.java b/spring-security-core/src/test/java/org/baeldung/methodsecurity/TestMethodSecurity.java new file mode 100644 index 0000000000..dcc77fbab5 --- /dev/null +++ b/spring-security-core/src/test/java/org/baeldung/methodsecurity/TestMethodSecurity.java @@ -0,0 +1,163 @@ +package org.baeldung.methodsecurity; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.baeldung.methodsecurity.service.UserRoleService; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; +import org.springframework.security.test.context.support.WithAnonymousUser; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@ContextConfiguration +public class TestMethodSecurity{ + + @Autowired + UserRoleService userRoleService; + + @Configuration + @ComponentScan("org.baeldung.methodsecurity.*") + public static class SpringConfig { + + } + + @Test(expected=AuthenticationCredentialsNotFoundException.class) + public void givenNoSecurity_whenCallGetUsername_thenReturnException(){ + String userName = userRoleService.getUsername(); + assertEquals("john", userName); + } + + @Test + @WithMockUser(username="john",roles={"VIEWER"}) + public void givenRoleViewer_whenCallGetUsername_thenReturnUsername(){ + String userName = userRoleService.getUsername(); + assertEquals("john", userName); + } + + @Test + @WithMockUser(username="john",roles={"EDITOR"}) + public void givenUsernameJohn_whenCallIsValidUsername_thenReturnTrue(){ + boolean isValid = userRoleService.isValidUsername("john"); + assertEquals(true, isValid); + } + + @Test(expected = AccessDeniedException.class) + @WithMockUser(username = "john", roles = { "ADMIN" }) + public void givenRoleAdmin_whenCallGetUsername_thenReturnAccessDenied() { + userRoleService.getUsername(); + } + + @Test(expected = AccessDeniedException.class) + @WithMockUser(username = "john", roles = {"USER"}) + public void givenRoleUser_whenCallGetUsername2_thenReturnAccessDenied() { + userRoleService.getUsername2(); + } + + @Test + @WithMockUser(username="john",roles={"VIEWER","EDITOR"}) + public void givenRoleViewer_whenCallGetUsername2_thenReturnUsername(){ + String userName = userRoleService.getUsername2(); + assertEquals("john", userName); + } + + @Test + @WithMockUser(username="john",roles={"VIEWER"}) + public void givenUsernameJerry_whenCallIsValidUsername2_thenReturnFalse(){ + boolean isValid = userRoleService.isValidUsername2("jerry"); + assertEquals(false, isValid); + } + + @Test + @WithMockUser(username="JOHN",authorities={"SYS_ADMIN"}) + public void givenAuthoritySysAdmin_whenCallGetUsernameInLowerCase_thenReturnUsername(){ + String username = userRoleService.getUsernameInLowerCase(); + assertEquals("john", username); + } + + @Test + @WithMockUser(username="john",roles={"ADMIN","USER","VIEWER"}) + public void givenUserJohn_whenCallGetMyRolesWithJohn_thenReturnRoles(){ + String roles = userRoleService.getMyRoles("john"); + assertEquals("ROLE_ADMIN,ROLE_USER,ROLE_VIEWER", roles); + } + + @Test(expected=AccessDeniedException.class) + @WithMockUser(username="john",roles={"ADMIN","USER","VIEWER"}) + public void givenUserJane_whenCallGetMyRolesWithJane_thenAccessDenied(){ + userRoleService.getMyRoles("jane"); + } + + @Test(expected=AccessDeniedException.class) + @WithAnonymousUser + public void givenAnomynousUser_whenCallGetUsername_thenAccessDenied(){ + userRoleService.getUsername(); + } + + @Test + @WithMockJohnViewer + public void givenMockedJohnViewer_whenCallGetUsername_thenReturnUsername(){ + String userName = userRoleService.getUsername(); + assertEquals("john", userName); + } + + @Test + @WithMockUser(username="jane") + public void givenListContainCurrentUsername_whenJoinUsernames_thenReturnUsernames(){ + List usernames = new ArrayList<>(); + usernames.add("jane"); + usernames.add("john"); + usernames.add("jack"); + String containCurrentUser = userRoleService.joinUsernames(usernames); + assertEquals("john;jack", containCurrentUser); + + } + + @Test + @WithMockUser(username="john") + public void givenListNotContainCurrentUsername_whenCallContainCurrentUser_thenReturnAccessDenied(){ + List usernames = new ArrayList<>(); + usernames.add("jane"); + usernames.add("john"); + usernames.add("jack"); + + List roles = new ArrayList<>(); + roles.add("ROLE_ADMIN"); + roles.add("ROLE_TEST"); + + String containCurrentUser = userRoleService.joinUsernamesAndRoles(usernames,roles); + assertEquals("jane;jack:ROLE_ADMIN;ROLE_TEST", containCurrentUser); + } + + @Test + @WithMockUser(username="john") + public void givenUserJohn_whenCallGetAllUsernamesExceptCurrent_thenReturnOtherusernames(){ + List others = userRoleService.getAllUsernamesExceptCurrent(); + assertEquals(2, others.size()); + assertTrue(others.contains("jane")); + assertTrue(others.contains("jack")); + } + + @Test + @WithMockUser(username="john",roles={"VIEWER"}) + public void givenRoleViewer_whenCallGetUsername4_thenReturnUsername(){ + String userName = userRoleService.getUsername4(); + assertEquals("john", userName); + } + + @Test(expected=AccessDeniedException.class) + @WithMockUser(username="john") + public void givenDefaultRole_whenCallGetUsername4_thenAccessDenied(){ + userRoleService.getUsername4(); + } +} \ No newline at end of file diff --git a/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/TestWithMockUserAtClassLevel.java b/spring-security-core/src/test/java/org/baeldung/methodsecurity/TestWithMockUserAtClassLevel.java similarity index 82% rename from spring-security-core/src/test/java/org/baeldung/testmethodsecurity/TestWithMockUserAtClassLevel.java rename to spring-security-core/src/test/java/org/baeldung/methodsecurity/TestWithMockUserAtClassLevel.java index a348a7799d..319aee63a6 100644 --- a/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/TestWithMockUserAtClassLevel.java +++ b/spring-security-core/src/test/java/org/baeldung/methodsecurity/TestWithMockUserAtClassLevel.java @@ -1,8 +1,8 @@ -package org.baeldung.testmethodsecurity; +package org.baeldung.methodsecurity; import static org.junit.Assert.assertEquals; -import org.baeldung.testmethodsecurity.service.UserRoleService; +import org.baeldung.methodsecurity.service.UserRoleService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -27,7 +27,7 @@ public class TestWithMockUserAtClassLevel { UserRoleService userService; @Configuration - @ComponentScan("org.baeldung.testmethodsecurity.*") + @ComponentScan("org.baeldung.methodsecurity.*") public static class SpringConfig { } diff --git a/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/TestWithUserDetails.java b/spring-security-core/src/test/java/org/baeldung/methodsecurity/TestWithUserDetails.java similarity index 64% rename from spring-security-core/src/test/java/org/baeldung/testmethodsecurity/TestWithUserDetails.java rename to spring-security-core/src/test/java/org/baeldung/methodsecurity/TestWithUserDetails.java index ed8ed8cc85..3f60281380 100644 --- a/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/TestWithUserDetails.java +++ b/spring-security-core/src/test/java/org/baeldung/methodsecurity/TestWithUserDetails.java @@ -1,9 +1,9 @@ -package org.baeldung.testmethodsecurity; +package org.baeldung.methodsecurity; import static org.junit.Assert.assertEquals; -import org.baeldung.testmethodsecurity.entity.CustomUser; -import org.baeldung.testmethodsecurity.service.UserRoleService; +import org.baeldung.methodsecurity.entity.CustomUser; +import org.baeldung.methodsecurity.service.UserRoleService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -21,7 +21,7 @@ public class TestWithUserDetails { UserRoleService userService; @Configuration - @ComponentScan("org.baeldung.testmethodsecurity.*") + @ComponentScan("org.baeldung.methodsecurity.*") public static class SpringConfig { } @@ -32,4 +32,11 @@ public class TestWithUserDetails { CustomUser user = userService.loadUserDetail("jane"); assertEquals("jane",user.getNickName()); } + + @Test + @WithUserDetails(value="jane",userDetailsServiceBeanName="userDetailService") + public void whenJohn_callSecuredLoadUserDetail_thenOK(){ + CustomUser user = userService.securedLoadUserDetail("john"); + assertEquals("jane",user.getNickName()); + } } diff --git a/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/WithMockJohnViewer.java b/spring-security-core/src/test/java/org/baeldung/methodsecurity/WithMockJohnViewer.java similarity index 72% rename from spring-security-core/src/test/java/org/baeldung/testmethodsecurity/WithMockJohnViewer.java rename to spring-security-core/src/test/java/org/baeldung/methodsecurity/WithMockJohnViewer.java index 994fe2e69b..5e1e882f3d 100644 --- a/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/WithMockJohnViewer.java +++ b/spring-security-core/src/test/java/org/baeldung/methodsecurity/WithMockJohnViewer.java @@ -1,4 +1,4 @@ -package org.baeldung.testmethodsecurity; +package org.baeldung.methodsecurity; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/TestMethodSecurity.java b/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/TestMethodSecurity.java deleted file mode 100644 index 671229c726..0000000000 --- a/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/TestMethodSecurity.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.baeldung.testmethodsecurity; - -import static org.junit.Assert.assertEquals; - -import org.baeldung.testmethodsecurity.service.UserRoleService; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.test.context.support.WithAnonymousUser; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@ContextConfiguration -public class TestMethodSecurity{ - - @Autowired - UserRoleService userRoleService; - - @Configuration - @ComponentScan("org.baeldung.testmethodsecurity.*") - public static class SpringConfig { - - } - - @Test - @WithMockUser(username="john",roles={"VIEWER"}) - public void givenRoleViewer_whenCallGetUsername_thenReturnUsername(){ - String userName = userRoleService.getUsername(); - assertEquals("john", userName); - } - - @Test - @WithMockUser(username="john",authorities={"SYS_ADMIN"}) - public void givenAuthoritySysAdmin_whenCallGetUsername_thenReturnUsername(){ - String userName = userRoleService.getUsername(); - assertEquals("john", userName); - } - - @Test(expected=AccessDeniedException.class) - @WithAnonymousUser - public void givenAnomynousUser_whenCallGetUsername_thenAccessDenied(){ - userRoleService.getUsername(); - } - - @Test - @WithMockJohnViewer - public void givenMockedJohnViewer_whenCallGetUsername_thenReturnUsername(){ - String userName = userRoleService.getUsername(); - assertEquals("john", userName); - } - -} \ No newline at end of file