900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > SSO单点登录系列1:cas客户端源码分析cas-client-java-2.1.1.jar

SSO单点登录系列1:cas客户端源码分析cas-client-java-2.1.1.jar

时间:2023-10-15 10:23:45

相关推荐

SSO单点登录系列1:cas客户端源码分析cas-client-java-2.1.1.jar

落雨 cas 单点登录

希望能给以后来研究cas的兄弟留下一点思路,也算是研究了两天的成果,外国人的代码写的很晦涩,翻译下来也没有时间继续跟进,所以有错误的还请大家跟帖和我讨论,qq394263788

edu.yale.its.tp.cas.client.filter源码分析:

[java]view plaincopy /*Copyright(c)2000-YaleUniversity.Allrightsreserved.*Seefullnoticeatend.*/packageedu.yale.its.tp.cas.client.filter;importjava.io.*;.*;importjava.util.*;importjavax.servlet.*;importjavax.servlet.http.*;importedu.yale.its.tp.cas.client.*;mons.logging.Log;mons.logging.LogFactory;/***@authorShawnBayern*@authorDrewMazurek*@authorandrew.petro@yale.edu*/publicclassCASFilterimplementsFilter{privatestaticLoglog=LogFactory.getLog(CASFilter.class);//Filterinitializationparameters//必须参数/***loginUrl:指定CAS提供登录页面的URL*/publicfinalstaticStringLOGIN_INIT_PARAM="edu.yale.its.tp.cas.client.filter.loginUrl";/***validateUrl:指定CAS提供serviceticket或proxyticket验证服务的URL*/publicfinalstaticStringVALIDATE_INIT_PARAM="edu.yale.its.tp.cas.client.filter.validateUrl";/***serviceUrl:本web项目的URL,该参数指定过后将覆盖serverName参数,成为登录成功过后重定向的目的地址*/publicfinalstaticStringSERVICE_INIT_PARAM="edu.yale.its.tp.cas.client.filter.serviceUrl";/***serverName:全主机端口号,指定客户端的域名和端口,是指客户端应用所在机器而不是CASServer所在机器,该参数或serviceUrl至少有一个必须指定*/publicfinalstaticStringSERVERNAME_INIT_PARAM="edu.yale.its.tp.cas.client.filter.serverName";//可选参数/***renew:如果指定为true,那么受保护的资源每次被访问时均要求用户重新进行验证,而不管之前是否已经通过*/publicfinalstaticStringRENEW_INIT_PARAM="edu.yale.its.tp.cas.client.filter.renew";/***authorizedProxy:用于允许当前应用从代理处获取proxytickets,该参数接受以空格分隔开的多个proxyURLs,但实际使用只需要一个成功即可。当指定该参数过后,需要修改validateUrl到proxyValidate,*/publicfinalstaticStringAUTHORIZED_PROXY_INIT_PARAM="edu.yale.its.tp.cas.client.filter.authorizedProxy";/***proxyCallbackUrl:用于当前应用需要作为其他服务的代理(proxy)时获取ProxyGrantingTicket的地址*/publicfinalstaticStringPROXY_CALLBACK_INIT_PARAM="edu.yale.its.tp.cas.client.filter.proxyCallbackUrl";/***wrapRequest:如果指定为true,那么CASFilter将重新包装HttpRequest,并且使getRemoteUser()方法返回当前登录用户的用户名*/publicfinalstaticStringWRAP_REQUESTS_INIT_PARAM="edu.yale.its.tp.cas.client.filter.wrapRequest";/***gateway:这个参数很奇葩,一开始没读懂是干嘛的。。官方解释是一旦发生过CAS重定向,过滤器将不会自动重新设置登录的用户。然后你可以提供一个明确的CAS登录链接(HTTPS://CAS服务器/CAS/登录?服务=HTTP://应用程序)或建立映射到不同的路径的过滤器的两个实例。一个实例将gateway实现。当你需要登录的用户,直接转到其他过滤器。*是的你没有想错,这一句话着实让人不知道是要说明什么,于是万能的百度上有且仅有一个前辈说出来了这个参数其实是和renew互斥的,renew就是说无论如何都得重新验证此用户,不管你session中有没有上下文信息。而gateway则是只要检测到session中有sso上下文,就不再重新认证*/publicfinalstaticStringGATEWAY_INIT_PARAM="edu.yale.its.tp.cas.client.filter.gateway";publicfinalstaticStringCAS_FILTER_USER="edu.yale.its.tp.cas.client.filter.user";publicfinalstaticStringCAS_FILTER_RECEIPT="edu.yale.its.tp.cas.client.filter.receipt";privatestaticfinalStringCAS_FILTER_GATEWAYED="edu.yale.its.tp.cas.client.filter.didGateway";//*********************************************************************//ConfigurationstateprivateStringcasLogin;privateStringcasValidate;privateStringcasServiceUrl;privateStringcasServerName;privateStringcasProxyCallbackUrl;privatebooleancasRenew;privatebooleanwrapRequest;privatebooleancasGateway=false;/***对proxyticketreceptorURL授权代理在过滤器的路径的服务列表*/privateListauthorizedProxies=newArrayList();//*********************************************************************//Initializationpublicvoidinit(FilterConfigconfig)throwsServletException{//拿到参数casLogin=config.getInitParameter(LOGIN_INIT_PARAM);casValidate=config.getInitParameter(VALIDATE_INIT_PARAM);casServiceUrl=config.getInitParameter(SERVICE_INIT_PARAM);StringcasAuthorizedProxy=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()){//这俩参数不能一起设置为truethrownewServletException("gatewayandrenewcannotbothbetrueinfilterconfiguration");}if(casServerName!=null&&casServiceUrl!=null){//这俩参数也不能一起设置thrownewServletException("serverNameandserviceUrlcannotbothbeset:chooseone.");}if(casServerName==null&&casServiceUrl==null){//这俩参数也不能一起为nullthrownewServletException("oneofserverNameorserviceUrlmustbeset.");}if(casServiceUrl!=null){//检测uri前缀if(!(casServiceUrl.startsWith("https://")||(casServiceUrl.startsWith("http://")))){thrownewServletException("serviceURLmuststartwithhttp://orhttps://;itscurrentvalueis["+casServiceUrl+"]");}}if(casValidate==null){//cas验证用户的网址不能为空thrownewServletException("validateUrlparametermustbeset.");}if(!casValidate.startsWith("https://")){//如果cas认证网址不是以https开头,就报错。。如果你是用http请求,可以屏蔽掉这个判断语句thrownewServletException("validateUrlmuststartwithhttps://,itscurrentvalueis["+casValidate+"]");}//代理是否为空if(casAuthorizedProxy!=null){//parseandrememberauthorizedproxiesStringTokenizercasProxies=newStringTokenizer(casAuthorizedProxy);while(casProxies.hasMoreTokens()){//授权的标记StringanAuthorizedProxy=casProxies.nextToken();//https前缀检测if(!anAuthorizedProxy.startsWith("https://")){thrownewServletException("CASFilterinitializationparameterforauthorizedproxies"+"mustbeawhitespacedelimitedlistofauthorizedproxies."+"Authorizedproxiesmustbesecure(https)addresses.Thisonewasn't:["+anAuthorizedProxy+"]");}//将所有授权的代理添加到list中(唉,着实不知道是干什么的,也许几年后回来读读应该能知道答案,4月22日14:56:37)this.authorizedProxies.add(anAuthorizedProxy);}}if(log.isDebugEnabled()){log.debug(("CASFilterinitializedas:["+toString()+"]"));}}//*********************************************************************//Filterprocessing//过滤器处理publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainfc)throwsServletException,IOException{//核心思想:首先检查session中有无凭证receipt,如果有,那么就要去下个过滤器链进行处理,如果无,则获取传参ticket,如果有ticket,就经过getAuthenticatedUser()方法去拿到receipt凭证,如果无(这中间会有一些对renew或者gateway的处理),就立即进入cas服务端进行登录if(log.isTraceEnabled()){log.trace("enteringdoFilter()");}//makesurewe'vegotanHTTPrequestif(!(requestinstanceofHttpServletRequest)||!(responseinstanceofHttpServletResponse)){log.error("doFilter()calledonarequestorresponsethatwasnotanHttpServletRequestorresponse.");thrownewServletException("CASFilterprotectsonlyHTTPresources");}//Isthisarequestfortheproxycallbacklistener?Ifso,pass//itthroughif(casProxyCallbackUrl!=null&&casProxyCallbackUrl.endsWith(((HttpServletRequest)request).getRequestURI())&&request.getParameter("pgtId")!=null&&request.getParameter("pgtIou")!=null){log.trace("passingthroughwhatwehopeisCAS'srequestforproxyticketreceptor.");fc.doFilter(request,response);return;}//Wraptherequestifdesiredif(wrapRequest){log.trace("WrappingrequestwithCASFilterRequestWrapper.");request=newCASFilterRequestWrapper((HttpServletRequest)request);}//1.从当前web应用中拿到sessionHttpSessionsession=((HttpServletRequest)request).getSession();//ifourattribute'salreadypresentandvalid,passthroughthefilterchain//1.1.如果存在一个票据(令牌,凭证),就要跳到下一个过滤器链(去验证此票据的真实性,因为此票据的真实性是未知的)CASReceiptreceipt=(CASReceipt)session.getAttribute(CAS_FILTER_RECEIPT);if(receipt!=null&&isReceiptAcceptable(receipt)){log.trace("CAS_FILTER_RECEIPTattributewaspresentandacceptable-passingrequestthroughfilter..");fc.doFilter(request,response);return;}//otherwise,weneedtoauthenticateviaCAS//1.2.如果receipt(令牌)不存在就先拿到ticket,我们要去cas验证用户进行登录Stringticket=request.getParameter("ticket");//noticket?abortrequestprocessingandredirect//如果ticket为空if(ticket==null||ticket.equals("")){log.trace("CASticketwasnotpresentonrequest.");//4.1判断是否经过网关参数(didGateway这个参数否已经经过网关的一个标记参数,表示不再进行认证)//didwegothroughthegatewayalready?booleandidGateway=Boolean.valueOf((String)session.getAttribute(CAS_FILTER_GATEWAYED)).booleanValue();//4.1.1没有casLogin的配置信息下的异常处理if(casLogin==null){//TODO:casLoginshouldprobablybeensuredtonotbenullatfilterinitialization.-awp9log.fatal("casLoginwasnotset,sofiltercannotredirectrequestforauthentication.");thrownewServletException("WhenCASFilterprotectspagesthatdonotreceivea'ticket'"+"parameter,itneedsaedu.yale.its.tp.cas.client.filter.loginUrl"+"filterparameter");}//4.2如果网关标记为false,设置CAS_FILTER_GATEWAYED属性为true,并跳转到cas服务端进行验证if(!didGateway){log.trace("Didnotpreviouslygateway.Settingsessionattributetotrue.");session.setAttribute(CAS_FILTER_GATEWAYED,"true");redirectToCAS((HttpServletRequest)request,(HttpServletResponse)response);//abortchainreturn;}else{log.trace("Previouslygatewayed.");//4.3如果有网关参数(之前已经通过了网关),就不再进行验证,从而进入下一个过滤器处理即可。//ifweshouldbeloggedin,makesurevalidationsucceededif(casGateway||session.getAttribute(CAS_FILTER_USER)!=null){//已经通过了验证和授权。。log.trace("casGatewaywastrueandCAS_FILTER_USERset:passingrequestalongfilterchain.");//continueprocessingtherequest交给下一个过滤器fc.doFilter(request,response);return;}else{//其他情况下,跳往cas服务端//unknownstate...redirecttoCAS//将经过网关的参数didGateway设置为truesession.setAttribute(CAS_FILTER_GATEWAYED,"true");redirectToCAS((HttpServletRequest)request,(HttpServletResponse)response);//abortchainreturn;}}}try{//ticket存在,就经过getAuthenticatedUser()方法去拿到receipt,初步判断此方法是为根据request中的ticket参数组装了一个数据发送给了cas服务端进行判断此ticket是否是正确的合法的(它可能是使用代理类进行的实现)receipt=getAuthenticatedUser((HttpServletRequest)request);}catch(CASAuthenticationExceptione){log.error(e);thrownewServletException(e);}if(!isReceiptAcceptable(receipt)){//检测授权不被认可,就是非法的。thrownewServletException("Authenticationwastechnicallysuccessfulbutrejectedasamatterofpolicy.["+receipt+"]");}//既然拿到了凭证,就去拿到session中是否有相关信息,并写入CASFilter.CAS_FILTER_RECEIPT//Storetheauthenticateduserinthesessionif(session!=null){//probablyunnecessary//将username(用户名)信息放入session中session.setAttribute(CAS_FILTER_USER,receipt.getUserName());//放入票据session.setAttribute(CASFilter.CAS_FILTER_RECEIPT,receipt);//don'tstoreextraunnecessarysessionstate//不要储存额外的不必要的会话状态session.removeAttribute(CAS_FILTER_GATEWAYED);}if(log.isTraceEnabled()){log.trace("validatedtickettogetauthenticatedreceipt["+receipt+"],nowpassingrequestalongfilterchain.");}//continueprocessingtherequest//进入下一个过滤器进行处理fc.doFilter(request,response);log.trace("returningfromdoFilter()");}/***Isthisreceiptacceptableasevidenceofauthenticationbycredentialsthatwouldhavebeenacceptabletothispath?Currentimplementationcheckswhetherfromrenewandwhetherproxywasauthorized.**@paramreceipt票据*@returntrueifacceptable,falseotherwise*/privatebooleanisReceiptAcceptable(CASReceiptreceipt){if(receipt==null)thrownewIllegalArgumentException("Cannotevaluateanullreceipt.");if(this.casRenew&&!receipt.isPrimaryAuthentication()){returnfalse;}if(receipt.isProxied()){if(!this.authorizedProxies.contains(receipt.getProxyingService())){returnfalse;}}returntrue;}//*********************************************************************//Utilitymethods/***ConvertsaticketparametertoaCASReceipt,takingintoaccountanoptionallyconfiguredtrustedproxyinthetierimmediatelyinfrontofus.**@throwsServletException-*whenunabletogetserviceforrequest*@throwsCASAuthenticationException-*onauthenticationfailure*/privateCASReceiptgetAuthenticatedUser(HttpServletRequestrequest)throwsServletException,CASAuthenticationException{log.trace("enteringgetAuthenticatedUser()");ProxyTicketValidatorpv=null;pv=newProxyTicketValidator();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("abouttovalidateProxyTicketValidator:["+pv+"]");}returnCASReceipt.getReceipt(pv);}/***Returnseithertheconfiguredserviceorfiguresitoutforthecurrentrequest.ThereturnedserviceisURL-encoded.*/privateStringgetService(HttpServletRequestrequest)throwsServletException{log.trace("enteringgetService()");StringserviceString;//ensurewehaveaservernameorservicenameif(casServerName==null&&casServiceUrl==null)thrownewServletException("needoneofthefollowingconfiguration"+"parameters:edu.yale.its.tp.cas.client.filter.serviceUrlor"+"edu.yale.its.tp.cas.client.filter.serverName");//usethegivenstringifit'sprovidedif(casServiceUrl!=null)serviceString=URLEncoder.encode(casServiceUrl);else//otherwise,returnourbestguessattheserviceserviceString=Util.getService(request,casServerName);if(log.isTraceEnabled()){log.trace("returningfromgetService()withservice["+serviceString+"]");}returnserviceString;}/***RedirectstheusertoCAS,determiningtheservicefromtherequest.*/privatevoidredirectToCAS(HttpServletRequestrequest,HttpServletResponseresponse)throwsIOException,ServletException{if(log.isTraceEnabled()){log.trace("enteringredirectToCAS()");}StringcasLoginString=casLogin+"?service="+getService((HttpServletRequest)request)+((casRenew)?"&renew=true":"")+(casGateway?"&gateway=true":"");if(log.isDebugEnabled()){log.debug("Redirectingbrowserto["+casLoginString+")");}((HttpServletResponse)response).sendRedirect(casLoginString);if(log.isTraceEnabled()){log.trace("returningfromredirectToCAS()");}}publicStringtoString(){StringBuffersb=newStringBuffer();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!!!");}returnsb.toString();}/*(non-Javadoc)*@seejavax.servlet.Filter#destroy()*/publicvoiddestroy(){//TODOAuto-generatedmethodstub}}

注释都已经写在代码块里了

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。