/* * 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.securedobject.impl; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.sql.DataSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.security.ConfigAttributeDefinition; import org.springframework.security.SecurityConfig; import org.springframework.security.intercept.web.RequestKey; import egovframework.rte.fdl.security.securedobject.EgovSecuredObjectService; /** * DB기반의 보호된 자원 관리를 구현한 DAO 클래스 * <p> * <b>NOTE:</b> DB 기반의 Secured Object 정보를 제공하기 위한 DAO 로 * default 쿼리를 제공하며 사용자 DB 에 맞는 각 유형의 DB 쿼리는 재설정 가능하다. * namedParameterJdbcTemplate 를 사용하여 DB 조회를 처리한다. * @author ByungHun Woo * @since 2009.06.01 * @version 1.0 * @see <pre> * == 개정이력(Modification Information) == * * 수정일 수정자 수정내용 * ------- -------- --------------------------- * 2009.06.01 윤성종 최초 생성 * * </pre> */ public class SecuredObjectDAO { /** * url 형식인 보호자원 - Role 맵핑정보를 조회하는 default 쿼리이다. */ public static final String DEF_ROLES_AND_URL_QUERY = "SELECT a.resource_pattern url, b.authority authority " + "FROM SECURED_RESOURCES a, SECURED_RESOURCES_ROLE b " + "WHERE a.resource_id = b.resource_id " + "AND a.resource_type = 'url' ORDER BY a.sort_order "; /** * method 형식인 보호자원 - Role 맵핑정보를 조회하는 default 쿼리이다. */ public static final String DEF_ROLES_AND_METHOD_QUERY = "SELECT a.resource_pattern method, b.authority authority " + "FROM SECURED_RESOURCES a, SECURED_RESOURCES_ROLE b " + "WHERE a.resource_id = b.resource_id " + "AND a.resource_type = 'method' ORDER BY a.sort_order "; /** * pointcut 형식인 보호자원 - Role 맵핑정보를 조회하는 default * 쿼리이다. */ public static final String DEF_ROLES_AND_POINTCUT_QUERY = "SELECT a.resource_pattern pointcut, b.authority authority " + "FROM SECURED_RESOURCES a, SECURED_RESOURCES_ROLE b " + "WHERE a.resource_id = b.resource_id " + "AND a.resource_type = 'pointcut' ORDER BY a.sort_order "; /** * 매 request 마다 best matching url 보호자원 - Role 맵핑정보를 * 얻기위한 default 쿼리이다. (Oracle 10g specific) */ public static final String DEF_REGEX_MATCHED_REQUEST_MAPPING_QUERY_ORACLE10G = "SELECT a.resource_pattern uri, b.authority authority " + "FROM secured_resources a, secured_resources_role b " + "WHERE a.resource_id = b.resource_id " + "AND a.resource_id = " + " ( SELECT resource_id FROM " + " ( SELECT resource_id, ROW_NUMBER() OVER (ORDER BY sort_order) resource_order FROM secured_resources c " + " WHERE REGEXP_LIKE ( :url, c.resource_pattern ) " + " AND c.resource_type = 'url' " + " ORDER BY c.sort_order ) " + " WHERE resource_order = 1 ) "; /** * Role 의 계층(Hierarchy) 관계를 조회하는 default 쿼리이다. */ public static final String DEF_HIERARCHICAL_ROLES_QUERY = "SELECT a.child_role child, a.parent_role parent " + "FROM ROLES_HIERARCHY a LEFT JOIN ROLES_HIERARCHY b on (a.child_role = b.parent_role) "; private String sqlRolesAndUrl; private String sqlRolesAndMethod; private String sqlRolesAndPointcut; private String sqlRegexMatchedRequestMapping; private String sqlHierarchicalRoles; public SecuredObjectDAO() { this.sqlRolesAndUrl = DEF_ROLES_AND_URL_QUERY; this.sqlRolesAndMethod = DEF_ROLES_AND_METHOD_QUERY; this.sqlRolesAndPointcut = DEF_ROLES_AND_POINTCUT_QUERY; this.sqlRegexMatchedRequestMapping = DEF_REGEX_MATCHED_REQUEST_MAPPING_QUERY_ORACLE10G; this.sqlHierarchicalRoles = DEF_HIERARCHICAL_ROLES_QUERY; } private NamedParameterJdbcTemplate namedParameterJdbcTemplate; public void setDataSource(DataSource dataSource) { this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); } /** * 롤에 대한 URL 정보를 가져오는 SQL을 얻어온다. * @return */ public String getSqlRolesAndUrl() { return sqlRolesAndUrl; } /** * 롤에대한 URL 정보를 가져오는 SQL을 설정한다. * @param sqlRolesAndUrl */ public void setSqlRolesAndUrl(String sqlRolesAndUrl) { this.sqlRolesAndUrl = sqlRolesAndUrl; } public String getSqlRolesAndMethod() { return sqlRolesAndMethod; } public void setSqlRolesAndMethod(String sqlRolesAndMethod) { this.sqlRolesAndMethod = sqlRolesAndMethod; } public String getSqlRolesAndPointcut() { return sqlRolesAndPointcut; } public void setSqlRolesAndPointcut(String sqlRolesAndPointcut) { this.sqlRolesAndPointcut = sqlRolesAndPointcut; } public String getSqlRegexMatchedRequestMapping() { return sqlRegexMatchedRequestMapping; } public void setSqlRegexMatchedRequestMapping( String sqlRegexMatchedRequestMapping) { this.sqlRegexMatchedRequestMapping = sqlRegexMatchedRequestMapping; } public String getSqlHierarchicalRoles() { return sqlHierarchicalRoles; } public void setSqlHierarchicalRoles(String sqlHierarchicalRoles) { this.sqlHierarchicalRoles = sqlHierarchicalRoles; } public LinkedHashMap getRolesAndResources(String resourceType) throws Exception { LinkedHashMap resourcesMap = new LinkedHashMap(); String sqlRolesAndResources; boolean isResourcesUrl = true; if ("method".equals(resourceType)) { sqlRolesAndResources = getSqlRolesAndMethod(); isResourcesUrl = false; } else if ("pointcut".equals(resourceType)) { sqlRolesAndResources = getSqlRolesAndPointcut(); isResourcesUrl = false; } else { sqlRolesAndResources = getSqlRolesAndUrl(); } List resultList = this.namedParameterJdbcTemplate.queryForList(sqlRolesAndResources, new HashMap()); Iterator itr = resultList.iterator(); Map tempMap; String preResource = null; String presentResourceStr; Object presentResource; while (itr.hasNext()) { tempMap = (Map) itr.next(); presentResourceStr = (String) tempMap.get(resourceType); // url 인 경우 RequestKey 형식의 key를 Map에 담아야 함 presentResource = isResourcesUrl ? new RequestKey(presentResourceStr) : (Object) presentResourceStr; List configList = new LinkedList(); // 이미 requestMap 에 해당 Resource 에 대한 Role 이 // 하나 이상 맵핑되어 있었던 경우, sort_order 는 // resource(Resource) 에 대해 매겨지므로 같은 // Resource 에 대한 Role 맵핑은 연속으로 조회됨. // 해당 맵핑 Role List (SecurityConfig) 의 데이터를 // 재활용하여 새롭게 데이터 구축 if (preResource != null && presentResourceStr.equals(preResource)) { List preAuthList = (List) ((ConfigAttributeDefinition) resourcesMap .get(presentResource)).getConfigAttributes(); Iterator preAuthItr = preAuthList.iterator(); while (preAuthItr.hasNext()) { SecurityConfig tempConfig = (SecurityConfig) preAuthItr.next(); configList.add(tempConfig); } } configList .add(new SecurityConfig((String) tempMap.get("authority"))); ConfigAttributeDefinition cad = new ConfigAttributeDefinition(configList); // 만약 동일한 Resource 에 대해 한개 이상의 Role 맵핑 추가인 // 경우 이전 resourceKey 에 현재 새로 계산된 Role 맵핑 // 리스트로 덮어쓰게 됨. resourcesMap.put(presentResource, cad); // 이전 resource 비교위해 저장 preResource = presentResourceStr; } return resourcesMap; } public LinkedHashMap getRolesAndUrl() throws Exception { return getRolesAndResources("url"); } public LinkedHashMap getRolesAndMethod() throws Exception { return getRolesAndResources("method"); } public LinkedHashMap getRolesAndPointcut() throws Exception { return getRolesAndResources("pointcut"); } public ConfigAttributeDefinition getRegexMatchedRequestMapping(String url) throws Exception { ConfigAttributeDefinition attributes = null; // best regex matching - best 매칭된 Uri 에 따른 Role // List 조회, DB 차원의 정규식 지원이 있는 경우 사용 (ex. hsqldb // custom function, Oracle 10g regexp_like 등) Map paramMap = new HashMap(); paramMap.put("url", url); List resultList = this.namedParameterJdbcTemplate.queryForList( getSqlRegexMatchedRequestMapping(), paramMap); Iterator itr = resultList.iterator(); Map tempMap; List configList = new LinkedList(); // 같은 Uri 에 대한 Role 맵핑이므로 무조건 configList 에 add // 함 while (itr.hasNext()) { tempMap = (Map) itr.next(); configList .add(new SecurityConfig((String) tempMap.get("authority"))); } if (configList.size() > 0) { attributes = new ConfigAttributeDefinition(configList); EgovSecuredObjectService.LOGGER.debug("Request Uri : " + url + ", matched Uri : " + ((Map) resultList.get(0)).get("uri") + ", mapping Roles : " + attributes); } return attributes; } public String getHierarchicalRoles() throws Exception { List resultList = this.namedParameterJdbcTemplate.queryForList( getSqlHierarchicalRoles(), new HashMap()); Iterator itr = resultList.iterator(); StringBuffer concatedRoles = new StringBuffer(); Map tempMap; while (itr.hasNext()) { tempMap = (Map) itr.next(); concatedRoles.append(tempMap.get("child")); concatedRoles.append(" > "); concatedRoles.append(tempMap.get("parent")); concatedRoles.append("\n"); } return concatedRoles.toString(); } }