All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alogic.cas.server.CasHandler Maven / Gradle / Ivy

package com.alogic.cas.server;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Stack;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.ParserConfigurationException;

import com.anysoft.webloader.HttpClientTool;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.alogic.auth.CookieManager;
import com.alogic.auth.Session;
import com.alogic.auth.SessionManager;
import com.alogic.auth.SessionManagerFactory;
import com.alogic.cas.CasConstants;
import com.alogic.xscript.Logiclet;
import com.alogic.xscript.LogicletContext;
import com.alogic.xscript.Script;
import com.alogic.xscript.doc.XsObject;
import com.alogic.xscript.doc.json.JsonObject;
import com.anysoft.util.BaseException;
import com.anysoft.util.Configurable;
import com.anysoft.util.IOTools;
import com.anysoft.util.KeyGen;
import com.anysoft.util.Properties;
import com.anysoft.util.PropertiesConstants;
import com.anysoft.util.Settings;
import com.anysoft.util.XMLConfigurable;
import com.anysoft.util.XmlElementProperties;
import com.anysoft.util.XmlTools;
import com.anysoft.util.resource.ResourceFactory;
import com.anysoft.webloader.ServletConfigProperties;
import com.anysoft.webloader.ServletHandler;
import com.logicbus.backend.Context;
import com.logicbus.backend.bizlog.BizLog;
import com.logicbus.backend.server.http.HttpContext;

