/*
* Copyright 2008-2009 MOPAS(Ministry of Public Administration and Security).
*
* 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 egovframework.rte.fdl.security.userdetails.jdbc;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import egovframework.rte.fdl.security.userdetails.EgovUserDetails;
import egovframework.rte.fdl.string.EgovObjectUtil;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContextException;
import org.springframework.dao.DataAccessException;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
/**
* 사용자계정 정보를 DB에서 관리할수 있도록 구현한 클래스
*
* <p><b>NOTE:</b> org.springframework.security.userdetails.jdbc.JdbcUserDetailsManager 를 확장하여 사용자 계정 정보를 DB에서 관리할 수 있도록 구현한 클래스이다.</p>
*
* @author 실행환경 개발팀 윤성종
* @since 2009.06.01
* @version 1.0
* @see <pre>
* == 개정이력(Modification Information) ==
*
* 수정일 수정자 수정내용
* ------- -------- ---------------------------
* 2009.06.01 윤성종 최초 생성
* 2014.01.22 한성곤 Spring Security 3.2.X 업그레이드 적용
*
* </pre>
*/
public class EgovJdbcUserDetailsManager extends JdbcUserDetailsManager {
private static final Logger LOGGER = LoggerFactory.getLogger(EgovJdbcUserDetailsManager.class);
private EgovUserDetails userDetails = null;
private EgovUsersByUsernameMapping usersByUsernameMapping;
private String mapClass;
private RoleHierarchy roleHierarchy = null;
/**
* 사용자 테이블의 쿼리 조회 컬럼과 세션에서 사용할 사용자 VO와 메핑 할 클래스를 지정한다.
*
* @param mapClass
*/
public void setMapClass(String mapClass) {
this.mapClass = mapClass;
}
/**
* Role Hierarchy를 지원한다.
*
* @param roleHierarchy
*/
public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
this.roleHierarchy = roleHierarchy;
}
/**
* JdbcUserDetailsManager 클래스 재정의
*/
@Override
protected void initDao() throws ApplicationContextException {
super.initDao();
try {
initMappingSqlQueries();
} catch (Exception e) {
LOGGER.error("EgovJdbcUserDetailsManager.initDao.Exception : {}", e.toString(), e);
}
}
/**
* jdbc-user-service의 usersByUsernameQuery 사용자조회 쿼리와
* authoritiesByUsernameQuery 권한조회 쿼리를 이용하여 정보를 저장한다.
*
* @throws Exception
* @throws ClassNotFoundException
*/
private void initMappingSqlQueries() throws Exception {
LOGGER.debug("## EgovJdbcUserDetailsManager query : {}", getUsersByUsernameQuery());
LOGGER.debug("Mapping Class : {}", this.mapClass);
Class<?> clazz = EgovObjectUtil.loadClass(this.mapClass);
Constructor<?> constructor = clazz.getConstructor(new Class[] {DataSource.class, String.class });
Object[] params = new Object[] { getDataSource(), getUsersByUsernameQuery() };
this.usersByUsernameMapping = (EgovUsersByUsernameMapping) constructor.newInstance(params);
}
/**
* JdbcDaoImpl 클래스의 loadUsersByUsername 메소드 재정의.
* 사용자명(또는 ID)로 UserDetails 정보를 조회하여 리스트 형식으로 저장한다.
*/
@Override
protected List<UserDetails> loadUsersByUsername(String username) {
List<EgovUserDetails> list = usersByUsernameMapping.execute(username);
ArrayList<UserDetails> newList = new ArrayList<UserDetails>();
for (EgovUserDetails user : list) {
newList.add(user);
}
return newList;
}
/**
* JdbcDaoImpl 클래스의 loadUsersByUsername 메소드 재정의.
* 사용자명(또는 ID)로 EgovUserDetails의 정보를 조회한다.
*
* @param username
* @return
* @throws UsernameNotFoundException
* @throws DataAccessException
*/
@Override
public EgovUserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
List<UserDetails> users = loadUsersByUsername(username);
if (users.size() == 0) {
LOGGER.debug("Query returned no results for user '{}'", username);
throw new UsernameNotFoundException(messages.getMessage("EgovJdbcUserDetailsManager.notFound", new Object[] { username }, "Username {0} not found"));
}
UserDetails obj = users.get(0);
this.userDetails = (EgovUserDetails) obj;
Set<GrantedAuthority> dbAuthsSet = new HashSet<GrantedAuthority>();
dbAuthsSet.addAll(loadUserAuthorities(this.userDetails.getUsername()));
List<GrantedAuthority> dbAuths = new ArrayList<GrantedAuthority>(dbAuthsSet);
addCustomAuthorities(this.userDetails.getUsername(), dbAuths);
if (dbAuths.size() == 0) {
throw new UsernameNotFoundException(messages.getMessage("EgovJdbcUserDetailsManager.noAuthority", new Object[] { username }, "User {0} has no GrantedAuthority"));
}
// RoleHierarchyImpl 에서 저장한 Role Hierarchy 정보가 저장된다.
Collection<? extends GrantedAuthority> authorities = roleHierarchy.getReachableGrantedAuthorities(dbAuths);
// JdbcDaoImpl 클래스의 createUserDetails 메소드 재정의
return new EgovUserDetails(this.userDetails.getUsername(),
this.userDetails.getPassword(), this.userDetails.isEnabled(), true,
true, true, authorities, this.userDetails.getEgovUserVO());
}
/**
* 인증된 사용자 이름으로 사용자정보(EgovUserDetails)를 가져온다.
*
* @return
* @throws UsernameNotFoundException
* @throws DataAccessException
*/
public EgovUserDetails getAuthenticatedUser() throws UsernameNotFoundException, DataAccessException {
return loadUserByUsername(SecurityContextHolder.getContext().getAuthentication().getName());
}
}