package egovframework.rte.fdl.security;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.AuthenticationManager;
import org.springframework.security.BadCredentialsException;
import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.security.SecurityConfig;
import org.springframework.security.config.BeanIds;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.intercept.method.DelegatingMethodDefinitionSource;
import org.springframework.security.intercept.web.FilterInvocation;
import org.springframework.security.intercept.web.FilterInvocationDefinitionSource;
import org.springframework.security.intercept.web.FilterSecurityInterceptor;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.util.FilterChainProxy;
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
import org.springframework.test.annotation.ExpectedException;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.jdbc.SimpleJdbcTestUtils;
import egovframework.rte.fdl.security.userdetails.EgovUserDetailsVO;
import egovframework.rte.fdl.security.userdetails.util.EgovUserDetailsHelper;
import egovframework.rte.fdl.security.web.CategoryController;
/**
* @author sjyoon
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath*:META-INF/spring/context-common.xml",
"classpath*:META-INF/spring/context-datasource-jdbc.xml"
})
public class EgovSecurityServiceTest extends
AbstractDependencyInjectionSpringContextTests {
private Log log = LogFactory.getLog(getClass());
@Autowired
private ApplicationContext context;
@Resource(name = "dataSource")
private DataSource dataSource;
private boolean isHsql = true;
@Resource(name = "jdbcProperties")
private Properties jdbcProperties;
/* (non-Javadoc)
* @see org.springframework.test.AbstractSingleSpringContextTests#onSetUp()
*/
@Before
public void onSetUp() throws Exception {
log.debug("###### EgovSecurityServiceTest.onSetUp START ######");
isHsql = "hsql".equals(jdbcProperties.getProperty("usingDBMS"));
if (isHsql) {
SimpleJdbcTestUtils.executeSqlScript(new SimpleJdbcTemplate(
dataSource), new ClassPathResource(
"META-INF/testdata/sample_schema_hsql.sql"), true);
}
context =
new ClassPathXmlApplicationContext("classpath*:META-INF/spring/context-*.xml");
log.debug("###### EgovSecurityServiceTest.onSetUp END ######");
}
@After
public void onTearDown() throws Exception {
log.debug("###### EgovSecurityServiceTest.onTearDown START ######");
isHsql = "hsql".equals(jdbcProperties.getProperty("usingDBMS"));
if (isHsql) {
SimpleJdbcTestUtils.executeSqlScript(new SimpleJdbcTemplate(
dataSource), new ClassPathResource(
"META-INF/testdata/sample_schema_hsql_drop.sql"), true);
}
log.debug("###### EgovSecurityServiceTest.onTearDown END ######");
SecurityContextHolder.clearContext();
}
/**
* DB에 사용자 정보(id/password)를 유지하여 인증처리 함
* DB에 등록된 사용자의 인증 확인 테스트
* @throws Exception
*/
@Test
public void testAllowAccessForAuthorizedUser() throws Exception {
UsernamePasswordAuthenticationToken login = new UsernamePasswordAuthenticationToken("jimi", "jimi");
AuthenticationManager authManager =
(AuthenticationManager) context.getBean(BeanIds.AUTHENTICATION_MANAGER);
SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(login));
log.debug("### jimi's password is right!!");
///////////
login = new UsernamePasswordAuthenticationToken("test", "test");
authManager =
(AuthenticationManager) context.getBean(BeanIds.AUTHENTICATION_MANAGER);
SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(login));
log.debug("### test's password is right!!");
///////////
login = new UsernamePasswordAuthenticationToken("user", "user");
authManager =
(AuthenticationManager) context.getBean(BeanIds.AUTHENTICATION_MANAGER);
SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(login));
log.debug("### user's password is right!!");
///////////
login = new UsernamePasswordAuthenticationToken("buyer", "buyer");
authManager =
(AuthenticationManager) context.getBean(BeanIds.AUTHENTICATION_MANAGER);
SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(login));
log.debug("### buyer's password is right!!");
}
/**
* DB에 등록된 사용자의 인증 실패 테스트
* @throws Exception
*/
@Test
@ExpectedException(BadCredentialsException.class)
public void testRejectAccessForUnauthorizedUser() throws Exception {
UsernamePasswordAuthenticationToken login = new UsernamePasswordAuthenticationToken("jimi", "wrongpw");
AuthenticationManager authManager =
(AuthenticationManager) context.getBean(BeanIds.AUTHENTICATION_MANAGER);
log.debug("### jimi's password is wrong!!");
SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(login));
}
/**
* 메소드 접근 제어 권한에 따른 Role 맵핑을 처리함
* 메소드 수행이 허용된 메소드 실행 시 성공 테스트
* @throws Exception
*/
@Test
public void testMethodAndRoleMapping() throws Exception {
DelegatingMethodDefinitionSource definitionsource = (DelegatingMethodDefinitionSource) context.getBean(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE);
Method method = null;
ConfigAttributeDefinition role = null;
// test1 : matched role
try {
method = CategoryController.class.getMethod("selectCategoryList", null);
} catch (NoSuchMethodException nsme) {
log.error("## testMethodAndRoleMapping : ", nsme);
}
role = definitionsource.getAttributes(method, CategoryController.class);
assertEquals("ROLE_USER", role.getConfigAttributes().toArray()[0].toString());
log.debug("## testMethodAndRoleMapping : " + method.getName() + " is " + role.getConfigAttributes().toArray()[0].toString());
}
/**
* 메소드 수행이 허용되지 않은 메소드 실행 시 실패 테스트
* @throws Exception
*/
@Test
public void testFailedMethodAndRoleMapping() throws Exception {
DelegatingMethodDefinitionSource definitionsource = (DelegatingMethodDefinitionSource) context.getBean(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE);
Method method = null;
ConfigAttributeDefinition role = null;
// test1 : no matched role
try {
method = CategoryController.class.getMethod("addCategoryView", null);
} catch (NoSuchMethodException nsme) {
log.error("## testMethodAndRoleMapping : ", nsme);
}
role = definitionsource.getAttributes(method, CategoryController.class);
assertEquals(null, role);
log.debug("## testMethodAndRoleMapping : " + method.getName() + " is no roles");
}
/**
* 웹 URL 접근 제어 권한에 따른 Role 맵핑을 처리함
* 웹 접근이 허용된 URL로 접근 시 성공 테스트
* @throws Exception
*/
@Test
public void testURLAndRoleMapping() throws Exception {
FilterSecurityInterceptor interceptor = (FilterSecurityInterceptor) context.getBean("filterSecurityInterceptor");
FilterInvocationDefinitionSource definitionsource = interceptor.getObjectDefinitionSource();
// "/test.do" ROLE_USER
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setRequestURI(null);
request.setServletPath("/test.do");
FilterInvocation filterInvocation =
new FilterInvocation(request, new MockHttpServletResponse(), new MockFilterChain());
ConfigAttributeDefinition attrs = definitionsource.getAttributes(filterInvocation);
log.debug("### Pattern Matched url size is " + attrs.getConfigAttributes().size() + " and Roles are " + attrs);
assertTrue(attrs.contains(new SecurityConfig("ROLE_USER")));
// "/sale/index.do" ROLE_RESTRICTED
request = new MockHttpServletRequest();
request.setMethod("POST");
request.setRequestURI(null);
request.setServletPath("/sale/index.do");
filterInvocation =
new FilterInvocation(request, new MockHttpServletResponse(), new MockFilterChain());
attrs = definitionsource.getAttributes(filterInvocation);
log.debug("### Pattern Matched url size is " + attrs.getConfigAttributes().size() + " and Roles are " + attrs);
assertTrue(attrs.contains(new SecurityConfig("ROLE_RESTRICTED")));
}
/**
* 웹 접근이 허용되지 않은 URL로 접근 시 실패 테스트
* @throws Exception
*/
@Test
public void testFailedURLAndRoleMapping() throws Exception {
FilterSecurityInterceptor interceptor = (FilterSecurityInterceptor) context.getBean("filterSecurityInterceptor");
FilterInvocationDefinitionSource definitionsource = interceptor.getObjectDefinitionSource();
// "/test.do" ROLE_USER
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
request.setRequestURI(null);
request.setServletPath("/index.do");
FilterInvocation filterInvocation =
new FilterInvocation(request, new MockHttpServletResponse(), new MockFilterChain());
ConfigAttributeDefinition attrs = definitionsource.getAttributes(filterInvocation);
log.debug("### Pattern Matched url is none");
assertNull(attrs);
}
/**
* 웹 접근이 허용된 URL로 접근 시 Context 에서 지정한 로그인 화면으로 이동됨 검사
* @throws Exception
*/
@Test
public void testSuccessfulUrlInvocation() throws Exception {
final String loginPage = "/cvpl/EgovCvplLogin.do";
FilterChainProxy filterChainProxy = (FilterChainProxy) context.getBean(BeanIds.FILTER_CHAIN_PROXY);
////////////////
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET");
request.setServletPath("/test.do");
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
filterChainProxy.doFilter(request, response, chain);
assertTrue(response.getRedirectedUrl().indexOf(loginPage) >= 0);
log.debug("### getRedirectedUrl " + response.getRedirectedUrl());
log.debug("### getForwardedUrl " + response.getForwardedUrl());
log.debug("### getIncludedUrl " + response.getIncludedUrl());
log.debug("### getErrorMessage " + response.getErrorMessage());
log.debug("### getContentAsString " + response.getContentAsString());
/////////////
request = new MockHttpServletRequest();
request.setMethod("GET");
request.setServletPath("/sale/index.do");
response = new MockHttpServletResponse();
filterChainProxy.doFilter(request, response, chain);
assertTrue(response.getRedirectedUrl().indexOf(loginPage) >= 0);
log.debug("### getRedirectedUrl " + response.getRedirectedUrl());
log.debug("### getForwardedUrl " + response.getForwardedUrl());
log.debug("### getIncludedUrl " + response.getIncludedUrl());
log.debug("### getErrorMessage " + response.getErrorMessage());
log.debug("### getContentAsString " + response.getContentAsString());
}
/**
* 웹 접근이 허용되지 않은 URL로 접근 시 Context 에서 지정한 로그인 화면으로 이동되지 않음 검사
* @throws Exception
*/
@Test
public void testFailureUrlInvocation() throws Exception {
final String loginPage = "/cvpl/EgovCvplLogin.do";
FilterChainProxy filterChainProxy = (FilterChainProxy) context.getBean(BeanIds.FILTER_CHAIN_PROXY);
////////////////
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET");
request.setServletPath("/index.do");
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
filterChainProxy.doFilter(request, response, chain);
assertNull(response.getRedirectedUrl());
log.debug("### getRedirectedUrl is null");
////////////////
request = new MockHttpServletRequest();
request.setMethod("GET");
request.setServletPath("/sale/index.doit");
response = new MockHttpServletResponse();
chain = new MockFilterChain();
filterChainProxy.doFilter(request, response, chain);
assertNull(response.getRedirectedUrl());
log.debug("### getRedirectedUrl is null");
}
/**
* 세션처리를 위한 UserDetails 확장 테스트
* @throws Exception
*/
@Test
public void testUserDetailsExt() throws Exception {
// 인증되지 않은 사용자 체크
Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
assertFalse(isAuthenticated.booleanValue());
log.debug("### testUserDetailsExt 인증 : " + isAuthenticated.booleanValue());
EgovUserDetailsVO user = (EgovUserDetailsVO)EgovUserDetailsHelper.getAuthenticatedUser();
assertNull(user);
log.debug("### testUserDetailsExt 사용자정보 : " + user);
// 로그인 jimi
UsernamePasswordAuthenticationToken login = new UsernamePasswordAuthenticationToken("jimi", "jimi");
AuthenticationManager authManager =
(AuthenticationManager) context.getBean(BeanIds.AUTHENTICATION_MANAGER);
SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(login));
// 인증된 사용자 검증
isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
assertTrue(isAuthenticated.booleanValue());
log.debug("### testUserDetailsExt 인증 : " + isAuthenticated.booleanValue());
// 검증
// ID : jimi
user = (EgovUserDetailsVO)EgovUserDetailsHelper.getAuthenticatedUser();
assertNotNull(user);
assertEquals("jimi", user.getUserId());
assertEquals("jimi test", user.getUserName());
assertEquals("19800604", user.getBirthDay());
assertEquals("1234567890123", user.getSsn());
log.debug("### testUserDetailsExt 사용자 : " + user.getUserId());
// 로그인
login = new UsernamePasswordAuthenticationToken("test", "test");
authManager =
(AuthenticationManager) context.getBean(BeanIds.AUTHENTICATION_MANAGER);
SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(login));
// 인증된 사용자 검증
isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
assertTrue(isAuthenticated.booleanValue());
// ID : test
user = (EgovUserDetailsVO)EgovUserDetailsHelper.getAuthenticatedUser();
assertNotNull(user);
assertEquals("test", user.getUserId());
assertEquals("Kim, Young-Su", user.getUserName());
assertEquals("19800604", user.getBirthDay());
assertEquals("1234567890123", user.getSsn());
log.debug("### testUserDetailsExt 사용자 : " + user.getUserId());
// 로그인
login = new UsernamePasswordAuthenticationToken("user", "user");
authManager =
(AuthenticationManager) context.getBean(BeanIds.AUTHENTICATION_MANAGER);
SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(login));
// 인증된 사용자 검증
isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
assertTrue(isAuthenticated.booleanValue());
// ID : test
user = (EgovUserDetailsVO)EgovUserDetailsHelper.getAuthenticatedUser();
assertNotNull(user);
assertEquals("user", user.getUserId());
assertEquals("Hong Gil-dong", user.getUserName());
assertEquals("19800603", user.getBirthDay());
assertEquals("8006041227717", user.getSsn());
log.debug("### testUserDetailsExt 사용자 : " + user.getUserId());
// 로그인
login = new UsernamePasswordAuthenticationToken("buyer", "buyer");
authManager =
(AuthenticationManager) context.getBean(BeanIds.AUTHENTICATION_MANAGER);
SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(login));
// 인증된 사용자 검증
isAuthenticated = EgovUserDetailsHelper.isAuthenticated();
assertTrue(isAuthenticated.booleanValue());
// ID : buyer
user = (EgovUserDetailsVO)EgovUserDetailsHelper.getAuthenticatedUser();
assertEquals("buyer", user.getUserId());
assertEquals("Lee, Man-hong", user.getUserName());
assertEquals("19701231", user.getBirthDay());
assertEquals("1234567890123", user.getSsn());
log.debug("### testUserDetailsExt 사용자 : " + user.getUserId());
}
/**
* 지정된 Role 조회 테스트
* @throws Exception
*/
@Test
public void testAuthoritiesAndRoleHierarchy() throws Exception {
// user User : ROLE_USER
UsernamePasswordAuthenticationToken login = new UsernamePasswordAuthenticationToken("user", "user");
AuthenticationManager authManager =
(AuthenticationManager) context.getBean(BeanIds.AUTHENTICATION_MANAGER);
SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(login));
log.debug(EgovUserDetailsHelper.getAuthorities());
List<String> authorities = EgovUserDetailsHelper.getAuthorities();
// 1. authorites 에 ROLE_USER 권한이 있는지 체크 TRUE/FALSE
log.debug("########### user ROLES are " + authorities);
assertTrue(authorities.contains("ROLE_USER"));
assertTrue(authorities.contains("ROLE_RESTRICTED"));
assertTrue(authorities.contains("IS_AUTHENTICATED_ANONYMOUSLY"));
assertTrue(authorities.contains("IS_AUTHENTICATED_FULLY"));
assertTrue(authorities.contains("IS_AUTHENTICATED_REMEMBERED"));
// 2. authorites 에 ROLE 이 여러개 설정된 경우
for (Iterator<String> it = authorities.iterator(); it.hasNext();) {
String auth = it.next();
log.debug("########### user ROLE is " + auth);
}
// 3. authorites 에 ROLE 이 하나만 설정된 경우
String auth = (String) authorities.toArray()[0];
log.debug("########### user ROLE is " + auth);
// buyer USER : ROLE_RESTRICTED
login = new UsernamePasswordAuthenticationToken("buyer", "buyer");
authManager =
(AuthenticationManager) context.getBean(BeanIds.AUTHENTICATION_MANAGER);
SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(login));
log.debug(EgovUserDetailsHelper.getAuthorities());
authorities = EgovUserDetailsHelper.getAuthorities();
log.debug("########### buyer ROLES are " + authorities);
assertFalse(authorities.contains("ROLE_USER"));
assertFalse(authorities.contains("ROLE_ADMIN"));
assertTrue(authorities.contains("ROLE_RESTRICTED"));
assertTrue(authorities.contains("IS_AUTHENTICATED_ANONYMOUSLY"));
assertTrue(authorities.contains("IS_AUTHENTICATED_FULLY"));
assertTrue(authorities.contains("IS_AUTHENTICATED_REMEMBERED"));
// test USER : ROLE_ADMIN
login = new UsernamePasswordAuthenticationToken("test", "test");
authManager =
(AuthenticationManager) context.getBean(BeanIds.AUTHENTICATION_MANAGER);
SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(login));
log.debug(EgovUserDetailsHelper.getAuthorities());
authorities = EgovUserDetailsHelper.getAuthorities();
log.debug("########### test ROLES are " + authorities);
assertTrue(authorities.contains("ROLE_USER"));
assertTrue(authorities.contains("ROLE_ADMIN"));
assertTrue(authorities.contains("ROLE_RESTRICTED"));
assertTrue(authorities.contains("IS_AUTHENTICATED_ANONYMOUSLY"));
assertTrue(authorities.contains("IS_AUTHENTICATED_FULLY"));
assertTrue(authorities.contains("IS_AUTHENTICATED_REMEMBERED"));
}
}