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..8c5a5b2fb2 --- /dev/null +++ b/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/entity/CustomUser.java @@ -0,0 +1,39 @@ +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; + private int age; + + 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; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + +} 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/SystemPropImpl.java b/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/service/SystemPropImpl.java new file mode 100644 index 0000000000..7307fb63fe --- /dev/null +++ b/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/service/SystemPropImpl.java @@ -0,0 +1,26 @@ +package org.baeldung.testmethodsecurity.service; + +import org.springframework.security.access.annotation.Secured; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Service; + +@Service +public class SystemPropImpl implements SystemPropInterface{ + + @PreAuthorize("permitAll") + @Override + public String getSystemName() { + return "Method Security"; + } + + @Override + public String sayHello(){ + return sayHi(); + } + + @Secured("ROLE_USER") + public String sayHi(){ + return "Hi"; + } + +} diff --git a/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/service/SystemPropInterface.java b/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/service/SystemPropInterface.java new file mode 100644 index 0000000000..b61d42083d --- /dev/null +++ b/spring-security-core/src/main/java/org/baeldung/testmethodsecurity/service/SystemPropInterface.java @@ -0,0 +1,11 @@ +package org.baeldung.testmethodsecurity.service; + +public interface SystemPropInterface { + + String getSystemName(); + + String sayHello(); + + String sayHi(); + +} 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..46cab5918a --- /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/TestCustomSecurityContext.java b/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/TestCustomSecurityContext.java new file mode 100644 index 0000000000..f231437e40 --- /dev/null +++ b/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/TestCustomSecurityContext.java @@ -0,0 +1,41 @@ +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.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class TestCustomSecurityContext { + + @Autowired + UserRoleService userRoleService; + + @Configuration + @ComponentScan("org.baeldung.testmethodsecurity.*") + public static class SpringConfig { + + } + + @Test + @WithMockSysUser(systemUserName="jane") + public void whenJane_callGetUserName_thenOK(){ + String userName = userRoleService.getUserName(); + assertEquals("jane",userName); + } + + @Test(expected=AccessDeniedException.class) + @WithMockSysUser(systemUserName="john") + public void whenJohn_callGetUserName_thenFail(){ + userRoleService.getUserName(); + } + +} 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..8b7b095187 --- /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.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.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 whenRoleViewer_callGetUserName_thenOK(){ + String userName = userRoleService.getUserName(); + assertEquals("john", userName); + } + + @Test + @WithMockUser(username="john",authorities={"SYS_ADMIN"}) + public void whenSysAdmin_callGetUserName_thenOK(){ + String userName = userRoleService.getUserName(); + assertEquals("john", userName); + } + + @Test(expected=AccessDeniedException.class) + @WithAnonymousUser + public void whenAnomynous_callGetUserName_thenFail(){ + userRoleService.getUserName(); + } + + @Test + @WithMockJohnViewer + public void whenJohnViewer_callGetUserName_thenOK(){ + 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/TestSystemProp.java b/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/TestSystemProp.java new file mode 100644 index 0000000000..1a36cf7ae1 --- /dev/null +++ b/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/TestSystemProp.java @@ -0,0 +1,54 @@ +package org.baeldung.testmethodsecurity; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.lang.reflect.Proxy; + +import org.baeldung.testmethodsecurity.service.SystemPropImpl; +import org.baeldung.testmethodsecurity.service.SystemPropInterface; +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.authentication.AuthenticationCredentialsNotFoundException; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class TestSystemProp{ + + @Autowired + SystemPropInterface systemProp; + + @Test + @WithMockUser(username="test") + public void checkSystemPropInstance(){ + assertFalse(systemProp instanceof SystemPropImpl); + assertTrue(systemProp instanceof SystemPropInterface); + assertTrue(systemProp instanceof Proxy); + + assertEquals("Method Security", systemProp.getSystemName()); + } + + @Test + public void whenNotAuthentication_callSayHello_thenOK(){ + String hello = systemProp.sayHello(); + assertEquals("Hi", hello); + } + + @Test(expected=AuthenticationCredentialsNotFoundException.class) + public void whenNotAuthentication_callSayHi_thenFailed(){ + systemProp.sayHi(); + } + + @Configuration + @ComponentScan("org.baeldung.testmethodsecurity.*") + public static class SpringConfig { + + } +} 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..aaa1b84294 --- /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.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +@WithMockUser(username="john",roles={"VIEWER"}) +public class TestWithMockUserAtClassLevel { + + @Test + public void whenRoleViewerLogged_callGetUserName_thenOK(){ + 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..751062e223 --- /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.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.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 diff --git a/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/WithMockSysUser.java b/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/WithMockSysUser.java new file mode 100644 index 0000000000..34e6c78a9d --- /dev/null +++ b/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/WithMockSysUser.java @@ -0,0 +1,12 @@ +package org.baeldung.testmethodsecurity; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import org.springframework.security.test.context.support.WithSecurityContext; + +@Retention(RetentionPolicy.RUNTIME) +@WithSecurityContext(factory = WithMockSysUserSecurityContextFactory.class) +public @interface WithMockSysUser { + String systemUserName(); +} \ No newline at end of file diff --git a/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/WithMockSysUserSecurityContextFactory.java b/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/WithMockSysUserSecurityContextFactory.java new file mode 100644 index 0000000000..820f6f2d07 --- /dev/null +++ b/spring-security-core/src/test/java/org/baeldung/testmethodsecurity/WithMockSysUserSecurityContextFactory.java @@ -0,0 +1,28 @@ +package org.baeldung.testmethodsecurity; + +import org.baeldung.testmethodsecurity.entity.CustomUser; +import org.baeldung.testmethodsecurity.repository.UserRoleRepository; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.test.context.support.WithSecurityContextFactory; + +public class WithMockSysUserSecurityContextFactory + implements WithSecurityContextFactory { + + @Override + public SecurityContext createSecurityContext(WithMockSysUser customUser) { + SecurityContext context = SecurityContextHolder.createEmptyContext(); + UserRoleRepository userRoleRepo = new UserRoleRepository(); + + CustomUser user = userRoleRepo.loadUserByUserName(customUser.systemUserName()); + + Authentication auth = + new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities()); + + context.setAuthentication(auth); + return context; + } + +} \ No newline at end of file