说明:因为当在浏览器的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();
}
}
}