도메인 acl을 적용해 보자
집에가서 소스 코드 업로드 및 수정 보완 할 것.
기본적인 구성은 http://starplatina.tistory.com/entry/Spring-Security-ACL-Example
여기 링크의 url 을 참고로 소스를 재구성 하였삼.
스프링 도메인 ACLS
- Security 부분이 다른 비즈니스 로직과 독립적으로 운용된다.(도메인 클래스에 따로 ACL 및 보안 관련된 값들이 없고, 별도 테이블에서 관리)
- Affirmative(긍정적인), Consensus(합의에 의한), Unanimous(만장일치의) 권한 체크를 한다. Voter라는 클래스가 투표를 하게 되는데 여기서 긍적적인 표가 한개라도 있으면, 긍정 중립 부정 표를 비교 해서 긍정 표가 있으면, 모두 긍정으로 투표하였을 경우
- accessControllist라는 jsp tag로 권한에 따라서 뷰를 조작 할 수 있다.
- 권한 관리를 위한 테이블이 추가 된다(acl 관련 테이블 4개, 기타 시큐리티 권한 관련 클래스 2~3개)
- 도메인 클래스에 대한 acl 작성시 aop를 사용해서 권한을 부여하는 작업을 해야 한다.
도메인 ACL의 경우 물론 스프링 시큐리티에 대한 이해가 필요 합니다.
(url 보안, 메서드 보안(롤베이스, acl 베이스))
그럼 간단하게 acl을 적용하는 케이스를 보면서 이에 대해서 코드를 구성해나가는 방법으로 알아 보도록 하겠습니다.
일단 어떤 도메인 오브젝트가 있다고 보고 이에 대한 읽기 권한에 대해서 제어를 할 경우.
보통 서비스 클래스의 메서드에 작업을 하게 됩니다.
@Secured({"ROLE_USER", "ACL_OBJECT_READ"})
public Object getObj( String id) {
return (AclBbs)aclBbsDAO.getBbs( id);
}
@Security("USER_ROLE")은 스프링 시큐리티에서 지원하는 롤 베이스 메서드 보안입니다.
getObj()라는 메서드를 호출 할 때, 이 메서드를 호출 하는 사용자가 "USER_ROLE"이라는 권한이 있는지 확인하여 권한이 있을 경우에만 메서드를 실행 할 수 있도록 합니다.
@Security({"USER_ROLE", "ACL_OBJECT_READ"}) 굵게 표시한 "ACL_OBJECT_READ" 이 부분이 바로 ACL 권한을 체크하는 부분입니다.
이 경우에는 조회 할려는 도메인 오브젝트에 대한 사용자의 권한(읽기)이 존재 할 경우에만 메서드를 실행 합니다.
그럼 위 메서드 보안이 동작 하도록 하기 위해서 작업해야할 흐름들을 알아 보도록 하겠습니다.
1. 도메인 오브젝트를 작성 할 때(insert 할때), ACL 권한과 관련된 작업들을 함께 처리해 주어야 한다.
-> 오브젝트에 대한 권한 부여를 해주어야 한다.
2. 시큐리티 설정을 통해서 오브젝트를 호출 할 때, 메서드 보안을 통해 ACL 권한 체크를 하도록 처리 한다.
-> 권한체크 방법(긍정적인, 합의에 의한, 만장일치)에 따라 권한을 체크 해 주어야한다.
기본적으로 위 두가지 작업을 해 주게 되면 보안 작업이 완료 됩니다.
ACL 권한 부여의 경우 서비스 클래스에서 insert 작업이 일어날 경우 작업을 진행하면 됩니다.
insert 메서드 내부에 권한부여 작업을 호출할 수도 있지만, 이렇게 하면 비즈니스로직과 관련없는 로직이 들어가므로 AOP를 적용하여 권한부여 작업을 진행 하도록 합니다.
시큐리티 UML
위 UML에서 AclSecurityUtil은 Acl 오브젝트에 대한 권한 부여를 하는 메서드(addPermission, deletePermission)를 가진 인터페이스 입니다. SecurityService는 AOP를 사용해서 실제 권한 부여 작업을 하는 인터페이스 입니다. SecurityService에서 setPermissions를 통해 AclSecurityUtil의 addPermission을 호출하여 권한을 부여 합니다.
위와 같은 방법으로 권한 부여에 관한 로직을 작성 한 후, XML 설정을 통해서 이를 동작하도록 해 주어야 합니다.
XML 설정
XML 설정은 권한 체크 방법을 정의 하고, 체크할 권한에 대한 정의, ACL 권한 부여에 필요한 bean 정의 를 하게 됩니다.
일단 가장 먼저 해야할 일이 메서드 시큐리티에 대한 access-decision-manager를 설정 해야 합니다.
secured-annotations="enabled" access-decision-manager-ref="businessAccessDecisionManager" >
</sec:global-method-security>
<bean id="businessAccessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
<property name="allowIfAllAbstainDecisions" value="true" />
<property name="decisionVoters">
<util:list>
<bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter" />
<ref local="aclObjectReadVoter" />
<ref local="aclObjectWriteVoter" />
</util:list>
</property>
</bean>
위의 설정을 보면 access-decision-manager로 businessAccessDecisionManager를 참조 하도록 하고, businessAccessDecisionManager에서는 UnanimouseBased(만장일치) 방식으로 권한 체크를 하도록 하고 있습니다. 만약 다른 방법으로 사용하고 싶다면 클래스를 AffirmativeBased나 ConsensusBased로 정의 하면 각각의 방식으로 권한 체크를 하게 됩니다.
그다음에 정의해 주어야 할 것이 decisionVoters 입니다. 권한 체크를 할 떄 저 voter들을 순차적으로 호출 하면서, 권한이 있는지 실질적으로 체크 하게 됩니다. UnanimouseBased의 decide메서드를 살표보면 아래와 같은 로직을 실행합니다.
AffirmativeBased의 경우 한개라도 허가가 발생 하면 바로 return 하여 권한을 부여 하고, ConsensusBased는 찬성, 반대, 중립 표들을 비교 하여 찬성일 경우만, UnanimouseBased는 모두 찬성일 경우만 권한을 부여 하게 됩니다.
for (ConfigAttribute attribute : attributes) {
singleAttributeList.set(0, attribute);
for(AccessDecisionVoter voter : getDecisionVoters()) {
int result = voter.vote(authentication, object, singleAttributeList);
if (logger.isDebugEnabled()) {
logger.debug("Voter: " + voter + ", returned: " + result);
}
이 경우에는 "ROLE_BASE", "ACL_OBJECT_READ" 가 attributes 가 되겠고, getDecisionVoters()에서 가져온 voter들은 XML 설정 파일에서 정의한 roleVoter, aclObjectReadVoter, aclObjectWriterVoter가 됩니다.
각각의 방식으로 vote를 호출해서 로그인한 사용자가 권한이 있는지 없는지를 확인하게 됩니다.
스프링 시큐리티 ACL 권한의 종류.
BasePermission 클래스 확인하기
기본 권한으로는 READ, WRITE, CREATE, DELETE, ADMINISTRATION 권한을 가지고 있습니다.
만약 다른 권한을 만들고 싶다면, AbstractPermission를 확장하여 구현 하면 됩니다.
추가로 그럼 ACL DA 로직은 어디에 있는가 하는가 하면.
JdbcMutableAclService 클래스를 사용 하여 Acl 관련 서비스를 제공 합니다.
기본 쿼리가 PostregeSql 기본으로 되어 있기 때문에 각각 DB 벤더에 맞게 쿼리를 커스터마이징 해야합니다.
(call identity 등 ANSI 표준 쿼리가 아닌 것만 작성하면 됨)
프로그램 실행 화면.
소스 구성은 간단한 테스트 클래스와, ACL 을 활용한 게시판으로 구성 되어 있습니다.
소스에 첨부된 스키마대로 db를 설치 하고(mysql 기본) STS 최신버전(이클립스 스프링 버전, Spring tool suit 인가 ;)에서 첨부한 파일을 가져다가 실행 시키면 됩니다. 서버는 톰캣 6.0 으로 실행 시키시면 됩니다.
일단 서버를 실행 시키면
이런 화면이 표시 됩니다.
제가 전에 공부하던 소스를 가지고 구성한 것이라... 몇몇 소스가 동작하지 않을 수도 있습니다. ^^;
jquery plug-in을 몇개 포함하고 있습니다.
액션은 전부 jquery를 사용해서 ajax로 처리하도록 되어 있습니다.
글쓰기를 선택하면 글쓰기 화면이 표시되고, 제목을 선택하면 보기 화면으로 넘어갑니다.
jsp에서 권한을 체크하는 부분이 있는데, 이 부분을 보면 아래와 같습니다.
hasPermission 부분에서 접속한 사용자의 권한과 조회한 오브젝트의 ACL 권한을 비교해서 권한이 있을 경우에만 태그 안의 내용을 보여주게 됩니다.(삭제 및 수정 버튼 렌더링 처리)
아래 파일은 프로젝트 압축학 war 파일.
STS에서 불러서 쓰삼.