====== Authentication ====== ===== 개요 ===== 허락된 사용자에게만 공개되는 컨텐츠(정보 또는 기능)에 접근하기 위해 반드시 아이디와 암호를 입력하는 로그인 과정을 거치는데 이러한 과정이 인증(authentication)이다.\\ 즉, 인증은 특정 사용자가 유효한 사용자인지를 판단하는 과정을 의미한다.\\ 본 가이드에서는 인증을 위한 기본적인 환경 및 전자정부 개발프레임워크에서 사용된 인증 방법을 설명한다. ===== 설명 ===== 전자정부 개발프레임워크의 인증은 XML기반의 인증이 아닌 DB기반의 JDBC인증을 사용한다.\\ 기본적인 인증 메커니즘은 인증 주체가 인증을 시도하는 초기에 오직 한 번만 인증 메커니즘이 사용되며 그 이후로는 인증 메커니즘이 정보를 필터에 유지하여 요구되는 요청을 필터 체인상의 다음 필터로 전달하기만 한다.\\ Spring Security 에서 제공하는 인증을 사용하기 위해서는 오직 하나의 AuthenticationManager 구현체만이 포함되어 있으며 AuthenticationProvider의 설정이 필요하다.\\ AuthenticationManager는 요청을 AuthenticationProvider 체인에 전달해야 할 임무가 있다.\\ AuthenticationProvider는 기본적으로 UserDetails 와 UserDetailsService 인터페이스를 이용한다.\\ UserDetailsService 인터페이스 내 loadUserByUsername 메소드의 리턴된 UserDetails은 사용자명(username), 패스워드(password), 허가권한(GrantedAuthority[]) 및 사용여부(enabled)와 같은 기초적인 인증 정보들을 제공한다.\\ 이에 전자정부 개발프레임워크에서는 UserDetails 인터페이스를 확장하였으며 JDBC 기반으로 사용자 테이블로부터 사용자 정보를 VO형태로 사용할 수 있도록 하였다.\\ ==== 최소환경설정 ==== 최소환경설정으로 사용자 인증을 설정하는 예제이다. == Configuration == * 은 여러개를 정의할 수 있으며, 위에서부터 차례로 해당되는 url pattern이 적용된다. 정규식을 사용하여 접근 url을 정의한다. "access"속성은 접근할 수 있는 사용자 권한을 나타낸다. * 을 지정하지 않을 경우 Spring Security에서 제공하는 로그인 폼을 사용한다. 인증요청을 처리하기 위해 authentication manager가 xml(또는 DB, LDAP 등)에 정의된 사용자 정보를 사용한다. * user-service : 사용자 정보(사용자 ID, 사용자 암호, 권한 등)를 얻어오는 서비스 ==== JDBC 인증 ==== JdbcDaoImpl은 SQL 문장을 조정할 수 있도록 해주는 두 개의 프로퍼티를 제공하며 좀더 커스터마이징이 필요할 경우 JdbcDaoImpl을 서브클래싱할 수도 있다. ==== DAO 인증 ==== Server Security에는 AuthenticationProvider 인터페이스의 구현체인 DaoAuthenticationProvider 클래스가 포함되어 있으며 DB기반의 인증을 처리할 수 있다.\\ 사용자명, 패스워드 및 권한 정보를 DB에서 얻어오기 위하여 UserDetailsService 를 이용한다. == Sample == PasswordEncoder와 SaltSource는 선택사항이다. PasswordEncoder는 설정된 UserDetailsService로부터 반환된 UserDetails 객체에 들어있는 비밀번호의 인코딩과 디코딩을 제공한다.\\ SaltSource는 패스워드에 "양념(salt)"을 뿌릴 수 있도록 하는데, 이러한 salt는 인증 저장소에 들어있는 패스워드의 보안을 강화한다.\\ Spring Security에서 제공되는 PasswordEncoder 구현체로는 MD5, SHA, 클리어텍스트(cleartext) 인코딩들이 있다. Spring Security에는 두 개의 SaltSource 구현체가 제공되는데, 모든 비밀번호에 대하여 동일한 salt로 인코딩을 수행하는 SystemWideSaltSource와, 반환된 UserDetails 객체의 프로퍼티를 검사하여 salt를 획득하는 ReflectionSaltSource가 있다. 선택적인 기능들에 관해 자세히 알아보려면 JavaDoc을 참조하길 바란다. ==== HTTP Form 인증 메카니즘 ==== HTTP 폼 인증은 AuthenticationProcessingFilter를 이용하여 로그인 폼을 처리하는 것을 수반한다.\\ HTTP 폼 인증은 어플리케이션에서 가장 널리 사용되는 최종 사용자에 대한 인증 방법이다.\\ 로그인 폼은 단순히 j_username과 j_password 입력 필드를 포함하며, 필터에 의해 모니터링되고 있는 URL로 게시한다.기본값은 j_spring_security_check 이다. ==== 기타 인증 ==== BASIC 인증\\ 다이제스트 인증\\ 익명 인증\\ Remember-Me 인증\\ X509 인증\\ LDAP 인증\\ CAS 인증\\ 컨테이너 어댑터 인증 ==== Sample Configuration ==== == WEB Security service == * 설정으로 허용된 사용자만 접근이 가능하게 할 수 있다. * 을 지정할 경우 개발자가 직접 지정한 로그인 폼을 사용할 수 있다. * 사용자 정보(사용자 ID, 사용자 암호, 권한 등)를 얻어오는 기능은 jdbcUserService 에서 담당한다. * password-encoder : 저장된 패스워드의 암호화 알고리즘은 md5를 사용한다. == JDBC User Service == 사용자 정보를 얻어오는 **user service**를 DB에 저장된 사용자 정보를 이용하여 인증할 수 있다. == Sample Source ==
User:
Password:
      
