구조는 replacementLoginUrl과 casServerLoginUrl를 init-param으로 받고 casServerLoginUrl을 HttpClient로 연결을 해봐서 문제가 없으면 filterChain으로 계속 처리를 하고 아니면 replacementLoginUrl 페이지로 리다이렉트 시킵니다.
중요한 것은 web.xml에서 CasAuthenticationFilter 보다 위에 정의를 해야 한다는 점입니다.
아래에 해버리면 아무 의미가 없어져 버린다는...
CAS 3.1은 single sign out을 지원하도록 설계되어 있습니다. 언제든지 부여된 티켓이 만료되면 로그아웃 프로토콜이 초기화 될 수 있습니다. 로그아웃을 지원하지 않는 클라이언트는 추가의 요구사항을 아무것도 하지 않았다고 나타내는 그들의 로그에 남길 수 있습니다.
... 번역하다가 실패... 아래 내용은 이해 되는대로 다시 정리 -_ㅜ...
Where Single Sign Out Works:
Clients / Languages whose session management is maintained on the server side. CAS clients can then access session information to end the session. CAS 클라이언트는
Where Single Sign Out Doesn't Work:
Clients / Languages whose only session management consists of cookies. CAS does not have access to the browser's cookies and cannot therefore terminate a session. (however, closing a browser window should do that)
How it works:
When a CAS session ends, it will callback to each of the services that are registered with the system and send a POST request with the following:
The URL that will be POSTed to is the original service url.
At this moment the session identifier is the same as the CAS Service Ticket (the service ticket should be sufficiently long to be secure). The session identifier should map back to a session which can be terminated (i.e. deleted from a database, expired, etc.)
Alternative future choices for this protocol would be to transfer the LogoutRequest via SOAP (like SAML 1.1 responses).
Disabling Single Sign Out on the Server
Because not all clients support single sign out, you may need to disable it at the server level. Each ArgumentExtractor has a property called "disableSingleSignOut", which if set to true will make sure the callback does not occur.
CAS Client는 WAS의 web.xml에 filter설정에 의하여 동작을 하게됩니다.
역시 구축 시에 정리해 놓는 것이 좋을 듯하여 슥삭슥삭... (물론 틀릴 가능성은 많습니다 ㅋㅋㅋ)
CAS Client Filter들은 그냥 정의해서는 되는게 아니랍니다. 다음과 같은 순서로 필터를 정의해야 합니다.
1. AuthenticationFilter
2. TicketValidationFilter
3. HttpServletRequestWrapperFilter
4. AssertionThreadLocalFilter
ㅁ 필수요소
- casServerLoginUrl: CAS 서버의 login URL을 정의합니다. ex) https://cas.vicki.co.kr:8443/login
- service: CAS서버로 메시지를 보낼 service URL을 정의합니다. ex) https://client.vicki.co.kr:8443/index.html
- serverName: 어플리케이션(클라이언트가 설치된)의 서버 이름을 정의합니다. ex) https://client.vicki.co.kr:8443
ㅁ 옵션
- renew: 갱신(renew) 시 CAS 서버에 전송 여부를 설정합니다.
- gateway: Gateway CAS 서버 전송 여부를 설정 (??????)
- artifactParameterName: ticket의 파라미터 이름을 정의
- serviceParameterName: service의 파라미터 이름을 정의
그 다음으로는 각 ticket 별 TickatValidationFilter 입니다. org.jasig.cas.client.validation.Cas10TicketValidationFilter
CAS 1.0 Protocol 입니다. (현재 프로젝트에서는 안쓰므로 일단 스킵) org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter
CAS 2.0 Protocol 입니다. (위와 마찬가지 이유로 스킵)
ㅁ 필수요소
- casServerUrlPrefix: CAS 서버 URL을 시작(prefix) ex) https://cas.vicki.co.kr:8443
ㅁ 옵션
- redirectAfterValidation(default: false): 티켓 validation 후에 티켓 파라미터 없이 같은 URL로 리다이렉트
- userSession(default: true): 세션에 Assertion을 저장할지 말지를 설정
- exceptionOnValidationFailure (default: true): 티켓 validation이 실패했을 때 exception을 던질지의 여부
- tolerance (default: 1000): SAML 티켓을 validating 할 때의 트리프트 클럭에 대한 내성
- renew (default: false): 갱신(renew) 시에 CAS 서버로 전송 여부를 설정
세번째로 HttpServletRequestWrapperFilter 입니다. org.jasig.cas.client.util.HttpServletRequestWrapperFilter
getRemoteUser() 와 getPrincipal() 메소드가 CAS과 관련있는 엔트리들을 반환하기 위해 HttpServletRequest를 랩핑
마지막으로 AssertionThreadLocalFilter 입니다. org.jasig.cas.client.util.AssertionThreadLocalFilter
접속할 필요가 있는 어플리케이션의 일부에 대한 ThreadLocal 내에 Assertion을 위치시킨다. Princial의 이름을 가져올 때에 HttpServletRequest에서는 접근을 할 수 없으며, getRemoteUser() 호출로는 불가능 하므로 위의 필터가 유용합니다. 아니 유용하답니다.
ㅁ AbstractJdbcUsernamePasswordAuthenticationHandler
- 데이터베이스 인증 핸들러에 대한 추상 클래스.
ㅁ BindModeSearchDatabaseAuthenticationHandler
- 제공된 사용자 이름 및 암호를 사용하여 데이터베이스에 대한 연결을 열어 사용자 인증을 시도.
서버는 URL을 키로 갖고, 필요로하는 데이터베이스 드라이버의 타입을 프로퍼티로 갖는 Properties와 같은 클래스를 제공.
ㅁ QueryDatabaseAuthenticationHandler
- 사용자 이름을 파라미터로 한 쿼리에 의해 리턴된 패스워드는 사용자에 의해 제공된 패스워드의 변환된 버전과 비교되어 짐.
일치 한다면 인증은 성공. 기본 암호 변역기는 일반텍스트 번역기. (???)
ㅁ SearchModeSearchDatabaseAuthenticationHandler
- 사용자 이름과 패스워드에 사용된 암호화 방식을 조회하는 핸들러 (???)
이 클래스의 기본적으로 PlainTextPAsswordTranslator의 PasswordTranslator.
------------------------------------------------------------------------------- Test set: org.jasig.cas.authentication.principal.GoogleAccountsServiceTests ------------------------------------------------------------------------------- Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.016 sec <<< FAILURE! testResponse(org.jasig.cas.authentication.principal.GoogleAccountsServiceTests) Time elapsed: 0 sec <<< ERROR! java.io.FileNotFoundException: class path resource [DSAPublicKey01.key] cannot be opened because it does not exist
GoogleAccountsArgumentsExtractor 관련 실패 로그
------------------------------------------------------------------------------- Test set: org.jasig.cas.web.support.GoogleAccountsArgumentExtractorTests ------------------------------------------------------------------------------- Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0 sec <<< FAILURE! testNoService(org.jasig.cas.web.support.GoogleAccountsArgumentExtractorTests) Time elapsed: 0 sec <<< ERROR! java.io.FileNotFoundException: class path resource [DSAPublicKey01.key] cannot be opened because it does not exist
위의 문제들 모두다 어떤 파일들이 없다는 것 입니다. 보아하니 인증서 관련 문제인 것 같았습니다. 하지만 아무리 구글을 뒤져봐도 나오지 않는 해결책으로 인하여 결국 CAS 소스 서버를 뒤지게 되었습니다.
ㅁ Web 방식 CAS Source Repository
우측 상단에 DSAPublicKey01.key를 검색합니다.
ㅁ trunk 데이터 조회
아래쪽에 있는 trunk 데이터를 클릭하여 리소스에 접근 합니다.
ㅁ 실제 파일을 다운로드
아래쪽에 보면 raw 라는 링크가 있습니다. 그것을 클릭하여 다운 받습니다.
이런식으로 아래의 세 가지 파일을 구합니다.
jaas.conf, DSAPublicKey01.key, DSAPrivateKey01.key
그런 후 각 파일을 cas server maven project의 해당 경로에 넣어줍니다. jaas.conf - /cas-server-3.3.5/cas-server-core/src/test/resources/org/jasig/cas/authentication/handler/support/jaas.conf DSAPrivateKey01.key - /cas-server-3.3.5/cas-server-core/src/test/resources/DSAPrivateKey01.key DSAPublicKey01.key - /cas-server-3.3.5/cas-server-core/src/test/resources/DSAPublicKey01.key
그러면 빌드 시 문제는 해결됩니다. 하지만 이게 정식 해결책인지는 검증을 해보지 못 하였음을 알려드립니다.
SafeDispatcherServlet: The Spring DispatcherServlet we wrap threw on init. But for our having caught this error, the servlet would not have initialized. org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from ServletContext resource [/WEB-INF/-servlet.xml]; nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/-servlet.xml]
뜬금 없는 /WEB-INF/-servlet.xml ... "-servlet.xml" 앞에 먼가 있을 것 같은데...
CAS Server를 설치하다가 문제에 봉착하였습니다.
회사 내에서 사용하기 위해 Internal Repository를 Sonatype Nexus 로 구성해 놓았는데, cas에서 설정된 사설 repository에 있는 jar를 받지 못하는 문제가 발생하였습니다.
현재 cas 에 잡혀있는 repository
에러를 보아하니 nexus에서 위의 repository에 접근하지 못하는 문제로 보였습니다.
Repositories 에서 Add - Proxy Repository 를 선택합니다.
아래와 같이 새로운 Proxy Repository 정보를 입력합니다. Repository ID: jasig-repository Repository name: JA-SIG Maven2 Repository Remote Storage Location: http://developer.ja-sig.org/maven2
local setting에 기본적으로 public group을 연결해 놓았을 것이므로 Public Repository 그룹의 Configuration을 이용하여 JA-SIG Maven2 Repository를 추가합니다.