CAS应用端异常解决
说明:因为当在浏览器的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();
??????? }
??? }
???
}