diff --git a/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/config/MethodSecurityConfig.java b/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/config/MethodSecurityConfig.java new file mode 100644 index 0000000000..1b2227f9be --- /dev/null +++ b/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/config/MethodSecurityConfig.java @@ -0,0 +1,11 @@ +package org.baeldung.testmethodsecurity.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) +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/testmethodsecurity/entity/CustomUser.java new file mode 100644 index 0000000000..b145a82c80 --- /dev/null +++ b/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/entity/CustomUser.java @@ -0,0 +1,30 @@ +package org.baeldung.testmethodsecurity.entity; + +import java.util.Collection; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.User; + +@SuppressWarnings("serial") +public class CustomUser extends User{ + + private String nickName; + + public CustomUser(String username, String password, Collection authorities) { + super(username, password, authorities); + } + + public CustomUser(String username, String password, Collection authorities,String nickName) { + super(username, password, authorities); + this.nickName = nickName; + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + +} diff --git a/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/repository/UserRoleRepository.java b/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/repository/UserRoleRepository.java new file mode 100644 index 0000000000..565b46262d --- /dev/null +++ b/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/repository/UserRoleRepository.java @@ -0,0 +1,41 @@ +package org.baeldung.testmethodsecurity.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.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +@Service +public class UserRoleRepository { + + static Map DB_BASED_USER_MAPPING; + + static{ + DB_BASED_USER_MAPPING = new LinkedHashMap<>(); + DB_BASED_USER_MAPPING.put("jane", new CustomUser("jane","1234", getGrantedAuthorities("ROLE_USER","ROLE_VIEWER"),"jane")); + DB_BASED_USER_MAPPING.put("john", new CustomUser("john","1234", getGrantedAuthorities("ROLE_EDITOR","ROLE_ADMIN"),"jane")); + DB_BASED_USER_MAPPING.put("jack", new CustomUser("jack","1234", getGrantedAuthorities("ROLE_USER","ROLE_REVIEWER"),"jane")); + } + + private static List getGrantedAuthorities(String...roles){ + ArrayList authorities = new ArrayList<>(); + for (String role : roles){ + authorities.add(new SimpleGrantedAuthority(role)); + } + return authorities; + } + + public CustomUser loadUserByUserName(String username){ + if (DB_BASED_USER_MAPPING.containsKey(username)){ + return DB_BASED_USER_MAPPING.get(username); + } + throw new UsernameNotFoundException("User "+username+" cannot be found"); + } + +} diff --git a/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/service/CustomUserDetailsService.java b/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/service/CustomUserDetailsService.java new file mode 100644 index 0000000000..a5adcd3408 --- /dev/null +++ b/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/service/CustomUserDetailsService.java @@ -0,0 +1,19 @@ +package org.baeldung.testmethodsecurity.service; + +import org.baeldung.testmethodsecurity.repository.UserRoleRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.stereotype.Service; + +@Service("userDetailService") +public class CustomUserDetailsService implements UserDetailsService { + + @Autowired + UserRoleRepository userRoleRepo; + + @Override + public UserDetails loadUserByUsername(String username) { + return userRoleRepo.loadUserByUserName(username); + } +} \ No newline at end of file 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 new file mode 100644 index 0000000000..f4dc6cf335 --- /dev/null +++ b/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/service/UserRoleService.java @@ -0,0 +1,29 @@ +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/testmethodsecurity/TestMethodSecurity.java b/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/TestMethodSecurity.java new file mode 100644 index 0000000000..671229c726 --- /dev/null +++ b/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/TestMethodSecurity.java @@ -0,0 +1,57 @@ +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 diff --git a/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/TestWithMockUserAtClassLevel.java b/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/TestWithMockUserAtClassLevel.java new file mode 100644 index 0000000000..a348a7799d --- /dev/null +++ b/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/TestWithMockUserAtClassLevel.java @@ -0,0 +1,34 @@ +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.test.context.support.WithMockUser; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@ContextConfiguration +@WithMockUser(username="john",roles={"VIEWER"}) +public class TestWithMockUserAtClassLevel { + + @Test + public void givenRoleViewer_whenCallGetUsername_thenReturnUsername(){ + String currentUserName = userService.getUsername(); + assertEquals("john",currentUserName); + } + + @Autowired + UserRoleService userService; + + @Configuration + @ComponentScan("org.baeldung.testmethodsecurity.*") + 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/testmethodsecurity/TestWithUserDetails.java new file mode 100644 index 0000000000..ed8ed8cc85 --- /dev/null +++ b/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/TestWithUserDetails.java @@ -0,0 +1,35 @@ +package org.baeldung.testmethodsecurity; + +import static org.junit.Assert.assertEquals; + +import org.baeldung.testmethodsecurity.entity.CustomUser; +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.test.context.support.WithUserDetails; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@ContextConfiguration +public class TestWithUserDetails { + + @Autowired + UserRoleService userService; + + @Configuration + @ComponentScan("org.baeldung.testmethodsecurity.*") + public static class SpringConfig { + + } + + @Test + @WithUserDetails(value="john",userDetailsServiceBeanName="userDetailService") + public void whenJohn_callLoadUserDetail_thenOK(){ + CustomUser user = userService.loadUserDetail("jane"); + 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/testmethodsecurity/WithMockJohnViewer.java new file mode 100644 index 0000000000..994fe2e69b --- /dev/null +++ b/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/WithMockJohnViewer.java @@ -0,0 +1,10 @@ +package org.baeldung.testmethodsecurity; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import org.springframework.security.test.context.support.WithMockUser; + +@Retention(RetentionPolicy.RUNTIME) +@WithMockUser(value="john",roles="VIEWER") +public @interface WithMockJohnViewer { } \ No newline at end of file