`
songshu8312
  • 浏览: 18931 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

CAS应用端异常解决

    博客分类:
  • 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();
        }
    }
   
}

分享到:
评论

相关推荐

    cas-client-3.3.3

    "client端"指的是这个包服务于那些需要与CAS服务器进行身份验证交互的客户端应用。 在实际应用中,CAS客户端3.3.3主要涉及以下知识点: 1. **CAS协议**:理解CAS的工作流程,包括服务票(Service Ticket)和代理票...

    cas结合 springmvc shiro 单点登录

    1. **CAS服务端配置**:首先,我们需要搭建CAS服务器,这通常涉及安装CAS服务器软件,配置服务器端的认证逻辑,例如数据库连接以验证用户凭证。 2. **CAS客户端配置**:然后,我们需要在SpringMVC应用中配置CAS...

    CAS Server 4.1二次开发说明文档.docx

    CAS (Central Authentication Service) 是一项由耶鲁大学发起的开源项目,旨在为Web应用系统提供可靠且灵活的单点登录(Single Sign-On, SSO)解决方案。随着业务场景的不断复杂化,官方提供的CAS Server标准功能...

    单点登录CAS.net客户端源码

    CAS(Central Authentication Service)是开源的SSO解决方案,由耶鲁大学开发,广泛应用于教育、企业和组织环境中。本资源“单点登录CAS.net客户端源码”提供了实现CAS协议的.NET客户端源代码,适用于.NET框架的项目...

    cas-client-3.2.1+cas-server-3.4.10

    总结来说,"cas-client-3.2.1+cas-server-3.4.10"是实现网络应用SSO认证的一个解决方案,涉及到了客户端和服务端的配置、安全策略、用户认证流程、单点登出以及系统维护等多个方面。正确配置和使用这个组合,可以极...

    cas-server-3.5.2-release.rar

    综上所述,"cas-server-3.5.2-release" 是一个功能丰富的SSO解决方案,包含了SSO的基本原理、部署配置、安全机制、服务注册等多个方面的重要知识点。对于需要构建和管理统一认证平台的IT专业人士来说,理解和掌握...

    CAS客户端开发说明1

    【CAS客户端开发说明】这篇文档是关于如何进行CAS...总的来说,这个指南详细阐述了建立CAS客户端开发环境、配置、测试以及开发中的关键步骤,为开发者提供了一个清晰的流程,帮助他们理解和实现基于CAS的SSO解决方案。

    cas3.4集成restle所需jar文件

    此外,还需要考虑错误处理和异常情况,以提供健壮的解决方案。 总的来说,Cas 3.4与Restlet的集成是一个涉及身份验证机制和RESTful API设计的复杂过程,需要对两者都有深入的理解。正确配置和使用这些jar文件是成功...

    java单点登录的实现与应用整合中SSO的技术实现.rar

    1. **Cas协议**:Cas是由耶鲁大学开发的开源SSO解决方案,它基于HTTP和SOAP协议,通过服务器端的Ticket Granting Ticket(TGT)来实现单点登录。用户首次登录Cas服务器时,会收到一个TGT,然后这个TGT可以在访问其他...

    cas.rar_site:www.pudn.com

    标题中的"cas.rar_site:www.pudn.com"暗示了这是一个在PUDN网站上分享的压缩文件,文件名可能是"CAS"的简写,它是一个与聊天软件相关的项目。这个项目的源代码是用C语言编写的,可能是一个教学或学习资源。 描述中...

    sso完整demo,可直接运行

    1. **CAS服务器配置**:包括服务器端的部署,如修改`cas.properties`文件以配置数据库连接、服务定义、安全策略等。此外,可能还需要自定义登录页面或添加额外的认证模块。 2. **服务注册**:每个需要SSO保护的应用...

    patch_20210113单点登录跳转主页显示白屏.zip

    2. **CAS(Central Authentication Service)**:如果NCCloud采用了CAS作为SSO解决方案,白屏可能源于CAS服务器与客户端应用之间的通信问题,例如票据验证失败、服务URL配置错误等。 3. **OAuth2**:如果使用OAuth2...

    Netty(集成跨平台远程登录)_nettyCAS登入_netty远程登陆_

    总的来说,Netty 结合 CAS 实现远程登录,提供了一个安全、高效的解决方案,尤其适合需要跨多个平台的大型分布式系统。通过深入了解和实践,开发者可以更好地掌握网络通信和身份验证的核心技术。

    java web sso 实现

    它提供了一个服务器端组件,用于处理认证,而客户端应用只需要集成CAS的验证协议。用户通过CAS服务器进行身份验证后,可以在所有与CAS服务器相连接的应用中自由访问。 2. **OAuth2.0 / OpenID Connect**:OAuth2.0...

    SSO单点登录概要设计说明书[借鉴].pdf

    - 服务提供者:应用系统,需要与CAS服务器交互验证用户身份 - CAS服务器:核心组件,处理所有认证请求和响应 2.4 总体设计思路和处理流程 1. 用户尝试访问服务提供者。 2. 如果用户未登录,服务提供者将请求重定向...

    sso client端1 注销

    SSO(Single Sign-On)是一种身份验证机制,允许用户通过一次登录即可访问多个相互关联的应用系统,无需在每个系统上分别进行登录操作。在“sso client端1 注销”这个主题中,我们主要探讨的是如何在完全跨域的环境...

    springsecurity.pdf

    SiteMinder认证机制是一种与第三方安全解决方案集成的方式,适用于大型企业级应用。 ##### 9.2 配置 配置SiteMinder认证机制需要与SiteMinder服务器进行交互,设置相应的认证代理和会话管理参数。 #### 九、Run-...

    【精品】强智科技-大数据时代智慧校园一体化平台的创新应用.pdf

    - **前后端分离**:采用VueJS+ElementUI构建前端界面,Spring Cloud搭建后端服务,实现了良好的用户体验和技术分离。 - **数据存储与处理**:使用Oracle或MySQL作为数据存储,Redis作为缓存服务,提高了数据访问效率...

    高并发高可用的电商平台架构

    - **应用端缓存**:如Memcached,用于存储热点数据或计算结果,减少对数据库的频繁访问。 - **内存数据库**:如Redis,用于高频读写场景,提供亚毫秒级别的响应速度。 - **Buffer、Cache机制**:在数据库、中间件...

    SSO单点登入,使用cookie实习(Struts2)

    2. **Cookie管理**:在用户成功登录后,我们在服务器端生成一个唯一的Session ID,并将其存储在Cookie中。这个Cookie将在用户每次访问系统时发送到服务器,以便识别用户的身份。 3. **Ticket验证**:当用户尝试访问...

Global site tag (gtag.js) - Google Analytics