==== 세션관리 ==== Security Service의 세션 기능은 Spring Security의 JdbcUserDetailsManager 인터페이스를 확장하여 EgovJdbcUserDetailsManager 클래스를 구현하였으며\\ 기본 테이블에 기재된 username, password, enabled 필드 외에 다른 사용자 정보를 추가하여 세션정보를 관리할 수 있다. === 세션설정 === == Configuration == 세션 기능을 사용하기 위해서는 JDBC 인증의 환경설정 부분을 전자정부 개발프레임워크 Server Security의 환경으로 수정해야한다.\\ 변경전(사용안함) 변경후(사용) * class : egovframework.rte.fdl.security.userdetails.jdbc.EgovJdbcUserDetailsManager * usersByUsernameQuery : 사용자 인증을 위해 사용자 테이블에서 사용자정보를 조회한다. * authoritiesByUsernameQuery : 사용자 인증을 위해 사용자권한 테이블에서 사용자권한정보를 조회한다. * roleHierarchy : 역할의 계층적 관리를 위해 계층 역할을 설정한다. * mapClass : 세션 사용을 위한 세션 쿼리 및 세션VO간의 매핑 클래스를 설정한다. * dataSource : JDBC 서비스를 위한 dataSource를 설정한다. == VO Class == public class EgovUserDetailsVO { private String userId; private String passWord; private String userName; private String ssn; private String lsYn; private String birthDay; private Integer age; private String cellPhone; private String addr; private String email; public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getPassWord() { return passWord; } public void setPassWord(String passWord) { this.passWord = passWord; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getSsn() { return ssn; } public void setSsn(String ssn) { this.ssn = ssn; } . . . == Mapping Class == public class EgovUserDetailsMapping extends EgovUsersByUsernameMapping { public EgovUserDetailsMapping(DataSource ds, String usersByUsernameQuery) { super(ds, usersByUsernameQuery); } @Override protected Object mapRow(ResultSet rs, int rownum) throws SQLException { String userid = rs.getString("user_id"); String password = rs.getString("password"); boolean enabled = rs.getBoolean("enabled"); String username = rs.getString("user_name"); String birthDay = rs.getString("birth_day"); String ssn = rs.getString("ssn"); EgovUserDetailsVO userVO = new EgovUserDetailsVO(); userVO.setUserId(userid); userVO.setPassWord(password); userVO.setUserName(username); userVO.setBirthDay(birthDay); userVO.setSsn(ssn); return new EgovUserDetails(userid, password, enabled, userVO); } } * EgovUsersByUsernameMapping 클래스 상속 * mapRow 메소드 재정의 * ResultSet 클래스에서 작성된 VO로 데이터 매핑 * VO 객체를 EgovUserDetails(userid, password, enabled, userVO) 에 담아서 리턴 === 세션사용 === == 세션 가져오기 == import egovframework.rte.fdl.security.userdetails.util.EgovUserDetailsHelper; . . . EgovUserDetailsVO user = (EgovUserDetailsVO)EgovUserDetailsHelper.getAuthenticatedUser(); assertEquals("jimi", user.getUserId()); assertEquals("jimi test", user.getUserName()); assertEquals("19800604", user.getBirthDay()); assertEquals("1234567890123", user.getSsn()); == 인증되지 않은 경우 처리 == Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated(); assertFalse(isAuthenticated.booleanValue()); 또는 assertNull(EgovUserDetailsHelper.getAuthenticatedUser()); == 동시 세션처리 == concurrent-session-control * max-sessions : 최대 허용 세션 수 * exception-if-maximum-exceeded : true => 최대 세션 수 초과할 경우 Exception 발생 , false => 최대 세션 수 초과할 경우 강제 로그아웃 ===== N. 참고자료 =====