说明:因为当在浏览器的URL行输入要访问应用的URL后跟无效的ticket时,原有的CAS应用端过滤器会抛出异常,所以加入以下红色部分的代码。
package edu.yale.its.tp.cas.client.filter;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import edu.yale.its.tp.cas.client.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class CASFilter implements Filter {
private static Log log = LogFactory.getLog(CASFilter.class);
// Filter initialization parameters
public final static String LOGIN_INIT_PARAM = "edu.yale.its.tp.cas.client.filter.loginUrl";
public final static String VALIDATE_INIT_PARAM = "edu.yale.its.tp.cas.client.filter.validateUrl";
public final static String SERVICE_INIT_PARAM = "edu.yale.its.tp.cas.client.filter.serviceUrl";
public final static String SERVERNAME_INIT_PARAM = "edu.yale.its.tp.cas.client.filter.serverName";
public final static String RENEW_INIT_PARAM = "edu.yale.its.tp.cas.client.filter.renew";
public final static String AUTHORIZED_PROXY_INIT_PARAM = "edu.yale.its.tp.cas.client.filter.authorizedProxy";
public final static String PROXY_CALLBACK_INIT_PARAM = "edu.yale.its.tp.cas.client.filter.proxyCallbackUrl";
public final static String WRAP_REQUESTS_INIT_PARAM = "edu.yale.its.tp.cas.client.filter.wrapRequest";
public final static String GATEWAY_INIT_PARAM = "edu.yale.its.tp.cas.client.filter.gateway";
// Session attributes used by this filter
/** <p>Session attribute in which the username is stored.</p> */
public final static String CAS_FILTER_USER =
"edu.yale.its.tp.cas.client.filter.user";
/**
* Session attribute in which the CASReceipt is stored.
*/
public final static String CAS_FILTER_RECEIPT =
"edu.yale.its.tp.cas.client.filter.receipt";
/**
* Session attribute in which internally used gateway
* attribute is stored.
*/
private static final String CAS_FILTER_GATEWAYED =
"edu.yale.its.tp.cas.client.filter.didGateway";
//*********************************************************************
// Configuration state
/** Secure URL whereat CAS offers its login service. */
private String casLogin;
/** Secure URL whereat CAS offers its CAS 2.0 validate service */
private String casValidate;
/** Filtered service URL for use as service parameter to login and validate */
private String casServiceUrl;
/** Name of server, for use in assembling service URL for use as service parameter to login and validate. */
private String casServerName;
/** Secure URL whereto this filter should ask CAS to send Proxy Granting Tickets. */
private String casProxyCallbackUrl;
/** True if renew parameter should be set on login and validate */
private boolean casRenew;
/** True if this filter should wrap requests to expose authenticated user as getRemoteUser(); */
private boolean wrapRequest;
/** True if this filter should set gateway=true on login redirect */
private boolean casGateway = false;
/**
* List of ProxyTicketReceptor URLs of services authorized to proxy to the path
* behind this filter.
*/
private List authorizedProxies = new ArrayList();
//*********************************************************************
// Initialization
public void init(FilterConfig config) throws ServletException {
casLogin =
config.getInitParameter(
LOGIN_INIT_PARAM);
casValidate =
config.getInitParameter(
VALIDATE_INIT_PARAM);
casServiceUrl =
config.getInitParameter(
SERVICE_INIT_PARAM);
String casAuthorizedProxy =
config.getInitParameter(
AUTHORIZED_PROXY_INIT_PARAM);
casRenew =
Boolean.valueOf(config.getInitParameter(RENEW_INIT_PARAM)).booleanValue();
casServerName =
config.getInitParameter(
SERVERNAME_INIT_PARAM);
casProxyCallbackUrl =
config.getInitParameter(
PROXY_CALLBACK_INIT_PARAM);
wrapRequest =
Boolean
.valueOf(
config.getInitParameter(
WRAP_REQUESTS_INIT_PARAM))
.booleanValue();
casGateway =
Boolean
.valueOf(
config.getInitParameter(
GATEWAY_INIT_PARAM))
.booleanValue();
if (casGateway && Boolean.valueOf(casRenew).booleanValue()) {
throw new ServletException("gateway and renew cannot both be true in filter configuration");
}
if (casServerName != null && casServiceUrl != null) {
throw new ServletException("serverName and serviceUrl cannot both be set: choose one.");
}
if (casServerName == null && casServiceUrl == null) {
throw new ServletException("one of serverName or serviceUrl must be set.");
}
if (casServiceUrl != null){
if (! (casServiceUrl.startsWith("https://")|| (casServiceUrl.startsWith("http://") ))){
throw new ServletException("service URL must start with http:// or https://; its current value is [" + casServiceUrl + "]");
}
}
if (casValidate == null){
throw new ServletException("validateUrl parameter must be set.");
}
if (! casValidate.startsWith("https://")){
throw new ServletException("validateUrl must start with https://, its current value is [" + casValidate + "]");
}
if (casAuthorizedProxy != null){
// parse and remember authorized proxies
StringTokenizer casProxies =
new StringTokenizer(casAuthorizedProxy);
while (casProxies.hasMoreTokens()) {
String anAuthorizedProxy = casProxies.nextToken();
if (!anAuthorizedProxy.startsWith("https://")){
throw new ServletException("CASFilter initialization parameter for authorized proxies " +
"must be a whitespace delimited list of authorized proxies. " +
"Authorized proxies must be secure (https) addresses. This one wasn't: [" + anAuthorizedProxy + "]");
}
this.authorizedProxies.add(anAuthorizedProxy);
}
}
if (log.isDebugEnabled()){
log.debug(("CASFilter initialized as: [" + toString() + "]"));
}
}
//*********************************************************************
// Filter processing
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain fc)
throws ServletException, IOException {
if (log.isTraceEnabled()){
log.trace("entering doFilter()");
}
// make sure we've got an HTTP request
if (!(request instanceof HttpServletRequest)
|| !(response instanceof HttpServletResponse)) {
log.error("doFilter() called on a request or response that was not an HttpServletRequest or response.");
throw new ServletException("CASFilter protects only HTTP resources");
}
// Is this a request for the proxy callback listener? If so, pass
// it through
if (casProxyCallbackUrl != null
&& casProxyCallbackUrl.endsWith(
((HttpServletRequest) request).getRequestURI())
&& request.getParameter("pgtId") != null
&& request.getParameter("pgtIou") != null) {
log.trace("passing through what we hope is CAS's request for proxy ticket receptor.");
fc.doFilter(request, response);
return;
}
// Wrap the request if desired
if (wrapRequest) {
log.trace("Wrapping request with CASFilterRequestWrapper.");
request = new CASFilterRequestWrapper((HttpServletRequest) request);
}
HttpSession session = ((HttpServletRequest) request).getSession();
// if our attribute's already present and valid, pass through the filter chain
CASReceipt receipt = (CASReceipt) session.getAttribute(CAS_FILTER_RECEIPT);
if (receipt != null && isReceiptAcceptable(receipt)) {
log.trace("CAS_FILTER_RECEIPT attribute was present and acceptable - passing request through filter..");
fc.doFilter(request, response);
return;
}
// otherwise, we need to authenticate via CAS
String ticket = request.getParameter("ticket");
// no ticket? abort request processing and redirect
if (ticket == null || ticket.equals("")) {
log.trace("CAS ticket was not present on request.");
// did we go through the gateway already?
boolean didGateway =
Boolean
.valueOf(
(String) session.getAttribute(
CAS_FILTER_GATEWAYED))
.booleanValue();
if (casLogin == null) {
//TODO: casLogin should probably be ensured to not be null at filter initialization. -awp9
log.fatal("casLogin was not set, so filter cannot redirect request for authentication.");
throw new ServletException(
"When CASFilter protects pages that do not receive a 'ticket' "
+ "parameter, it needs a edu.yale.its.tp.cas.client.filter.loginUrl "
+ "filter parameter");
}
if (!didGateway) {
log.trace("Did not previously gateway. Setting session attribute to true.");
session.setAttribute(
CAS_FILTER_GATEWAYED,
"true");
redirectToCAS(
(HttpServletRequest) request,
(HttpServletResponse) response);
// abort chain
return;
} else {
log.trace("Previously gatewayed.");
// if we should be logged in, make sure validation succeeded
if (casGateway
|| session.getAttribute(CAS_FILTER_USER) != null) {
log.trace("casGateway was true and CAS_FILTER_USER set: passing request along filter chain.");
// continue processing the request
fc.doFilter(request, response);
return;
} else {
// unknown state... redirect to CAS
session.setAttribute(
CAS_FILTER_GATEWAYED,
"true");
redirectToCAS(
(HttpServletRequest) request,
(HttpServletResponse) response);
// abort chain
return;
}
}
}
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse rsp = (HttpServletResponse) response;
try {
receipt = getAuthenticatedUser((HttpServletRequest) request);
} catch (CASAuthenticationException e) {
log.error(e);
String casLoginURL=getCasLoginURL(req);
//当ticket无效时,转向登录页面;否则,显示异常信息
if (e.getMessage().indexOf("INVALID_TICKET") > 0) {
rsp.sendRedirect(casLoginURL);
} else {
sendPageInfo(rsp);
}
return;
}
if (! isReceiptAcceptable(receipt)){
throw new ServletException("Authentication was technically successful but rejected as a matter of policy. [" + receipt + "]");
}
// Store the authenticated user in the session
if (session != null) { // probably unnecessary
session.setAttribute(CAS_FILTER_USER, receipt.getUserName());
session.setAttribute(CASFilter.CAS_FILTER_RECEIPT, receipt);
// don't store extra unnecessary session state
session.removeAttribute(
CAS_FILTER_GATEWAYED);
}
if (log.isTraceEnabled()){
log.trace("validated ticket to get authenticated receipt [" + receipt + "], now passing request along filter chain.");
}
// continue processing the request
fc.doFilter(request, response);
log.trace("returning from doFilter()");
}
private boolean isReceiptAcceptable(CASReceipt receipt) {
if (receipt == null)
throw new IllegalArgumentException("Cannot evaluate a null receipt.");
if (this.casRenew && !receipt.isPrimaryAuthentication()){
return false;
}
if (receipt.isProxied()){
if (! this.authorizedProxies.contains(receipt.getProxyingService())){
return false;
}
}
return true;
}
private CASReceipt getAuthenticatedUser(HttpServletRequest request)
throws ServletException, CASAuthenticationException {
log.trace("entering getAuthenticatedUser()");
ProxyTicketValidator pv = null;
pv = new ProxyTicketValidator();
pv.setCasValidateUrl(casValidate);
pv.setServiceTicket(request.getParameter("ticket"));
pv.setService(getService(request));
pv.setRenew(Boolean.valueOf(casRenew).booleanValue());
if (casProxyCallbackUrl != null) {
pv.setProxyCallbackUrl(casProxyCallbackUrl);
}
if (log.isDebugEnabled()) {
log.debug(
"about to validate ProxyTicketValidator: [" + pv + "]");
}
return CASReceipt.getReceipt(pv);
}
private String getService(HttpServletRequest request)
throws ServletException {
log.trace("entering getService()");
String serviceString;
// ensure we have a server name or service name
if (casServerName == null && casServiceUrl == null)
throw new ServletException(
"need one of the following configuration "
+ "parameters: edu.yale.its.tp.cas.client.filter.serviceUrl or "
+ "edu.yale.its.tp.cas.client.filter.serverName");
// use the given string if it's provided
if (casServiceUrl != null)
serviceString = URLEncoder.encode(casServiceUrl);
else
// otherwise, return our best guess at the service
serviceString = Util.getService(request, casServerName);
if (log.isTraceEnabled()) {
log.trace(
"returning from getService() with service ["
+ serviceString
+ "]");
}
return serviceString;
}
/**
* Redirects the user to CAS, determining the service from the request.
*/
private void redirectToCAS(
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
if (log.isTraceEnabled()) {
log.trace("entering redirectToCAS()");
}
String casLoginString =
casLogin
+ "?service="
+ getService((HttpServletRequest) request)
+ ((casRenew)
? "&renew=true"
: "")
+ (casGateway ? "&gateway=true" : "");
if (log.isDebugEnabled()) {
log.debug("Redirecting browser to [" + casLoginString + ")");
}
((HttpServletResponse) response).sendRedirect(casLoginString);
if (log.isTraceEnabled()) {
log.trace("returning from redirectToCAS()");
}
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("[CASFilter:");
sb.append(" casGateway=");
sb.append(this.casGateway);
sb.append(" wrapRequest=");
sb.append(this.wrapRequest);
sb.append(" casAuthorizedProxies=[");
sb.append(this.authorizedProxies);
sb.append("]");
if (this.casLogin != null) {
sb.append(" casLogin=[");
sb.append(this.casLogin);
sb.append("]");
} else {
sb.append(" casLogin=NULL!!!!!");
}
if (this.casProxyCallbackUrl != null) {
sb.append(" casProxyCallbackUrl=[");
sb.append(casProxyCallbackUrl);
sb.append("]");
}
if (this.casRenew) {
sb.append(" casRenew=true");
}
if (this.casServerName != null) {
sb.append(" casServerName=[");
sb.append(casServerName);
sb.append("]");
}
if (this.casServiceUrl != null) {
sb.append(" casServiceUrl=[");
sb.append(casServiceUrl);
sb.append("]");
}
if (this.casValidate != null) {
sb.append(" casValidate=[");
sb.append(casValidate);
sb.append("]");
} else {
sb.append(" casValidate=NULL!!!");
}
return sb.toString();
}
/* (non-Javadoc)
* @see javax.servlet.Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/***
* 返回单点登录URL和访问的应用系统URL
* @param request
* @return String
* @throws ServletException
*/
private String getCasLoginURL(HttpServletRequest request) throws ServletException {
StringBuilder sb = new StringBuilder();
sb.append(casLogin).append("?service=").append(getService(request));
return sb.toString();
}
/***
* 显示异常信息
* @param rsp
* @param content
* @throws IOException
*/
private void sendPageInfo(HttpServletResponse rsp) throws IOException {
PrintWriter out = rsp.getWriter();
try {
out.print("<body style='background-color: WhiteSmoke'>");
out.print("<div style='font: 20;'>Not Found</div>");
out.print("<hr/>");
out.print("<div style='font: 20;'>Sorry,Error!</div>");
out.print("</body>");
} finally {
out.close();
}
}
}
相关推荐
"client端"指的是这个包服务于那些需要与CAS服务器进行身份验证交互的客户端应用。 在实际应用中,CAS客户端3.3.3主要涉及以下知识点: 1. **CAS协议**:理解CAS的工作流程,包括服务票(Service Ticket)和代理票...
1. **CAS服务端配置**:首先,我们需要搭建CAS服务器,这通常涉及安装CAS服务器软件,配置服务器端的认证逻辑,例如数据库连接以验证用户凭证。 2. **CAS客户端配置**:然后,我们需要在SpringMVC应用中配置CAS...
CAS (Central Authentication Service) 是一项由耶鲁大学发起的开源项目,旨在为Web应用系统提供可靠且灵活的单点登录(Single Sign-On, SSO)解决方案。随着业务场景的不断复杂化,官方提供的CAS Server标准功能...
CAS(Central Authentication Service)是开源的SSO解决方案,由耶鲁大学开发,广泛应用于教育、企业和组织环境中。本资源“单点登录CAS.net客户端源码”提供了实现CAS协议的.NET客户端源代码,适用于.NET框架的项目...
总结来说,"cas-client-3.2.1+cas-server-3.4.10"是实现网络应用SSO认证的一个解决方案,涉及到了客户端和服务端的配置、安全策略、用户认证流程、单点登出以及系统维护等多个方面。正确配置和使用这个组合,可以极...
综上所述,"cas-server-3.5.2-release" 是一个功能丰富的SSO解决方案,包含了SSO的基本原理、部署配置、安全机制、服务注册等多个方面的重要知识点。对于需要构建和管理统一认证平台的IT专业人士来说,理解和掌握...
【CAS客户端开发说明】这篇文档是关于如何进行CAS...总的来说,这个指南详细阐述了建立CAS客户端开发环境、配置、测试以及开发中的关键步骤,为开发者提供了一个清晰的流程,帮助他们理解和实现基于CAS的SSO解决方案。
此外,还需要考虑错误处理和异常情况,以提供健壮的解决方案。 总的来说,Cas 3.4与Restlet的集成是一个涉及身份验证机制和RESTful API设计的复杂过程,需要对两者都有深入的理解。正确配置和使用这些jar文件是成功...
1. **Cas协议**:Cas是由耶鲁大学开发的开源SSO解决方案,它基于HTTP和SOAP协议,通过服务器端的Ticket Granting Ticket(TGT)来实现单点登录。用户首次登录Cas服务器时,会收到一个TGT,然后这个TGT可以在访问其他...
标题中的"cas.rar_site:www.pudn.com"暗示了这是一个在PUDN网站上分享的压缩文件,文件名可能是"CAS"的简写,它是一个与聊天软件相关的项目。这个项目的源代码是用C语言编写的,可能是一个教学或学习资源。 描述中...
1. **CAS服务器配置**:包括服务器端的部署,如修改`cas.properties`文件以配置数据库连接、服务定义、安全策略等。此外,可能还需要自定义登录页面或添加额外的认证模块。 2. **服务注册**:每个需要SSO保护的应用...
2. **CAS(Central Authentication Service)**:如果NCCloud采用了CAS作为SSO解决方案,白屏可能源于CAS服务器与客户端应用之间的通信问题,例如票据验证失败、服务URL配置错误等。 3. **OAuth2**:如果使用OAuth2...
总的来说,Netty 结合 CAS 实现远程登录,提供了一个安全、高效的解决方案,尤其适合需要跨多个平台的大型分布式系统。通过深入了解和实践,开发者可以更好地掌握网络通信和身份验证的核心技术。
它提供了一个服务器端组件,用于处理认证,而客户端应用只需要集成CAS的验证协议。用户通过CAS服务器进行身份验证后,可以在所有与CAS服务器相连接的应用中自由访问。 2. **OAuth2.0 / OpenID Connect**:OAuth2.0...
- 服务提供者:应用系统,需要与CAS服务器交互验证用户身份 - CAS服务器:核心组件,处理所有认证请求和响应 2.4 总体设计思路和处理流程 1. 用户尝试访问服务提供者。 2. 如果用户未登录,服务提供者将请求重定向...
SSO(Single Sign-On)是一种身份验证机制,允许用户通过一次登录即可访问多个相互关联的应用系统,无需在每个系统上分别进行登录操作。在“sso client端1 注销”这个主题中,我们主要探讨的是如何在完全跨域的环境...
SiteMinder认证机制是一种与第三方安全解决方案集成的方式,适用于大型企业级应用。 ##### 9.2 配置 配置SiteMinder认证机制需要与SiteMinder服务器进行交互,设置相应的认证代理和会话管理参数。 #### 九、Run-...
- **前后端分离**:采用VueJS+ElementUI构建前端界面,Spring Cloud搭建后端服务,实现了良好的用户体验和技术分离。 - **数据存储与处理**:使用Oracle或MySQL作为数据存储,Redis作为缓存服务,提高了数据访问效率...
- **应用端缓存**:如Memcached,用于存储热点数据或计算结果,减少对数据库的频繁访问。 - **内存数据库**:如Redis,用于高频读写场景,提供亚毫秒级别的响应速度。 - **Buffer、Cache机制**:在数据库、中间件...
2. **Cookie管理**:在用户成功登录后,我们在服务器端生成一个唯一的Session ID,并将其存储在Cookie中。这个Cookie将在用户每次访问系统时发送到服务器,以便识别用户的身份。 3. **Ticket验证**:当用户尝试访问...