/**
 * CAS服务端处理逻辑
 * 
 * @author yyduan
 * @since 1.6.11.60 [20180912 duanyy]
 * 
 * @version 1.6.11.61 [20180913 duanyy] 
* - 部分字符串采用常量表达
* * @version 1.6.12.7 [20181108 duanyy]
* - 增加ip,service等脚本内置变量
* * @version 1.6.12.8 [20181121 duanyy]
* - 优化cas服务端处理
* * @version 1.6.12.9 [20181127 duanyy]
* - 采用HttpClientTool来获取客户端ip
* * @version 1.6.12.35 [20190528]
* - 未登录时的接入可以通过脚本控制
* * @version 1.6.12.36 [20190611 duanyy]
* - 增加bizlog输出
*/ public class CasHandler implements ServletHandler,XMLConfigurable,Configurable,CasConstants{ /** * a logger of slf4j */ protected final static Logger LOG = LoggerFactory.getLogger(CasHandler.class); /** * 缺省配置文件 */ protected static final String DEFAULT = "java:///conf/alogic.cas.server.xml#App"; /** * 退出登录的请求参数名 */ protected String arguLogout = CasConstants.ARGU_LOGOUT_REQUEST; /** * ticket参数名 */ protected String arguTicket = CasConstants.ARGU_TICKET; /** * service参数名 */ protected String arguService = CasConstants.ARGU_SERVICE; /** * 编码 */ protected String encoding = "utf-8"; /** * command的前缀 */ protected String cmdPrefix = "/cas"; /** * 内部跳转URL的参数 */ protected String returnURL = CasConstants.ARGU_RETURNURL; /** * 本服务器的登录地址 */ protected String loginURL = "/login"; /** * 当验证token时执行脚本 */ protected Logiclet onValidate = null; /** * 当注销时执行脚本 */ protected Logiclet onLogout = null; /** * 当登录时执行脚本 */ protected Logiclet onLogin = null; /** * 当未登录时执行脚本 */ protected Logiclet onNoLogin = null; /** * 当缺省时执行脚本 */ protected Logiclet onDefault = null; protected String contentType = "text/xml;charset=utf-8"; protected HttpClientTool httpClientTool = null; public void bizlog(String service,String clientIp,long time,long duration,String url,boolean error,String reason){ BizLog.log(KeyGen.uuid(8,0,15),service,clientIp,error?CODE_ERR:CODE_OK,reason,time,duration,url); } @Override public void configure(Properties props) { cmdPrefix = PropertiesConstants.getString(props, "cmdPrefix",cmdPrefix); returnURL = PropertiesConstants.getString(props,"auth.para.url",returnURL); loginURL = PropertiesConstants.getString(props, "auth.page.login", loginURL); arguTicket = PropertiesConstants.getString(props, "cas.para.ticket", arguTicket); arguService = PropertiesConstants.getString(props, "cas.para.service", arguService); arguLogout = PropertiesConstants.getString(props, "cas.para.logout",arguLogout); encoding = PropertiesConstants.getString(props,"http.encoding",encoding); httpClientTool = Settings.getToolkit(HttpClientTool.class); } @Override public void configure(Element e, Properties p) { Properties props = new XmlElementProperties(e,p); configure(props); Element elem = XmlTools.getFirstElementByPath(e, "on-validate"); if (elem != null){ onValidate = Script.create(elem, props); } elem = XmlTools.getFirstElementByPath(e, "on-logout"); if (elem != null){ onLogout = Script.create(elem, props); } elem = XmlTools.getFirstElementByPath(e, "on-login"); if (elem != null){ onLogin = Script.create(elem, props); } elem = XmlTools.getFirstElementByPath(e, "on-nologin"); if (elem != null){ onNoLogin = Script.create(elem, props); } elem = XmlTools.getFirstElementByPath(e, "on-default"); if (elem != null){ onDefault = Script.create(elem, props); } } @Override public void init(ServletConfig servletConfig) throws ServletException { ServletConfigProperties props = new ServletConfigProperties(servletConfig); String master = PropertiesConstants.getString(props, "cas.server.master", DEFAULT); String secondary = PropertiesConstants.getString(props, "cas.server.secondary", DEFAULT); ResourceFactory rf = Settings.getResourceFactory(); InputStream in = null; try { in = rf.load(master, secondary, null); Document doc = XmlTools.loadFromInputStream(in); if (doc != null){ configure(doc.getDocumentElement(), props); } }catch (Exception ex){ LOG.error("Can not init cas handler with file : " + master); }finally{ IOTools.close(in); } } @Override public void doService(HttpServletRequest httpReq,HttpServletResponse httpResp,String method)throws ServletException, IOException { SessionManager sm = SessionManagerFactory.getDefault(); Session session = sm.getSession(httpReq,httpResp,true); try { String cmd = getCommand(httpReq.getContextPath(),httpReq.getRequestURI()); if (StringUtils.isNotEmpty(cmd)){ if (cmd.startsWith("/logout")){ doLogout(httpReq,httpResp,sm,session); return; } if (cmd.startsWith("/validate")){ doValidate(httpReq,httpResp,sm,session); return; } if (cmd.startsWith("/serviceValidate")){ doValidate(httpReq,httpResp,sm,session); return; } if (cmd.startsWith("/login")){ doLogin(httpReq,httpResp,sm,session); return; } } doDefault(httpReq,httpResp,sm,session); }catch (BaseException ex){ httpClientTool.sendError(httpResp,E404,String.format("%s:%s",ex.getCode(),ex.getMessage())); } } protected void doDefault(HttpServletRequest httpReq, HttpServletResponse httpResp, SessionManager sm, Session session){ String nextUrl = loginURL; if (onDefault != null){ Context ctx = new HttpContext(httpReq,httpResp,encoding); LogicletContext logicletContext = new Context.ServantLogicletContext(ctx); CookieManager cm = new CookieManager.Default(sm, httpReq, httpResp); long start = System.nanoTime(); String clientIp = httpClientTool.getClientIp(httpReq); try { logicletContext.setObject(ID_SESSION, session); logicletContext.setObject(ID_COOKIES, cm) ; logicletContext.SetValue("$service", "/cas/Default"); logicletContext.SetValue("$clientIp",clientIp); logicletContext.SetValue("$nextUrl", nextUrl); XsObject doc = new JsonObject("root",new HashMap()); onDefault.execute(doc,doc, logicletContext, null); nextUrl = PropertiesConstants.getString(logicletContext,"$nextUrl",nextUrl); }finally{ logicletContext.removeObject(ID_SESSION); logicletContext.removeObject(ID_COOKIES); bizlog("/cas/Default",clientIp,System.currentTimeMillis(),System.nanoTime() - start,httpReq.getRequestURL().toString(),false,""); } } try { httpClientTool.sendRedirect(httpResp,nextUrl); } catch (IOException e) { LOG.error(e.getMessage()); } } protected void doLogin(HttpServletRequest httpReq, HttpServletResponse httpResp, SessionManager sm, Session session) { if (!session.isLoggedIn()){ //没有登录,跳转登录页面 String service = getParameter(httpReq,this.arguService,""); if (StringUtils.isEmpty(service)){ //没有找到跳转的service doDefault(httpReq,httpResp,sm,session); return; } String nextUrl = loginURL; try { String returnUrl = httpReq.getRequestURI(); String queryInfo = httpReq.getQueryString(); if (StringUtils.isNotEmpty(queryInfo)){ returnUrl += "?" + queryInfo; } if (nextUrl.indexOf("?") >= 0){ nextUrl += String.format("&%s=%s", this.returnURL,URLEncoder.encode(returnUrl,encoding)); }else{ nextUrl += String.format("?%s=%s", this.returnURL,URLEncoder.encode(returnUrl,encoding)); } }catch (Exception ex){ LOG.error(ex.getMessage()); } if (onNoLogin != null){ Context ctx = new HttpContext(httpReq,httpResp,encoding); LogicletContext logicletContext = new Context.ServantLogicletContext(ctx); CookieManager cm = new CookieManager.Default(sm, httpReq, httpResp); long start = System.nanoTime(); String clientIp = httpClientTool.getClientIp(httpReq); try { logicletContext.setObject(ID_SESSION, session); logicletContext.setObject(ID_COOKIES, cm) ; logicletContext.SetValue(ID_CAS_SERVICE, service); logicletContext.SetValue("$service", "/cas/NoLogin"); logicletContext.SetValue("$nextUrl", nextUrl); logicletContext.SetValue("$clientIp",clientIp); XsObject doc = new JsonObject("root",new HashMap()); onNoLogin.execute(doc,doc, logicletContext, null); nextUrl = PropertiesConstants.getString(logicletContext,"$nextUrl",nextUrl); }finally{ logicletContext.removeObject(ID_SESSION); logicletContext.removeObject(ID_COOKIES); bizlog("/cas/NoLogin",clientIp,System.currentTimeMillis(),System.nanoTime() - start,httpReq.getRequestURL().toString(),false,""); } } try { httpClientTool.sendRedirect(httpResp,nextUrl); }catch (Exception ex){ LOG.error(ex.getMessage()); } }else{ //已经登录 String service = getParameter(httpReq,this.arguService,""); if (StringUtils.isEmpty(service)){ //没有找到跳转的service doDefault(httpReq,httpResp,sm,session); return; } String nextUrl = service; String ticket = session.getId(); if (onLogin != null){ Context ctx = new HttpContext(httpReq,httpResp,encoding); LogicletContext logicletContext = new Context.ServantLogicletContext(ctx); CookieManager cm = new CookieManager.Default(sm, httpReq, httpResp); long start = System.nanoTime(); String clientIp = httpClientTool.getClientIp(httpReq); try { logicletContext.setObject(ID_SESSION, session); logicletContext.setObject(ID_COOKIES, cm) ; logicletContext.SetValue(ID_CAS_TICKET, ticket); logicletContext.SetValue(ID_CAS_SERVICE, service); logicletContext.SetValue("$service", "/cas/Login"); logicletContext.SetValue("$nextUrl", nextUrl); logicletContext.SetValue("$clientIp",clientIp); XsObject doc = new JsonObject("root",new HashMap()); onLogin.execute(doc,doc, logicletContext, null); ticket = PropertiesConstants.getString(logicletContext,ID_CAS_TICKET,ticket); nextUrl = PropertiesConstants.getString(logicletContext,"$nextUrl",nextUrl); }finally{ logicletContext.removeObject(ID_SESSION); logicletContext.removeObject(ID_COOKIES); bizlog("/cas/Login",clientIp,System.currentTimeMillis(),System.nanoTime() - start,httpReq.getRequestURL().toString(),false,""); } } try { if (nextUrl.indexOf("?") >= 0){ nextUrl += String.format("&%s=%s", this.arguTicket,ticket); }else{ nextUrl += String.format("?%s=%s", this.arguTicket,ticket); } httpClientTool.sendRedirect(httpResp,nextUrl); } catch (IOException e) { LOG.error(e.getMessage()); } } } protected void doValidate(HttpServletRequest httpReq,HttpServletResponse httpResp, SessionManager sm, Session session) { if (onValidate == null){ throw new BaseException("core.e1000","onValidate is not defined"); } String service = getParameter(httpReq,this.arguService,""); String ticket = getParameter(httpReq,this.arguTicket,""); Context ctx = new HttpContext(httpReq,httpResp,encoding); LogicletContext logicletContext = new Context.ServantLogicletContext(ctx); CookieManager cm = new CookieManager.Default(sm, httpReq, httpResp); long start = System.nanoTime(); String clientIp = httpClientTool.getClientIp(httpReq); try { logicletContext.setObject(ID_SESSION, session); logicletContext.setObject(ID_COOKIES, cm) ; logicletContext.SetValue(ID_CAS_TICKET, ticket); logicletContext.SetValue(ID_CAS_SERVICE, service); logicletContext.SetValue("$service", "/cas/Validate"); logicletContext.SetValue("$clientIp",clientIp); String idXmlStack = "$xml-stack"; Stack stack = new Stack(); try { Document xmldoc = getInitXmlDocument(); stack.add(xmldoc.getDocumentElement()); logicletContext.setObject(idXmlStack, stack); XsObject doc = new JsonObject("root",new HashMap()); onValidate.execute(doc,doc, logicletContext, null); OutputStream out = null; try { ctx.setResponseContentType(contentType); out = ctx.getOutputStream(); XmlTools.saveToOutputStream(xmldoc, out); out.flush(); } catch (Exception ex) { LOG.error("Error when writing data to outputstream",ex); }finally { IOTools.close(out); } }finally{ stack.pop(); logicletContext.removeObject(idXmlStack); } }finally{ logicletContext.removeObject(ID_SESSION); logicletContext.removeObject(ID_COOKIES); bizlog("/cas/Validate",clientIp,System.currentTimeMillis(),System.nanoTime() - start,httpReq.getRequestURL().toString(),false,""); } } protected static Document getInitXmlDocument(){ try { Document doc = XmlTools.newDocument(); Element root = doc.createElementNS("http://www.yale.edu/tp/cas","cas:serviceResponse"); doc.appendChild(root); return doc; } catch (ParserConfigurationException e) { LOG.error(ExceptionUtils.getStackTrace(e)); return null; } } protected void doLogout(HttpServletRequest httpReq,HttpServletResponse httpResp, SessionManager sm, Session session) { String nextUrl = this.getParameter(httpReq, this.returnURL, this.loginURL); if (onLogout != null){ Context ctx = new HttpContext(httpReq,httpResp,encoding); LogicletContext logicletContext = new Context.ServantLogicletContext(ctx); CookieManager cm = new CookieManager.Default(sm, httpReq, httpResp); long start = System.nanoTime(); String clientIp = httpClientTool.getClientIp(httpReq); try { logicletContext.setObject(ID_SESSION, session); logicletContext.setObject(ID_COOKIES, cm) ; logicletContext.SetValue("$service", "/cas/Logout"); logicletContext.SetValue("$clientIp",clientIp); logicletContext.SetValue("$nextUrl", nextUrl); XsObject doc = new JsonObject("root",new HashMap()); onLogout.execute(doc,doc, logicletContext, null); nextUrl = PropertiesConstants.getString(logicletContext,"$nextUrl",nextUrl); }finally{ logicletContext.removeObject(ID_SESSION); logicletContext.removeObject(ID_COOKIES); bizlog("/cas/Logout",clientIp,System.currentTimeMillis(),System.nanoTime() - start,httpReq.getRequestURL().toString(),false,""); } } try { httpClientTool.sendRedirect(httpResp,nextUrl); } catch (IOException e) { LOG.error(e.getMessage()); } } @Override public void destroy() { } /** * 通过URI计算出当前的command * @param uri URI * @return cmd */ protected String getCommand(String contextPath,String uri){ String prefix = contextPath + this.cmdPrefix; if (uri.startsWith(prefix)){ return uri.substring(prefix.length()); }else{ return ""; } } protected String getParameter(HttpServletRequest request,String id,String dftValue){ String value = request.getParameter(id); return StringUtils.isEmpty(value)?dftValue:value; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy