/* * Copyright (c) 2008-2016 Computer Network Information Center (CNIC), Chinese Academy of Sciences. * * This file is part of Duckling project. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package cn.vlabs.duckling.api.umt.sso.configable.servlet; import java.io.File; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import cn.vlabs.commons.principal.UserPrincipalV7; import cn.vlabs.duckling.api.umt.sso.SSOProperties; import cn.vlabs.duckling.api.umt.sso.SessionUtil; import cn.vlabs.duckling.api.umt.sso.configable.msg.Message; import cn.vlabs.duckling.api.umt.sso.configable.msg.Reason; import cn.vlabs.duckling.api.umt.sso.configable.service.ILoginHandle; import cn.vlabs.duckling.common.crypto.KeyFile; import cn.vlabs.duckling.common.crypto.impl.RSAKey; import cn.vlabs.duckling.common.http.WebSite; import cn.vlabs.duckling.common.transmission.PublicKeyEnvelope; import cn.vlabs.duckling.common.transmission.SignedEnvelope; import cn.vlabs.duckling.common.transmission.UserCredentialEnvelopeV7; import cn.vlabs.duckling.common.util.Base64Util; import cn.vlabs.duckling.common.util.ClassUtil; /** * 验证用户是否合法,主要包含解码的逻辑 * @date 2013-02-05 * @author LongYun Lv */ public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1876876234L; private static final Logger LOGGER = Logger.getLogger(LoginServlet.class); /** * 常用变量 * */ private static final String PARAM_WEB_INF = "WEB-INF"; /** * 常用变量 * */ private static final String PARAM_CONF = "conf"; /** * 常用变量 * */ private static final String SERVLET_CONFIG = "config"; /** * 常用变量,签署的证书 * */ public static final String PARAM_SIGNED_CREDENTIAL = "signedCredential"; /** * 公钥存放文件名 * */ private static final String DEFAULT_UMT_KEY_FILE_NAME = "umtpublickey.txt"; /** * 默认公钥下载地址 * */ private static final String DEFAULT_DOWNLOAD_PUBLIC_KEY_URL = "http://localhost/umt/getUMTPublicKey"; /** * 公钥,先下载,后放到本地文件里面 * */ private RSAKey umtKey; /** * 下载公钥,初始化 * */ private void initUmtKey() { if (umtKey == null) { this.downloadUMTKey(); this.loadUMTKeyFromLocal(); } } /** * 获得用户自定义,扩展接口 * */ private ILoginHandle getHandle() { String loginHandClass = SSOProperties.getInstance().getProperty(ILoginHandle.UMT_LOGIN_EXTHANDLE_CLASS,ILoginHandle.DEFAULT_IMPL_PATH); return (ILoginHandle) ClassUtil.classInstance(loginHandClass); } public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { initUmtKey(); ILoginHandle handle = getHandle(); String signedCredential = request.getParameter(PARAM_SIGNED_CREDENTIAL); //下载证书失败 if (umtKey == null){ logError(request, response, handle, new Message(Reason.PUB_KEY_ERROR,"failed:umtpublic key is not found in local app")); return; } //签名文件为空 if (StringUtils.isBlank(signedCredential)) { logError(request, response, handle, new Message(Reason.SIGNED_CREDENTIAL_ERROR,"signedCredential is null!")); return; } signedCredential = Base64Util.decodeBase64(signedCredential); //签名文件错误,解析不出来 if (StringUtils.isBlank(signedCredential)) { logError(request, response, handle, new Message(Reason.SIGNED_CREDENTIAL_ERROR,"signedCredential is invalid!")); return; } SignedEnvelope signedData = SignedEnvelope.valueOf(signedCredential); // 验证签名成功 if (signedData.verify(umtKey)) { UserPrincipalV7 userPrincipal= UserCredentialEnvelopeV7.valueOf(signedData.getContent()).getUser(); SessionUtil.setObject(request, SessionUtil.USER_CONTEXT,userPrincipal); if(handle!=null){ handle.onLoginSuccess(request, response, userPrincipal); } return; } // 验证签名异常 else { logError(request, response, handle, new Message(Reason.PUB_KEY_ERROR,"failed:umtpublickey verify")); return; } } private void logError(HttpServletRequest request, HttpServletResponse response, ILoginHandle handle, Message msg) { handle.onLoginFail(request, response, msg); LOGGER.error(msg); } /** * 初始化配置文件,web.xml配置的配置文件 * */ @Override public void init() throws ServletException { String file = getInitParameter(SERVLET_CONFIG); file = getServletContext().getRealPath(file); SSOProperties.getInstance().initProperties(file, true); } private void downloadUMTKey() { String umtPublicKeyContent = WebSite.getBodyContent(SSOProperties.getInstance().getProperty( ILoginHandle.UMT_PUBLICKEY_URL_KEY, DEFAULT_DOWNLOAD_PUBLIC_KEY_URL)); String umtKeyFile = getUmtFilePath(); try { FileUtils.writeStringToFile(new File(umtKeyFile), umtPublicKeyContent); } catch (IOException e) { LOGGER.error("failed:write umtpublickey to file(" + umtKeyFile + ")", e); } } private void loadUMTKeyFromLocal() { String umtKeyFile = getUmtFilePath(); if (new File(umtKeyFile).exists()) { KeyFile keyFile = new KeyFile(); try { umtKey = keyFile.loadFromPublicKeyContent(PublicKeyEnvelope.valueOf( FileUtils.readFileToString(new File(umtKeyFile))).getPublicKey()); } catch (IOException e) { LOGGER.error(e.getMessage(), e); throw new RuntimeException(e); } } } /** * 获得公钥存放路径,本地的绝对路径 * */ private String getUmtFilePath() { return getServletContext().getRealPath(PARAM_WEB_INF) + File.separator + PARAM_CONF + File.separator + DEFAULT_UMT_KEY_FILE_NAME; } }