[오리지널] CAS 가 정리 한 단일 탈퇴 편 (CAS 가 단일 탈퇴 를 실 현 했 습 니까?)
CAS 총결산 의 단점 퇴출 편
CAS 는 과연 단일 탈퇴 를 이 루 었 을 까?본인 은 JA - SIG CAS v 3.3 과 JA - SIG CAS - CLIENT 3.1.9 의 소스 코드 를 읽 어 보 니 겉 으로 는 단일 탈퇴 가 이 루어 진 것 같 지만 실제로는 실현 되 지 않 았 다.
CAS 의 logout 인터페이스의 실현 을 다음 과 같이 정리 합 니 다.
우선 CAS logout 기능 의 시퀀스 를 살 펴 보 겠 습 니 다.
CAS logout 기능 의 시퀀스 맵
그림 에서 보 듯 이 CAS logout 기능 은 두 단계 가 있 는데 하 나 는 TGT 대상 중 각 Service 를 호출 하 는 logoutOFService 방법 이 고, 다른 하 나 는 캐 시 에서 TGT 대상 을 제거 하 는 것 이다.
CAS 의 AbstractWebApplicationService 에서 logoutOFService 방법의 실현 을 살 펴 보 겠 습 니 다.
public synchronized boolean logOutOfService(final String sessionIdentifier) {
if (this.loggedOutAlready) {
return true;
}
LOG.debug("Sending logout request for: " + getId());
final String logoutRequest = "<samlp:LogoutRequest xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" ID=\""
+ GENERATOR.getNewTicketId("LR")
+ "\" Version=\"2.0\" IssueInstant=\"" + SamlUtils.getCurrentDateAndTime()
+ "\"><saml:NameID xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">@NOT_USED@</saml:NameID><samlp:SessionIndex>"
+ sessionIdentifier + "</samlp:SessionIndex></samlp:LogoutRequest>";
this.loggedOutAlready = true;
if (this.httpClient != null) {
return this.httpClient.sendMessageToEndPoint(getOriginalUrl(), logoutRequest);
}
return false;
}
또한 HttpClient 클래스 에서 sendmessage ToEndPoint 방법 은 다음 과 같 습 니 다.
public boolean sendMessageToEndPoint(final String url, final String message) {
HttpURLConnection connection = null;
BufferedReader in = null;
try {
if (log.isDebugEnabled()) {
log.debug("Attempting to access " + url);
}
final URL logoutUrl = new URL(url);
final String output = "logoutRequest=" + URLEncoder.encode(message, "UTF-8");
connection = (HttpURLConnection) logoutUrl.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setReadTimeout(this.readTimeout);
connection.setConnectTimeout(this.connectionTimeout);
connection.setRequestProperty("Content-Length", ""
+ Integer.toString(output.getBytes().length));
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
final DataOutputStream printout = new DataOutputStream(connection
.getOutputStream());
printout.writeBytes(output);
printout.flush();
printout.close();
in = new BufferedReader(new InputStreamReader(connection
.getInputStream()));
while (in.readLine() != null) {
// nothing to do
}
if (log.isDebugEnabled()) {
log.debug("Finished sending message to" + url);
}
return true;
} catch (final Exception e) {
log.error(e,e);
return false;
} finally {
if (in != null) {
try {
in.close();
} catch (final IOException e) {
// can't do anything
}
}
if (connection != null) {
connection.disconnect();
}
}
}
코드 를 읽 어 보면 logOutOfService 방법 은 serivce 의 origin Url 인 터 페 이 스 를 호출 하고 HttpURLConnection 방식 으로 종료 요청 을 service 에 보 내 는 것 으로 HttpURLConnection 에 requestMethod 를 설정 하지 않 았 음 을 주의 하 므 로 기본 GET 방법 을 사용 합 니 다.session Identifier 의 값 은 ST 의 값 입 니 다.서 비 스 는 response 에서 logoutRequest 매개 변수 에 있 는 session Identifier 의 값 을 분석 한 다음 session Identifier 표지 의 session kill 을 없 애 면 됩 니 다.이때 우 리 는 원리 적 으로 한 점 에서 물 러 날 수 있다 는 것 을 발견 했다.
클 라 이언 트 의 실현 을 살 펴 보면 클 라 이언 트 와 단일 지점 종료 와 관련 된 종 류 는 다음 과 같 습 니 다.
MANAGED_SESSIONS: key 는 ST 의 값 이 고 value 는 session 입 니 다.
ID_TO_SESSION_KEY_MAPPING: key 는 sessionId 이 고 value 는 ST 의 값 입 니 다.
싱글 Sign OutFilter 의 doFilter 방법 을 살 펴 보 겠 습 니 다.
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
if ("POST".equals(request.getMethod())) {
final String logoutRequest = CommonUtils.safeGetParameter(request, "logoutRequest");
if (CommonUtils.isNotBlank(logoutRequest)) {
if (log.isTraceEnabled()) {
log.trace ("Logout request=[" + logoutRequest + "]");
}
final String sessionIdentifier = XmlUtils.getTextForElement(logoutRequest, "SessionIndex");
if (CommonUtils.isNotBlank(sessionIdentifier)) {
final HttpSession session = SESSION_MAPPING_STORAGE.removeSessionByMappingId(sessionIdentifier);
if (session != null) {
String sessionID = session.getId();
if (log.isDebugEnabled()) {
log.debug ("Invalidating session [" + sessionID + "] for ST [" + sessionIdentifier + "]");
}
try {
session.invalidate();
} catch (final IllegalStateException e) {
log.debug(e,e);
}
}
return;
}
}
} else {
final String artifact = CommonUtils.safeGetParameter(request, this.artifactParameterName);
final HttpSession session = request.getSession(false);
if (session != null) {
if (log.isDebugEnabled()) {
log.debug("Storing session identifier for " + session.getId());
}
if (CommonUtils.isNotBlank(artifact)) {
try {
SESSION_MAPPING_STORAGE.removeBySessionById(session.getId());
} catch (final Exception e) {
// ignore if the session is already marked as invalid. Nothing we can do!
}
SESSION_MAPPING_STORAGE.addSessionById(artifact, session);
}
} else {
log.debug("No Session Found, so ignoring.");
}
}
filterChain.doFilter(servletRequest, servletResponse);
}
이상 하 게 도 이 방법 은 request 의 방법 을 먼저 판단 하 였 습 니 다. POST 라면 session. invalidate 방법 을 실행 하여 단일 지점 에서 종료 합 니 다. GET 라면 ticket 매개 변수 가 존재 하 는 상황 에서 session 을 Session MappingStorage 에 저장 하고 session. invalidate 방법 을 영원히 실행 하지 않 으 며 단일 지점 에서 종료 할 수 없습니다.CAS 의 logoutRequest 요청 은 GET 방법 으로 보 내 왔 기 때문에 단일 로그 인 기능 이 구현 되 지 않 았 습 니 다.
저 는 SingleSignOutFilter 의 doFilter 방법 에 대해 다시 썼 습 니 다. 코드 는 다음 과 같 습 니 다.경험 증, 확실히 단일 탈퇴 를 실현 하 였 습 니 다.
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final String logoutRequest = CommonUtils.safeGetParameter(request, "logoutRequest");
Enumeration ff = request.getParameterNames();
String a = request.getQueryString();
if (CommonUtils.isNotBlank(logoutRequest)) {
final String sessionIdentifier = XmlUtils.getTextForElement(logoutRequest, "SessionIndex");
if (CommonUtils.isNotBlank(sessionIdentifier)) {
final HttpSession session = SESSION_MAPPING_STORAGE.removeSessionByMappingId(sessionIdentifier);
if (session != null) {
String sessionID = session.getId();
try {
session.invalidate();
} catch (final IllegalStateException e) {
}
}
}
}
else{
final String artifact = CommonUtils.safeGetParameter(request, this.artifactParameterName);
final HttpSession session = request.getSession(false);
if (CommonUtils.isNotBlank(artifact) && session!=null) {
try {
SESSION_MAPPING_STORAGE.removeBySessionById(session.getId());
} catch (final Exception e) {
}
SESSION_MAPPING_STORAGE.addSessionById(artifact, session);
}
}
filterChain.doFilter(servletRequest, servletResponse);
}
또한 주의해 야 할 것 은 클 라 이언 트 가 세 개의 Filter: AuthenticationFilter, ServiceValidationFilter, SingleSignOutFilter 를 배 치 했 기 때문에 세 개의 Filter 순 서 는 주의해 야 합 니 다. 제 순 서 는 AuthenticationFilter, ServiceValidationFilter, SingleSignOutFilter 입 니 다. 처음에는 안 됩 니 다. 종료 기능 을 실행 할 때CAS 서버 는 HttpURLConnection 으로 클 라 이언 트 를 방문 합 니 다. sessionId 를 대신 하지 않 았 기 때문에 AuthenticationFilter 에서 CAS 로 리 디 렉 션 되 었 습 니 다. SingleSign OutFilter 에 도착 하지 못 했 습 니 다. 제 가 변경 한 것 은 AuthenticationFilter 의 redirectUrl 입 니 다. 그 다음 에 session ID 의 값 을 추 가 했 습 니 다. 형식 은 "; jsessionid =" 입 니 다.이렇게 CAS 에서 서비스 파 라미 터 를 분석 하여 웹 응용 프로그램 서 비 스 를 생 성 할 때 orginUrl 에 sessionId 가 있 습 니 다.
이렇게 해서 단일 탈퇴 가 실현 되 었 지만 CAS 의 이러한 Filter 방식 은 너무 번 거 로 운 것 같 습 니 다. 고객 애플 리 케 이 션 에 콜 백 url 을 제공 하 는 것 이 좋 습 니 다. CAS 는 이 콜 백 url 을 직접 호출 하여 종료 하 는 것 이 좋 습 니 다. 그러나 이렇게 하면 CAS 에 대한 변경 이 매우 큽 니 다.
본인 블 로그:http://zhenkm0507.iteye.com
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
thymeleaf로 HTML 페이지를 동적으로 만듭니다 (spring + gradle)지난번에는 에서 화면에 HTML을 표시했습니다. 이번에는 화면을 동적으로 움직여보고 싶기 때문에 입력한 문자를 화면에 표시시키고 싶습니다. 초보자의 비망록이므로 이상한 점 등 있으면 지적 받을 수 있으면 기쁩니다! ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.