Authentication and Authorization

요청을 보낸 클라이언트가 등록된 사용자인지 체크하여 로그인하게 해주는 Authentication과 사용자와 어플리케이션 내의 자원 간의 관계 정보를 기반으로 접근 권한을 관리하는 Authorization은 어플리케이션 개발 시 항상 고려되어야 하는 부분 중의 하나이며 두 부분이 밀접히 관련되어 있다.
인증과 권한 기능을 어플리케이션에 추가하려면 몇 가지 고려해야 할 것이 있다.
  • 사용자 정보는 어떤 방법(DB, LDAP, FILE, NT … )을 이용해 관리할 것인지 ...
  • 인증된 사용자 정보를 어떻게 (Session, Cookie… ) 저장할 것인지 ...
  • 사용자에게 권한을 부여하는 방법과 접근을 통제할 자원은 어떤 것인지 ...
JAAS 기반의 인증 방식을 적용하여 Login Context를 추상화함으로써 Login Module 개발 시 어플리케이션 코드의 수정 없이 타 시스템을 통한 인증을 수행할 수 있도록 처리하는 것이 가장 바람직하며, 프로젝트별 인증 처리 요건(ex. 외부 인증 솔루션 적용)에 맞게 작성해야 한다.
인증과 권한 관리 기능은 모든 어플리케이션에서 그대로 재사용할 수 있는 것은 아니다. 각 어플리케이션마다 정책이 다를 수 있으므로 커스터마이징이 필요하기 때문이다. 여기에서는 Anyframe Web의 Struts 기반 개발시 인증과 권한 관리 방법에 대해 살펴보기로 한다.

Authentication

여기서는 일반적으로 많이 쓰이는 인증 방법인 DB에 저장된 사용자 정보를 기반으로, 인증을 수행하는 예에 대해 알아본다.
  1. Anyframe 기반에서 인증 수행을 위한 서비스 개발. 이때, 해당 서비스에서는 인증된 사용자 정보를 담은 javax.security.auth.Subject 객체 전달
  2. 로그인 수행을 위한 Action 코드에서 User ID, Password를 기반으로 해당 서비스를 호출하여 유효성 검증
  3. 인증된 사용자 정보를 담고 있는 Subject 객체 내에 사용자가 속한 그룹(Role)의 정보를 TypedPrincipal 형태로 저장
  4. Subject 객체를 'subject'라는 key값으로 Session에 저장
  5. 이 후 Session에 저장된 Subject 객체를 이용하여 권한 관리 수행

Samples

다음은 DB 기반의 사용자 인증 처리를 수행하는 서비스 DBAuthenticationServiceImpl.java 의 일부분이다.
public class DBAuthenticationServiceImpl implements AuthenticationService {

	// 중략 ...
	 
	public Subject authenticate(anyframe.sample.struts.services.UserVO userVO)
			throws Exception {

		Subject subject = null;
		ResultSet rsu = null;
		PreparedStatement pstmt = null;
		Connection conn = null;

		String userId = userVO.getUserId();
		String password = userVO.getPassword();

		try {
			conn = dataSource.getConnection();

			pstmt = conn.prepareStatement(sqlQuery);

			pstmt.setString(1, userId);
			pstmt.setString(2, password);

			// 입력된 사용자 정보를 기반으로 등록된 사용자 정보 검색
			rsu = pstmt.executeQuery();

			if (rsu.next()) {

				userId = rsu.getString(1);
				String userName = rsu.getString(2);
				rsu.getString(3);
				String grade = rsu.getString(5);

				Set principals = new HashSet();
				Set credentials = new HashSet();

				principals
					.add(new TypedPrincipal(userName, TypedPrincipal.USER));

				StringTokenizer tokens = new StringTokenizer(grade, ",");
				while (tokens.hasMoreTokens()) {
					principals.add(new TypedPrincipal(tokens.nextToken(),
							TypedPrincipal.GROUP));
				}

				// 사용자 정보를 Subject 객체에 저장
				subject = new Subject(false, principals, credentials,
						credentials);
			} else {
				throw new FailedLoginException();
			}
		}catch (Exception e) {
			// 중략 ...
		} finally {
			// 중략 ...
		}
		return subject;
	}
}
다음은 앞서 구현한 DBAuthenticationServiceImpl 클래스의 속성 정의 파일인 context-authentication.xml 의 일부이다. USER_ID와 PASSWORD 정보를 이용하여 사용자 정보와 그룹(Role) 정보를 조회하는 쿼리문을 속성값으로 정의하고 있음을 알 수 있다. 해당 서비스는 이 쿼리문을 이용하게 될 것이다.
<bean id="authenticationService"
	class="anyframe.sample.struts.services.impl.DBAuthenticationServiceImpl">
	<property name="dataSource" ref="dataSource" />
	<property name="sqlQuery"
		value="SELECT u.USER_ID,u.USER_NAME,u.PASSWORD,u.ENABLED,a.AUTHORITY 
		FROM USERS u, AUTHORITIES a 
		WHERE u.USER_ID=? and u.PASSWORD=? and a.USER_ID = u.USER_ID" />
</bean>
다음은 LoginAction.java 로, 앞서 정의한 서비스를 이용하여 사용자의 유효성을 체크하고, 유효한 사용자 정보를 Session에 저장하는 역할을 수행하고 있다.
public ActionForward process(ActionMapping mapping, ActionForm form,
		HttpServletRequest request, HttpServletResponse response) 
		throws Exception {
	
	AuthenticationService authenticationService = 
			(AuthenticationService) getService("authenticationService");

	UserForm userForm = (UserForm) form;
	UserVO userVO = new UserVO();
	BeanUtils.copyProperties(userVO, userForm);

	Subject subject = authenticationService.authenticate(userVO);

	HttpSession session = request.getSession();

	session.setAttribute("subject", subject);
		
	return (mapping.findForward("success"));
}

Authorization

Action 단위로 접근 권한 제어가 가능하다.

접근 권한 제어 프로세스

다음 그림에서 보여지는 사용자 정보를 기반으로 어떻게 특정 URL에 대한 접근 제어가 이루어지는지 살펴보도록 하자.
  1. Struts 속성 정의 파일 내에 Action 매핑시 roles 속성값 부여
  2. Anyframe Web에서 확장한 DefaultRequestProcessor의 processRoles 메소드에서 Session에 저장되어 있는 Subject 객체의 값과 roles 정보 비교 후 해당 Action 수행 여부 결정

Samples

다음은 특정 URL에 접근 가능한 사용자 그룹(Role)을 지정하고 있는 struts-config-authorization.xml 의 Action 매핑 정보이다.
<action path="/authorization"
 	type="anyframe.web.struts.action.DefaultForwardAction"
 	roles="admin"
 	scope="request"
 	parameter="/extensions/accessSuccess.jsp">
</action>
위의 예에서 tester라는 USER_ID를 가진 사용자는 admin이란 GROUP에 속해 있으므로 authorization.do라는 요청을 수행할 수 있게 된다. roles 속성값이 부여되지 않은 Action의 경우에는 모든 사용자가 접근할 수 있음을 의미한다.

Resources

  • 다운로드
  • 이클립스 프로젝트 형태의 샘플 웹 어플리케이션을 포함하고 있는 anyframe-struts-sample-extensions.zip 파일을 다운받은 후, 테스트 환경 설정 을 참조하여 위에서 제시한 예제 코드를 실행해 볼 수 있다.
    Name
    Download
    anyframe-struts-sample-extensions.zip
    Download


  • 참고자료