package com.github.ebnew.ki4so.client.web.filters;
import com.github.ebnew.ki4so.app.custom.AppClientLoginHandler;
import com.github.ebnew.ki4so.client.handler.KnightAppClientLoginHandler;
import com.github.ebnew.ki4so.client.key.DefaultKeyServiceImpl;
import com.github.ebnew.ki4so.client.session.SessionStorage;
import com.github.ebnew.ki4so.common.utils.StringUtils;
import com.github.ebnew.ki4so.core.authentication.KnightEncryCredential;
import com.github.ebnew.ki4so.core.authentication.KnightEncryCredentialManagerImpl;
import com.github.ebnew.ki4so.core.key.KnightKey;
import com.github.ebnew.ki4so.core.key.KnightKeyService;
import com.github.ebnew.ki4so.core.model.KnightCredentialInfo;
import com.github.ebnew.ki4so.web.utils.WebConstants;
import org.apache.log4j.Logger;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* knight客户端应用的过滤器,从而实现集成knight单点登录系统
* @author zhenglu
* @since 15/4/30
*/
public class KnightClientFilter extends BaseClientFilter {
private static Logger logger = Logger.getLogger(KnightClientFilter.class);
//在客户端的session中的用户信息,避免频繁认证,提高性能
public static final String USER_STATE_IN_SESSION_KEY = "knight_client_user_info_session_key";
//将服务器登出地址设置到request属性中
public static final String KNIGHT_SERVER_LOGOUT_URL = "knight_server_logout_url";
// 登录服务器url地址
protected String knightServerLoginUrl = knightServerHost +"login.do";
//获取应用密钥信息的url地址
protected String knightServerFetchKeyUrl = knightServerHost + "fetchKey.do";
//退出服务器url地址
protected String knightServerLogoutUrl = knightServerHost + "logout.do";
//本应用服务器上的应用id
protected String knightClientAppId = "1001";
//本应用对应的加密key
protected KnightKey knightKey;
//密钥获取服务类
protected KnightKeyService keyService;
//凭据管理器
protected KnightEncryCredentialManagerImpl encryCredentialManager;
//登录本应用的处理器
protected KnightAppClientLoginHandler appClientLoginHandler;
/**
* 登录本应用处理器类,由此类进行构造一个对象。
*/
protected String appClientLoginHandlerClass = "com.github.ebnew.ki4so.app.custom.AppClientLogoutHandlerImpl";
@Override
protected void doInit(FilterConfig filterConfig) throws ServletException {
knightClientAppId = getInitParamterWithDefaultValue(filterConfig, "knightClientAppId", knightClientAppId);
knightServerLoginUrl = getInitParamterWithDefaultValue(filterConfig, "ki4soServerLoginUrl", knightServerLoginUrl);
knightServerLogoutUrl = getInitParamterWithDefaultValue(filterConfig, "ki4soServerLogoutUrl", knightServerLogoutUrl);
knightServerFetchKeyUrl = getInitParamterWithDefaultValue(filterConfig, "ki4soServerFetchKeyUrl", knightServerFetchKeyUrl);
appClientLoginHandlerClass = getInitParamterWithDefaultValue(filterConfig, "appClientLoginHandlerClass", appClientLoginHandlerClass);
//构造key服务等相关对象。
//构造登录本应用的处理器对象。
if(!StringUtils.isEmpty(appClientLoginHandlerClass)){
try{
this.appClientLoginHandler = (AppClientLoginHandler)Class.forName(appClientLoginHandlerClass).newInstance();
}catch (Exception e) {
// TODO: handle exception
}
}
keyService = new DefaultKeyServiceImpl(knightServerFetchKeyUrl, knightClientAppId);
this.encryCredentialManager = new KnightEncryCredentialManagerImpl();
this.encryCredentialManager.setKeyService(keyService);
logger.info("the ki4so sever is :"+this.knightServerHost+", please check this service is ok.");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
HttpSession session = request.getSession();
request.setAttribute(KNIGHT_SERVER_LOGOUT_URL,knightServerLogoutUrl);
//本地应用未登录
try{
String knight_client_ec = getClientEC(request);
if(StringUtils.isEmpty(knight_client_ec)){
//跳转到knight登录页面
response.sendRedirect(buildRedirectToKnightServer(request));
return;
}
if(knightKey == null){
KnightKey key = keyService.findKeyByAppId(knightClientAppId);
}
//new认证过的加密后的用户凭证
KnightEncryCredential encryCredential = new KnightEncryCredential();
encryCredential.setCredential(knight_client_ec);
KnightCredentialInfo knightCredentialInfo = this.encryCredentialManager.decrypt(encryCredential);
if(knightCredentialInfo != null){
//检查凭据的合法性
boolean valid = this.encryCredentialManager.checkEncryCredentialInfo(knightCredentialInfo);
if(valid){
session.setAttribute(USER_STATE_IN_SESSION_KEY,knightCredentialInfo);
if(appClientLoginHandler != null){
//登录本应用
appClientLoginHandler.loginClient(knightCredentialInfo,request,response);
}
//重新定位到原请求,去除ec参数
String url = request.getRequestURL().toString();
if(!StringUtils.isEmpty(url)){
//如果请求中存在ec参数,则去除这个参数,重定位
if(url.contains(WebConstants.KI4SO_CLIENT_ENCRYPTED_CREDENTIAL_COOKIE_KEY)){
url = url.substring(0,url.indexOf(WebConstants.KI4SO_CLIENT_ENCRYPTED_CREDENTIAL_COOKIE_KEY));
if(url.contains("?")){
url = url.substring(0,url.length() - 1);
}
// 去掉末尾的问好
if(url.endsWith("&")){
url = url.substring(0,url.length() - 1);
}
}
}
SessionStorage.put(knightCredentialInfo.getUserId(),session);
response.sendRedirect(url);
return;
}
}
filterChain.doFilter(request,response);
return;
}catch (Exception e){
logger.error("filter error:: " + e.getMessage());
response.sendRedirect(buildRedirectToKnightServer(request));
return;
}
}
@Override
public void destroy() {
}
protected String buildRedirectToKnightServer(HttpServletRequest request){
StringBuffer buffer = new StringBuffer(this.knightServerLoginUrl);
if(this.knightServerLoginUrl.contains("?")){
buffer.append("&");
}else {
buffer.append("?");
}
buffer.append("service=").append(request.getRequestURL().toString());
return buffer.toString();
}
/**
* 从http中获得cookie认证加密后的凭据
* @param request
* @return
*/
protected String getClientEC(HttpServletRequest request){
String ec = null;
if(request!=null){
ec = request.getParameter(WebConstants.KI4SO_CLIENT_ENCRYPTED_CREDENTIAL_COOKIE_KEY);
}
return ec;
}
}