/* * 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.umt.ui.servlet; import java.io.IOException; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import net.duckling.cloudy.common.CommonUtils; import net.duckling.falcon.api.cache.ICacheService; import net.duckling.vmt.api.IRestOrgService; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.json.simple.JSONObject; import org.springframework.beans.factory.BeanFactory; import com.octo.captcha.module.servlet.image.SimpleImageCaptchaServlet; import com.octo.captcha.service.CaptchaServiceException; import cn.vlabs.commons.principal.UserPrincipal; import cn.vlabs.umt.common.digest.Md5CryptDigest; import cn.vlabs.umt.common.util.Config; import cn.vlabs.umt.common.util.RequestUtil; import cn.vlabs.umt.domain.OauthLog; import cn.vlabs.umt.oauth.as.issuer.MD5Generator; import cn.vlabs.umt.oauth.as.issuer.OAuthIssuer; import cn.vlabs.umt.oauth.as.issuer.OAuthIssuerImpl; import cn.vlabs.umt.oauth.as.request.OAuthAuthzRequest; import cn.vlabs.umt.oauth.as.response.OAuthASResponse; import cn.vlabs.umt.oauth.common.exception.OAuthProblemException; import cn.vlabs.umt.oauth.common.exception.OAuthSystemException; import cn.vlabs.umt.oauth.common.message.OAuthResponse; import cn.vlabs.umt.services.account.IAccountService; import cn.vlabs.umt.services.account.IOauthLogService; import cn.vlabs.umt.services.session.SessionUtils; import cn.vlabs.umt.services.user.LoginService; import cn.vlabs.umt.services.user.bean.AuthorizationCodeBean; import cn.vlabs.umt.services.user.bean.LoginInfo; import cn.vlabs.umt.services.user.bean.LoginNameInfo; import cn.vlabs.umt.services.user.bean.OAuthAuthzRequestWrap; import cn.vlabs.umt.services.user.bean.OauthClientBean; import cn.vlabs.umt.services.user.bean.OauthCredential; import cn.vlabs.umt.services.user.bean.OauthScopeBean; import cn.vlabs.umt.services.user.bean.OauthToken; import cn.vlabs.umt.services.user.bean.User; import cn.vlabs.umt.services.user.bean.UsernamePasswordCredential; import cn.vlabs.umt.services.user.service.IAuthorizationCodeServer; import cn.vlabs.umt.services.user.service.IOauthClientService; import cn.vlabs.umt.services.user.service.IOauthTokenService; import cn.vlabs.umt.services.user.utils.ServiceFactory; import cn.vlabs.umt.ui.Attributes; import cn.vlabs.umt.ui.UMTContext; import cn.vlabs.umt.ui.servlet.login.LocalLogin; import cn.vlabs.umt.ui.servlet.login.LoginMethod; /** * oauth进入servlet * @author zhonghui * */ public class AuthorizationCodeServlet extends HttpServlet { /** * */ private static final long serialVersionUID = -1523764840219050925L; private static final Logger LOG = Logger.getLogger(AuthorizationCodeServlet.class); private static final String USER_OAUTH_REQUEST="user_oauth_request"; private static long authorTimeout = 5; private IOauthClientService oauthClientServer; private IOauthTokenService oauthTokenServer; private IAuthorizationCodeServer authorizationCodeServer; private ICacheService cacheService; private IOauthLogService oauthLogService; private IRestOrgService orgService; private Config config; private IRestOrgService getOrgService(){ if(orgService==null){ orgService=(IRestOrgService)getBeanFactory().getBean("restOrgService"); } return orgService; } private Config getConfig(){ if(config==null){ config=(Config) getBeanFactory().getBean(Config.BEAN_ID); } return config; } private Set<String> getCompulsionPwdScope(){ Set<String> result=new HashSet<String>(); String pwdScopeStr=this.getConfig().getStringProp("compulsion.pwd.strong.scope", ""); if(StringUtils.isNotBlank(pwdScopeStr)){ result.addAll(Arrays.asList(StringUtils.split(pwdScopeStr, ";"))); } return result; } private IOauthLogService getOauthLogService(){ if(oauthLogService==null){ oauthLogService=(IOauthLogService)getBeanFactory().getBean(IOauthLogService.BEAN_ID); } return oauthLogService; } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { addCrossDomainHeader(response); String pageInfo = request.getParameter("pageinfo"); if(StringUtils.isEmpty(pageInfo)){ authorization(request, response); }else if("userinfo".equals(pageInfo)){ validationUser(request, response,null); }else if("userscope".equals(pageInfo)){ sendAuthorization(request,response,null,null,null); }else if("cancelauthorization".equals(pageInfo)){ cancelAuthorization(request,response); }else if("checkPassword".equals(pageInfo)){ checkPassword(request,response); }else if("checkLogin".equals(pageInfo)){ checkLogin(request,response); }else{ response.setStatus(404); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } /** * 第一步 * 授权请求开始,校验用户Authorization数据格式,处理异常,并控制数据页面 * @param request * @param response * @throws IOException * @throws ServletException */ private void authorization(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException{ String redirectURI = null; try { OAuthAuthzRequest oauthRequest = new OAuthAuthzRequest(request); String clientId = oauthRequest.getClientId(); Set<String> scope = oauthRequest.getScopes(); redirectURI = oauthRequest.getRedirectURI(); if(!validateClient(clientId, redirectURI,request,response)){ return; } OauthClientBean bean = getClientServer().findByClientId(clientId); request.setAttribute("client_name", bean.getClientName()); request.setAttribute("client_website", bean.getClientWebsite()); if(!validateScope(clientId,scope)){ dealAppError("invalid_scope","scope["+scope+"]校验错误", redirectURI, response); return; } request.setAttribute(USER_OAUTH_REQUEST, new OAuthAuthzRequestWrap(oauthRequest,request)); if(userHaveLogin(request,response)){ return; } dealCoremailUserName(request); request.setAttribute("thirdPartyList", bean.getThirdPartyMap()); Map<String,String> siteInfo=new HashMap<String,String>(); siteInfo.put(Attributes.RETURN_URL, URLEncoder.encode(RequestUtil.getFullRequestUrl(request),"UTF-8")); siteInfo.put(Attributes.APP_NAME,"umtOauth2"); SessionUtils.setSessionVar(request, Attributes.SITE_INFO, siteInfo); request.setAttribute("showValidCode", StringUtils.equals(StringUtils.defaultIfEmpty((String)request.getSession().getAttribute("requireValid"), "false"), "true")); forwordUserInfoPage(request, response); } catch (OAuthProblemException ex) { if(StringUtils.isEmpty(redirectURI)){ redirectURI = request.getParameter("redirect_url"); if(StringUtils.isEmpty(redirectURI)){ request.setAttribute("client_id", request.getParameter("client_id")); request.setAttribute("errorCode", ex.getError()); request.setAttribute("errorDescription", ex.getDescription()); dealClientRedirectError(request, response); return; } } OAuthResponse resp = null; try { resp = OAuthASResponse .errorResponse(HttpServletResponse.SC_FOUND).error(ex) .location(redirectURI).buildQueryMessage(); } catch (OAuthSystemException e) { LOG.error("",e); } response.sendRedirect(resp.getLocationUri()); LOG.info("redirect="+redirectURI,ex); } catch (OAuthSystemException e) { LOG.error("",e); dealOAuthSystemError(redirectURI, e,request,response); } } /** * 处理记住用户名 * @param request */ private void dealCoremailUserName(HttpServletRequest request) { Cookie[] cs = request.getCookies(); if(cs!=null){ for(Cookie c : cs){ if("passport.remember.user".equals(c.getName())){ if(StringUtils.isNotEmpty(c.getValue())){ request.setAttribute("userName", c.getValue()); } } } } } /** * 允许IE跨域访问 * @param response */ private void addCrossDomainHeader(HttpServletResponse response){ response.setHeader( "P3P","CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\""); } private void forwordUserInfoPage(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException{ String theme = request.getParameter("theme"); if("full".equals(theme)){ request.getRequestDispatcher("/oauth/login_full.jsp").forward(request, response); }else if("simple".equals(theme)){//验证码 request.getRequestDispatcher("/oauth/login_simple.jsp").forward(request, response); }else if("embed".equals(theme)){ request.getRequestDispatcher("/oauth/login_embed.jsp").forward(request, response); }else if("shibboleth".equals(theme)){ request.getRequestDispatcher("/oauth/login_shibboleth.jsp").forward(request, response); }else if("coremail".equals(theme)){ request.getRequestDispatcher("/oauth/login_coremail.jsp").forward(request, response); }else if("coremail30".equals(theme)){ request.getRequestDispatcher("/oauth/login_coremail30.jsp").forward(request, response); }else if("coremail_mobile".equals(theme)){ request.getRequestDispatcher("/oauth/login_coremail_mobile.jsp").forward(request, response); }else if("coremail_mobile_ipad".equals(theme)){ request.setAttribute("ipadFlag", true); request.getRequestDispatcher("/oauth/login_coremail_mobile.jsp").forward(request, response); }else if("cstnet_wifi".equals(theme)){ request.getRequestDispatcher("/oauth/login_cstnet_wifi.jsp").forward(request, response); }else if("fellowship".equals(theme)){ request.getRequestDispatcher("/oauth/login_fellowship.jsp").forward(request, response); }else if("dchat".equals(theme)){//验证码 request.getRequestDispatcher("/oauth/login_dchat.jsp").forward(request, response); } else if("csp".equals(theme)){ request.getRequestDispatcher("/oauth/login_csp.jsp").forward(request, response); } //add by lvly @20140514 else if("embed_pc".equals(theme)){//验证码 request.getRequestDispatcher("/oauth/login_embed_pc.jsp").forward(request, response); }else if("embed_mobile".equals(theme)){//验证码 request.getRequestDispatcher("/oauth/login_embed_mobile.jsp").forward(request, response); } else{ request.getRequestDispatcher("/oauth/login_full.jsp").forward(request, response); } } /** * 如果用户已经登录直接跳转到权限设置方法 * @param request * @param response * @return * @throws IOException * @throws ServletException */ private boolean userHaveLogin(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { LoginInfo loginInfo = getLoginInfoFromCookieAndSession(request); if(loginInfo.getUser()!=null){ //如果用户已经登录了,会直接到下环节或者跳回页面进行页面自动登录过程 String theme = request.getParameter("theme"); if(!isEmbedPage(theme)){ validationUser(request, response,(OAuthAuthzRequestWrap)request.getAttribute(USER_OAUTH_REQUEST)); return true; }else{ request.setAttribute("login", true); } } return false; } /** * 是否页面使用的是嵌入框 * @param theme * @return */ private boolean isEmbedPage(String theme){ if(StringUtils.isEmpty(theme)){ return false; } return "embed".equals(theme)||theme.startsWith("coremail")||"cstnet_wifi".equals(theme); } /** * 通过session和cookie判断用户是否登录,如果登录就刷新session * @param request * @return */ private LoginInfo getLoginInfoFromCookieAndSession(HttpServletRequest request) { LoginInfo loginInfo = UMTContext.getLoginInfo(request.getSession()); return loginInfo; } private boolean validateScope(String clientId, Set<String> scope) { IOauthClientService server = getClientServer(); OauthClientBean bean = server.findByClientId(clientId); if(bean!=null){ return bean.validateScope(scope); } return false; } /** * 处理并返回异常结果 * @param errorCode 异常类型 * @param redirectURI * @param response * @throws IOException */ private void dealAppError(String errorCode,String desc,String redirectURI,HttpServletResponse response) throws IOException{ OAuthResponse resp = null; try { resp = OAuthASResponse .errorResponse(HttpServletResponse.SC_FOUND) .setError(errorCode) .setErrorDescription(desc) .location(redirectURI) .buildQueryMessage(); } catch (OAuthSystemException e) { LOG.error("", e); } LOG.info("redirectURI="+redirectURI+"发生了errorCode="+errorCode+";description="+desc+";的错误"); response.sendRedirect(resp.getLocationUri()); } /** * 校验客户端传来的参数 * @param clientId * @param secret * @param redirectURI * @return * @throws IOException * @throws ServletException */ private boolean validateClient(String clientId,String redirectURI,HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException{ IOauthClientService server = getClientServer(); OauthClientBean bean = server.findAcceptByClientId(clientId); OauthLog oauthLog=new OauthLog(); oauthLog.setClientId(clientId); oauthLog.setClientName(bean==null?null:bean.getClientName()); oauthLog.setIp(RequestUtil.getRemoteIP(request)); oauthLog.setUserAgent(request.getHeader("User-Agent")); oauthLog.setAction(OauthLog.ACTION_VALIDATE_CLIENT); try{ new URI(redirectURI); }catch(Exception e){ String errorMsg="redirect_uri格式不正确"; oauthLog.setResult(OauthLog.RESULT_REDIRECT_URL_ERROR); oauthLog.setDesc(redirectURI); getOauthLogService().addLog(oauthLog); request.setAttribute("redirect_uri", redirectURI); request.setAttribute("client_id", clientId); request.setAttribute("errorCode", "invalid_request"); request.setAttribute("errorDescription", errorMsg); dealClientRedirectError(request, response); return false; } if(bean==null||!bean.getClientId().equals(clientId)){ oauthLog.setResult(OauthLog.RESULT_CLIENT_ID_ERROR); getOauthLogService().addLog(oauthLog); dealAppError("unauthorized_client","client_id["+clientId+"]未获取授权" ,redirectURI, response); return false; } if(!bean.getRedirectURI().equals(redirectURI)){ oauthLog.setResult(OauthLog.RESULT_REDIRECT_URL_MISMATCH); oauthLog.setAssertDesc(bean.getRedirectURI(), redirectURI); getOauthLogService().addLog(oauthLog); request.setAttribute("redirect_uri", redirectURI); request.setAttribute("client_id", clientId); request.setAttribute("errorCode", "invalid_request"); request.setAttribute("errorDescription", "redirect_url_mismatch"); dealClientRedirectError(request, response); return false; } oauthLog.setResult(OauthLog.RESULT_SUCCESS); getOauthLogService().addLog(oauthLog); return true; } /** * 第二步<br/> * 授权请求处理,认证用户信息 * @param request * @param response * @throws ServletException * @throws IOException */ private void validationUser(HttpServletRequest request,HttpServletResponse response,OAuthAuthzRequestWrap oauthRequest) throws ServletException, IOException{ if(oauthRequest==null){ oauthRequest = new OAuthAuthzRequestWrap(request); } OauthClientBean bean = getClientServer().findByClientId(oauthRequest.getClientId()); UserPrincipal info = getLoginInfo(request,getClientServer().findByClientId(oauthRequest.getClientId())); String clientId=bean==null?null:bean.getClientId(); OauthLog log=new OauthLog(); log.setAction(OauthLog.ACTION_VALIDATE_USERINFO); log.setClientId(clientId); log.setClientName(bean==null?null:bean.getClientName()); log.setUserAgent(request.getHeader("User-Agent")); log.setIp(RequestUtil.getRemoteIP(request)); String username=request.getParameter("userName"); String password=request.getParameter("password"); LoginInfo loginInfo=null; if(info==null){ LoginService ls=ServiceFactory.getLoginService(request); loginInfo=ls.loginAndReturnPasswordType(new OauthCredential(clientId, username, password)); info=loginInfo.getUserPrincipal(); } if(info==null){ log.setResult(OauthLog.RESULT_VALIDATE_USER_ERROR); log.setDesc("{\"username\":\""+username+"\",\"password\":\"****\"}"); getOauthLogService().addLog(log); request.setAttribute("userName", username); request.setAttribute("password", password); if(StringUtils.isEmpty(request.getParameter("userName"))){ request.setAttribute("userNameNull", true); }else if(StringUtils.isEmpty(request.getParameter("password"))){ request.setAttribute("passwordNull", true); }else{ request.setAttribute("loginerror", true); } if(!validateClient(oauthRequest.getClientId(), oauthRequest.getRedirectURI(),request,response)){ return; } request.setAttribute("client_name", bean.getClientName()); request.setAttribute("client_website", bean.getClientWebsite()); request.setAttribute(USER_OAUTH_REQUEST, oauthRequest); forwordUserInfoPage(request, response); }else{ request.setAttribute(USER_OAUTH_REQUEST, oauthRequest); request.setAttribute("client_id", oauthRequest.getClientId()); doCoremailRequest(request,response); loginInfo =loginInfo==null? UMTContext.getLoginInfo(request.getSession()):loginInfo; log.setResult(OauthLog.RESULT_SUCCESS); log.setUid(loginInfo.getUser().getId()); log.setCstnetId(loginInfo.getUser().getCstnetId()); log.setDesc(loginInfo.getPasswordType()); getOauthLogService().addLog(log); if(StringUtils.isNotEmpty(request.getParameter("remember"))){ LoginMethod.generateSsoCookie(response, request, loginInfo); } LoginMethod.generateAutoFill(response,request,loginInfo); sendAuthorization(request, response, oauthRequest,bean,loginInfo); /*下列几行代码, 是正规流程,但是鉴于开发成本,先不走,按用户全部同意算* Set<String> s =getClientServer().findByClientId(oauthRequest.getClientId()).getScopeSet(); //如果client没有scope就直接返回,这里先不提示用户操作 if(s==null||s.isEmpty()){ return; } //request.setAttribute("scopes", dealScope(oauthRequest.getClientId(), oauthRequest.getScopes())); //request.getRequestDispatcher("/oauth/userscopeinfo.jsp").forward(request, response); * */ } } private void doCoremailRequest(HttpServletRequest request,HttpServletResponse response) { String theme = request.getParameter("themeinfo"); if(StringUtils.isNotEmpty(theme)&&theme.startsWith("coremail")){ if(StringUtils.isNotEmpty(request.getParameter("rememberUserName"))){ String userName = request.getParameter("userName"); if(StringUtils.isNotEmpty(userName)){ Cookie cookie = new Cookie("passport.remember.user",userName); cookie.setPath("/"); cookie.setMaxAge(14*60 * 60 * 24); response.addCookie(cookie); } }else{ //清除cookie Cookie cookie = new Cookie("passport.remember.user",""); cookie.setPath("/"); cookie.setMaxAge(1); response.addCookie(cookie); } if(StringUtils.isNotEmpty(request.getParameter("secureLogon"))){ request.getSession().setAttribute("coremailSecureLogon", true); } } } private String validateUP(String userName,String password,LoginService ls,String clientId){ LoginInfo info = ls.loginAndReturnPasswordType(new UsernamePasswordCredential(userName,password)); String result="true"; if(info.getUser()==null){ LoginInfo oauthInfo=ls.loginAndReturnPasswordType(new OauthCredential(clientId,userName,password)); if(oauthInfo.getUser()==null){ result= info.getValidateResult(); }else{ result=oauthInfo.getValidateResult(); } } return result; } private void checkPassword(HttpServletRequest request, HttpServletResponse response) { boolean validateCodeResult=validateCode(request, response); if(!validateCodeResult){ return; } String userName = request.getParameter("userName"); String password = request.getParameter("password"); String clientId=request.getParameter("clientId"); String result="true"; OauthLog log=new OauthLog(); log.setAction(OauthLog.ACTION_CHECK_PASSWORD); log.setClientId(clientId); log.setClientName(request.getParameter("clientName")); log.setCstnetId(userName); log.setIp(RequestUtil.getRemoteIP(request)); log.setUserAgent(request.getHeader("User-Agent")); if(StringUtils.isNotEmpty(userName)&&StringUtils.isNotEmpty(password)){ LoginService ls=ServiceFactory.getLoginService(request); result=validateUP(userName,password,ls,clientId); }else{ result="false"; } JSONObject obj = new JSONObject(); if(!"true".equals(result)){ log.setResult(OauthLog.RESULT_VALIDATE_USER_ERROR); log.setDesc("{\"username\":\""+userName+"\",\"password\":\"****\"}"); getOauthLogService().addLog(log); int counts =Integer.parseInt(StringUtils.defaultIfEmpty((String)(request.getSession().getAttribute("_wrongInputCountKey")), "0")); request.getSession().setAttribute("_wrongInputCountKey", (++counts)+""); if(counts>4){ obj.put("showValidCode", true); obj.put("lastErrorValidCode", ""); request.getSession().setAttribute("requireValid", "true"); } } obj.put("status", result); writeJSONResponse(response, obj); } private boolean validateCode(HttpServletRequest request, HttpServletResponse response) { HttpSession session =request.getSession(); String requireValid = (String)session.getAttribute("requireValid"); if (requireValid != null) { String validCode = request.getParameter("ValidCode"); boolean validWrong=true; try{ validWrong=SimpleImageCaptchaServlet.validateResponse(request,validCode ); }catch(CaptchaServiceException e){ } if (!validWrong) { JSONObject validJSON = new JSONObject(); validJSON.put("WrongValidCode", true); validJSON.put("showValidCode", true); if(!CommonUtils.isNull(validCode)){ validJSON.put("lastErrorValidCode", "error"); }else{ validJSON.put("lastErrorValidCode", "required"); } validJSON.put("status", "validCode.error"); writeJSONResponse(response, validJSON); return false; } } return true; } public void writeJSONResponse(HttpServletResponse response, JSONObject obj) { PrintWriter writer = null; try { //为了兼容IE系浏览器,特意设置成text/html格式 response.setContentType("text/html"); writer = response.getWriter(); writer.write(obj.toString()); } catch (IOException e) { LOG.error("JSONHelper write json object IOException:"+e.getMessage()); LOG.debug(e.getStackTrace()); }finally { if (writer!=null){ writer.flush(); writer.close(); } } } /** * 第三步 * 处理用户的scope数据,并返回授权结果 * @param request * @param response * @param bean * @throws IOException * @throws ServletException */ private void sendAuthorization(HttpServletRequest request, HttpServletResponse response,OAuthAuthzRequestWrap oauthRequest, OauthClientBean bean,LoginInfo loginInfo) throws IOException, ServletException { if(oauthRequest==null){ oauthRequest = new OAuthAuthzRequestWrap(request); } String responseType = oauthRequest.getResponseType(); if("code".equals(responseType)){ responseTypeIsCode(request, response, oauthRequest,bean,loginInfo); } //较为危险,不使用 // else if("token".equals(responseType)){ // responseTypeIsToken(request, response, oauthRequest); // } else{ dealAppError("unsupported_response_type","response_type["+ responseType+"]请求的响应类型授权服务器不支持", oauthRequest.getRedirectURI(), response); } cleanSession(request); } private String getEncPassword(HttpServletRequest request,OauthClientBean bean){ if(bean==null){ return null; } if(OauthClientBean.PWD_TYPE_NONE.equals(bean.getPwdType())){ return null; } String password=request.getParameter("password"); String encedPassword=null; if(OauthClientBean.PWD_TYPE_SHA.equals(bean.getPwdType())){ encedPassword=DigestUtils.shaHex(password); }else if(OauthClientBean.PWD_TYPE_MD5.equals(bean.getPwdType())){ encedPassword=DigestUtils.md5Hex(password); }else{ //Crypt加密使用MD5算法,返回MD5Crypt加密后的密码,和MD5加密后的“用户名+产品名+密码”作为digest,模拟PHP里面的crypt()方法 encedPassword=Md5CryptDigest.md5Crpt(password); encedPassword+="_"+DigestUtils.md5Hex(request.getParameter("userName")+":"+ServiceFactory.getConfig(request).getStringProp("dcloud.calendar.product.name", "calendar")+":"+password); } return encedPassword; } private void cleanSession(HttpServletRequest request) { HttpSession session = request.getSession(); session.removeAttribute("coremailSecureLogon"); } /** * 处理responseType为token类型 * @param request * @param response * @param oauthRequest * @throws IOException * @throws ServletException */ private void responseTypeIsToken(HttpServletRequest request, HttpServletResponse response, OAuthAuthzRequestWrap oauthRequest) throws IOException, ServletException { String[] scopes = request.getParameterValues("userScopes"); String redirectURI = oauthRequest.getRedirectURI(); try { OauthClientBean bean=getClientServer().findByClientId(oauthRequest.getClientId()); OauthLog oauthLog=new OauthLog(); oauthLog.setClientId(bean.getClientId()); oauthLog.setClientName(bean.getClientName()); oauthLog.setIp(RequestUtil.getRemoteIP(request)); oauthLog.setUserAgent(request.getHeader("User-Agent")); oauthLog.setAction(OauthLog.ACTION_VALIDATE_USERINFO_TOKEN); oauthLog.setResult(OauthLog.RESULT_SUCCESS); User user = ServiceFactory.getUserService(request).getUserByLoginName(getLoginInfo(request,bean).getName()); oauthLog.setUid(user.getId()); oauthLog.setCstnetId(user.getCstnetId()); getOauthLogService().addLog(oauthLog); OauthToken token = OauthTokenServlet.createToken(oauthRequest.getClientId(), redirectURI, request, tansferScope(scopes), user.getId()+"", "token--已废弃不用"); StringBuilder sb = new StringBuilder(); addTokenParam(sb,token,request,oauthRequest.getState(),bean); if(redirectURI.contains("#")){ if(redirectURI.endsWith("#")){ redirectURI=redirectURI+sb.toString(); }else{ redirectURI=redirectURI+"&"+sb.toString(); } }else{ redirectURI=redirectURI+"#"+sb.toString(); } getTokenServer().save(token); response.sendRedirect(redirectURI); } catch (OAuthSystemException e) { dealOAuthSystemError(redirectURI, e,request, response); } } private void addTokenParam(StringBuilder sb, OauthToken token,HttpServletRequest request,String state,OauthClientBean bean) { User user = ServiceFactory.getUserService(request).getUserByUid(Integer.parseInt(token.getUid())); LoginNameInfo loginInfo = ServiceFactory.getLoginNameService(request).getALoginNameInfo(user.getId(), user.getCstnetId()); LoginInfo userLogin = UMTContext.getLoginInfo(request.getSession()); String userInfo = OauthTokenServlet.getUserAsJSON(loginInfo, user,userLogin.getPasswordType(),null,bean.isNeedOrgInfo(),getOrgService()); sb.append("access_token=").append(encodeURL(token.getAccessToken())); sb.append("&"); sb.append("expires_in=").append(encodeURL(getExpired(token.getAccessExpired())+"")); if(StringUtils.isNotEmpty(state)){ sb.append("&").append("state=").append(encodeURL(state)); } sb.append("&").append("userInfo=").append(encodeURL(userInfo)); } private long getExpired(Date date){ long re = date.getTime()-System.currentTimeMillis(); return (re/1000); } private String encodeURL(String url){ try { return URLEncoder.encode(url, "utf-8"); } catch (UnsupportedEncodingException e) { return url; } } /** * 处理responseType为code类型 * @param request * @param response * @param oauthRequest * @throws IOException * @throws ServletException */ private void responseTypeIsCode(HttpServletRequest request, HttpServletResponse response, OAuthAuthzRequestWrap oauthRequest,OauthClientBean clientBean,LoginInfo loginInfo) throws IOException, ServletException { String[] scopses = request.getParameterValues("userScopes"); String redirectURI = getRedirectURI(request,oauthRequest); OAuthResponse resp; try { AuthorizationCodeBean bean = createAuthCodeBean(loginInfo, oauthRequest); //这里本来应该设置用户选择的信息,但是鉴于开发成本,暂时默认选择全部 bean.setScope(clientBean.getScope()); //设置过期时间 bean.setExpiredTime( new Date(System.currentTimeMillis()+authorTimeout*60l*1000l)); getCodeServer().save(bean); resp = OAuthASResponse .authorizationResponse(request, HttpServletResponse.SC_FOUND) .setCode(bean.getCode()) .setScope(bean.getScope()) .setParam("state", bean.getState()) .location(redirectURI).buildQueryMessage(); String encPwd=getEncPassword(request, clientBean); if(encPwd!=null){ getCacheService().set("pwd.enc."+bean.getCode(), encPwd); } //判断该用户邮箱是否在弱密码验证范围内 boolean isInScope=isInCompulsionPwdScop(getEmailScope(loginInfo.getUser().getCstnetId())); if(clientBean.isCompulsionStrongPwd()&&LoginInfo.TYPE_CORE_MAIL.equals(loginInfo.getPasswordType())&&isInScope&&loginInfo.isWeak()){ String encodedReturnUrl=URLEncoder.encode(resp.getLocationUri(),"UTF-8"); String changePasswordUrl=request.getContextPath()+"/user/manage.do?act=showChangePassword&weakPassword=true&returnUrl="+encodedReturnUrl+"&showCoremailTip=true"; StringBuffer javaScript=new StringBuffer(); javaScript.append("<script>"); javaScript.append(String.format("window.top.location.href='%s';",changePasswordUrl)); javaScript.append("</script>"); response.getWriter().print(javaScript.toString()); }else{ response.sendRedirect(resp.getLocationUri()); } } catch (OAuthSystemException e) { dealOAuthSystemError(redirectURI, e,request, response); } } public boolean isInCompulsionPwdScop(String emailDomail){ Collection<String> scopes=getCompulsionPwdScope(); if(scopes==null||scopes.isEmpty()){ return true; } return scopes.contains(emailDomail); } private String getRedirectURI(HttpServletRequest request, OAuthAuthzRequestWrap oauthRequest) { Boolean b = (Boolean)request.getSession().getAttribute("coremailSecureLogon"); String theme =oauthRequest.getTheme(); String redirectURL = oauthRequest.getRedirectURI(); if("coremail".equals(theme)){ if(b!=null&&b){ redirectURL = redirectURL.trim(); if(redirectURL.startsWith("http:")){ return "https"+redirectURL.substring(4); } } } return redirectURL; } private AuthorizationCodeBean createAuthCodeBean(LoginInfo userLogin, OAuthAuthzRequestWrap oauthRequest) throws OAuthSystemException { User user=userLogin.getUser(); AuthorizationCodeBean bean = new AuthorizationCodeBean(); String passwordType = userLogin.getPasswordType(); bean.setClientId(oauthRequest.getClientId()); bean.setPasswordType(passwordType); bean.setRedirectURI(oauthRequest.getRedirectURI()); bean.setScope(tansferScope(oauthRequest.getScopes())); bean.setState(oauthRequest.getState()); bean.setUid(user.getId()); bean.setCreateTime(new Date()); OAuthIssuer oauthIssuerImpl = new OAuthIssuerImpl(new MD5Generator()); bean.setCode(oauthIssuerImpl.authorizationCode()); return bean; } private UserPrincipal getLoginInfo(HttpServletRequest request,OauthClientBean bean) { LoginInfo userLogin = UMTContext.getLoginInfo(request.getSession()); User user=userLogin.getUser(); if(user == null){ String userName = request.getParameter("userName"); String password = request.getParameter("password"); if(StringUtils.isEmpty(userName)||StringUtils.isEmpty(password)){ return null; } LoginService ls=ServiceFactory.getLoginService(request); UsernamePasswordCredential cred = new UsernamePasswordCredential(userName,password); LoginInfo info = ls.loginAndReturnPasswordType(cred); user = info.getUser(); if(user!=null){ UMTContext.saveUser(request.getSession(), info); IAccountService logService=(IAccountService)ServiceFactory.getBean(request, IAccountService.BEAN_ID); logService.login(bean.getClientName(),null , user.getId(), RequestUtil.getRemoteIP(request), new Date(),request.getHeader("User-Agent"), ""); } }else{ userLogin = getLoginInfoFromCookieAndSession(request); user = userLogin.getUser(); } return user==null?null:user.getUserPrincipal(); } /** * 前端scope显示类型 * @param bean * @return */ private List<OauthScopeBean> dealScope(String clientId,Set<String> userScope) { OauthClientBean client = oauthClientServer.findByClientId(clientId); List<OauthScopeBean> result = new ArrayList<OauthScopeBean>(); Set<String> allScope = client.getScopeSet(); for(String s: allScope){ OauthScopeBean scope = new OauthScopeBean(); scope.setId(s); scope.setName(s); if(userScope.contains(s)){ scope.setStatus("ckecked"); }else{ scope.setStatus("unckecked"); } result.add(scope); } return result; } private String tansferScope(Set<String> scopes){ StringBuilder sb = new StringBuilder(); for(String s : scopes){ sb.append(s).append(","); } if(sb.length()>0){ sb.deleteCharAt(sb.length()-1); } return sb.toString(); } private String tansferScope(String[] scopes){ if(scopes==null||scopes.length==0){ return ""; } StringBuilder sb = new StringBuilder(); for(String s : scopes){ sb.append(s).append(","); } if(sb.length()>0){ sb.deleteCharAt(sb.length()-1); } return sb.toString(); } /** * 用户中途取消授权 * @param request * @param response * @throws IOException */ private void cancelAuthorization(HttpServletRequest request, HttpServletResponse response) throws IOException { OAuthAuthzRequestWrap oauthRequest = new OAuthAuthzRequestWrap(request); dealAppError("access_denied","用户取消授权" ,oauthRequest.getRedirectURI(), response); } public void checkLogin(HttpServletRequest request, HttpServletResponse response) { LoginInfo loginInfo = getLoginInfoFromCookieAndSession(request); JSONObject obj = new JSONObject(); if(loginInfo.getUser()!=null){ obj.put("status", true); obj.put("userName", loginInfo.getUser().getCstnetId()); obj.put("logoutURL", ServiceFactory.getWebUrl(request)+"/logout?WebServerURL="); }else{ obj.put("status", false); } writeJSONResponse(response, obj); } private IOauthClientService getClientServer(){ if(oauthClientServer ==null){ initClientServer(); } return oauthClientServer; } private synchronized void initClientServer() { if(oauthClientServer ==null){ oauthClientServer = (IOauthClientService)getBeanFactory().getBean(IOauthClientService.BEAN_ID); } } private synchronized IAuthorizationCodeServer getCodeServer(){ if(authorizationCodeServer==null){ initCodeServer(); } return authorizationCodeServer; } private synchronized void initCodeServer() { if(authorizationCodeServer==null){ authorizationCodeServer = (IAuthorizationCodeServer)getBeanFactory().getBean(IAuthorizationCodeServer.BEAN_ID); } } private synchronized IOauthTokenService getTokenServer(){ if(oauthTokenServer==null){ initTokenServer(); } return oauthTokenServer; } private synchronized void initTokenServer() { if(oauthTokenServer==null){ oauthTokenServer = (IOauthTokenService)getBeanFactory().getBean(IOauthTokenService.BEAN_ID); } } private BeanFactory getBeanFactory(){ return (BeanFactory) getServletContext() .getAttribute(Attributes.APPLICATION_CONTEXT_KEY); } private ICacheService getCacheService(){ if(cacheService==null){ this.cacheService=(ICacheService)getBeanFactory().getBean("cacheService"); } return cacheService; } private void dealOAuthSystemError(String redirectURI,OAuthSystemException e,HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException{ if(StringUtils.isEmpty(redirectURI)){ request.setAttribute("client_id", request.getParameter("client_id")); request.setAttribute("errorCode", "server_error"); request.setAttribute("errorDescription", e.getMessage()); dealClientRedirectError(request, response); return; } OAuthResponse resp = null; try { resp = OAuthASResponse .errorResponse(HttpServletResponse.SC_FOUND).setError("server_error") .location(redirectURI).buildQueryMessage(); } catch (OAuthSystemException ex) { LOG.error("redirectURI="+redirectURI,ex); } LOG.error("",e); response.sendRedirect(resp.getLocationUri()); } private void dealClientRedirectError(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException{ request.getRequestDispatcher("/oauth/redirecturlerror.jsp").forward(request, response); } private String getEmailScope(String email){ if(StringUtils.isBlank(email)){ return ""; } if(StringUtils.contains(email, "@")){ return StringUtils.split(email, "@")[1]; } return ""; } }