8 changed files with 458 additions and 1 deletions
Binary file not shown.
Binary file not shown.
@ -1,3 +1,6 @@ |
|||||||
# open-JSD-8364 |
# open-JSD-8364 |
||||||
|
|
||||||
JSD-8364 开源任务材料 |
JSD-8364 开源任务材料\ |
||||||
|
免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\ |
||||||
|
仅作为开发者学习参考使用!禁止用于任何商业用途!\ |
||||||
|
为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系hugh处理。 |
@ -0,0 +1,19 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||||
|
<plugin> |
||||||
|
<id>com.fr.plugin.adfs.saml</id> |
||||||
|
<name><![CDATA[xxxx单点]]></name> |
||||||
|
<active>yes</active> |
||||||
|
<version>1.4</version> |
||||||
|
<env-version>10.0</env-version> |
||||||
|
<jartime>2019-03-10</jartime> |
||||||
|
<vendor>fr.open</vendor> |
||||||
|
<description><![CDATA[xxxx单点]]></description> |
||||||
|
<change-notes> |
||||||
|
|
||||||
|
</change-notes> |
||||||
|
<function-recorder class="com.fr.plugin.adfs.saml.SsoFilter"/> |
||||||
|
|
||||||
|
<extra-decision> |
||||||
|
<GlobalRequestFilterProvider class="com.fr.plugin.adfs.saml.SsoFilter"/> |
||||||
|
</extra-decision> |
||||||
|
</plugin> |
@ -0,0 +1,66 @@ |
|||||||
|
package com.fr.plugin.adfs.saml; |
||||||
|
|
||||||
|
import com.fr.third.org.apache.commons.codec.binary.Base64; |
||||||
|
|
||||||
|
import javax.crypto.Cipher; |
||||||
|
import javax.crypto.spec.SecretKeySpec; |
||||||
|
import java.security.Key; |
||||||
|
|
||||||
|
/** |
||||||
|
* @Author fr.open |
||||||
|
* @Date 2021/7/21 |
||||||
|
* @Description |
||||||
|
**/ |
||||||
|
public class DesECBUtil { |
||||||
|
/** |
||||||
|
* 加密数据 |
||||||
|
* |
||||||
|
* @param encryptString |
||||||
|
* @param encryptKey |
||||||
|
* @return |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public static String encryptDES(String encryptString, String encryptKey) throws Exception { |
||||||
|
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); |
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(getKey(encryptKey), "DES")); |
||||||
|
byte[] encryptedData = cipher.doFinal(encryptString.getBytes("UTF-8")); |
||||||
|
return Base64.encodeBase64String(encryptedData); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* key 不足8位补位 |
||||||
|
* |
||||||
|
* @param |
||||||
|
*/ |
||||||
|
public static byte[] getKey(String keyRule) { |
||||||
|
Key key = null; |
||||||
|
byte[] keyByte = keyRule.getBytes(); |
||||||
|
// 创建一个空的八位数组,默认情况下为0
|
||||||
|
byte[] byteTemp = new byte[8]; |
||||||
|
// 将用户指定的规则转换成八位数组
|
||||||
|
for (int i = 0; i < byteTemp.length && i < keyByte.length; i++) { |
||||||
|
byteTemp[i] = keyByte[i]; |
||||||
|
} |
||||||
|
key = new SecretKeySpec(byteTemp, "DES"); |
||||||
|
return key.getEncoded(); |
||||||
|
} |
||||||
|
|
||||||
|
/*** |
||||||
|
* 解密数据 |
||||||
|
* @param decryptString |
||||||
|
* @param decryptKey |
||||||
|
* @return |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
|
||||||
|
public static String decryptDES(String decryptString, String decryptKey) throws Exception { |
||||||
|
byte[] sourceBytes = Base64.decodeBase64(decryptString); |
||||||
|
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); |
||||||
|
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(getKey(decryptKey), "DES")); |
||||||
|
byte[] decoded = cipher.doFinal(sourceBytes); |
||||||
|
return new String(decoded, "UTF-8"); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
@ -0,0 +1,116 @@ |
|||||||
|
package com.fr.plugin.adfs.saml; |
||||||
|
|
||||||
|
import javax.crypto.Cipher; |
||||||
|
import javax.crypto.SecretKey; |
||||||
|
import javax.crypto.SecretKeyFactory; |
||||||
|
import javax.crypto.spec.DESKeySpec; |
||||||
|
import java.io.UnsupportedEncodingException; |
||||||
|
import java.security.SecureRandom; |
||||||
|
|
||||||
|
/** |
||||||
|
* @Author fr.open |
||||||
|
* @Date 2021/7/21 |
||||||
|
* @Description |
||||||
|
**/ |
||||||
|
public class KeysUtil { |
||||||
|
/** 加密解密KEY */ |
||||||
|
// private static final String KEY = "xxxx";
|
||||||
|
/** 加密解密算法 */ |
||||||
|
private final static String ALGORITHM = "DES"; |
||||||
|
/** |
||||||
|
* 加密 |
||||||
|
* @param data 未加密数据 |
||||||
|
* @param key 加密key |
||||||
|
* @return |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public static String encrypt(String data, String key) throws Exception { |
||||||
|
|
||||||
|
byte[] dataBytes = data.getBytes("UTF-8"); |
||||||
|
|
||||||
|
byte[] keyBytes = key.getBytes("UTF-8"); |
||||||
|
|
||||||
|
// DES算法要求有一个可信任的随机数源
|
||||||
|
SecureRandom sr = new SecureRandom(); |
||||||
|
|
||||||
|
// 从原始密匙数据创建DESKeySpec对象
|
||||||
|
DESKeySpec dks = new DESKeySpec(keyBytes); |
||||||
|
|
||||||
|
// 创建一个密匙工厂,然后用它把DESKeySpec转换成
|
||||||
|
// 一个SecretKey对象
|
||||||
|
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM); |
||||||
|
SecretKey securekey = keyFactory.generateSecret(dks); |
||||||
|
|
||||||
|
// Cipher对象实际完成加密操作
|
||||||
|
Cipher cipher = Cipher.getInstance(ALGORITHM); |
||||||
|
|
||||||
|
// 用密匙初始化Cipher对象
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, securekey, sr); |
||||||
|
|
||||||
|
// 正式执行加密操作
|
||||||
|
byte[] bytes = cipher.doFinal(dataBytes); |
||||||
|
return byte2hex(bytes); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 解密 |
||||||
|
* @param data 加密后的数据 |
||||||
|
* @param key 加密key |
||||||
|
* @return |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
public static String decrypt(String data, String key) throws Exception { |
||||||
|
|
||||||
|
byte[] dataBytes = data.getBytes("UTF-8"); |
||||||
|
byte[] hex2byte = hex2byte(dataBytes); |
||||||
|
byte[] keyBytes = key.getBytes("UTF-8"); |
||||||
|
|
||||||
|
// DES算法要求有一个可信任的随机数源
|
||||||
|
SecureRandom sr = new SecureRandom(); |
||||||
|
|
||||||
|
// 从原始密匙数据创建一个DESKeySpec对象
|
||||||
|
DESKeySpec dks = new DESKeySpec(keyBytes); |
||||||
|
|
||||||
|
// 创建一个密匙工厂,然后用它把DESKeySpec对象转换成
|
||||||
|
// 一个SecretKey对象
|
||||||
|
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM); |
||||||
|
SecretKey securekey = keyFactory.generateSecret(dks); |
||||||
|
|
||||||
|
// Cipher对象实际完成解密操作
|
||||||
|
Cipher cipher = Cipher.getInstance(ALGORITHM); |
||||||
|
|
||||||
|
// 用密匙初始化Cipher对象
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, securekey, sr); |
||||||
|
|
||||||
|
// 正式执行解密操作
|
||||||
|
byte[] doFinal = cipher.doFinal(hex2byte); |
||||||
|
|
||||||
|
return new String(doFinal,"UTF-8"); |
||||||
|
} |
||||||
|
|
||||||
|
private static byte[] hex2byte(byte[] b) throws UnsupportedEncodingException { |
||||||
|
if ((b.length % 2) != 0) { |
||||||
|
throw new IllegalArgumentException("长度不是偶数"); |
||||||
|
} |
||||||
|
byte[] b2 = new byte[b.length / 2]; |
||||||
|
for (int n = 0; n < b.length; n += 2) { |
||||||
|
String item = new String(b, n, 2, "UTF-8"); |
||||||
|
b2[n / 2] = (byte) Integer.parseInt(item, 16); |
||||||
|
} |
||||||
|
return b2; |
||||||
|
} |
||||||
|
|
||||||
|
private static String byte2hex(byte[] b) { |
||||||
|
StringBuilder bulid = new StringBuilder(); |
||||||
|
String stmp = ""; |
||||||
|
for (int n = 0; n < b.length; n++) { |
||||||
|
stmp = (Integer.toHexString(b[n] & 0XFF)); |
||||||
|
if (stmp.length() == 1) { |
||||||
|
bulid.append("0").append(stmp); |
||||||
|
} else { |
||||||
|
bulid.append(stmp); |
||||||
|
} |
||||||
|
} |
||||||
|
return bulid.toString().toUpperCase(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,250 @@ |
|||||||
|
/* |
||||||
|
* The contents of this file are subject to the Mozilla Public |
||||||
|
* License Version 1.1 (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.mozilla.org/MPL/
|
||||||
|
* |
||||||
|
* Software distributed under the License is distributed on an |
||||||
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express |
||||||
|
* or implied. See the License for the specific language governing |
||||||
|
* rights and limitations under the License. |
||||||
|
* |
||||||
|
* |
||||||
|
* The Original Code is OIOSAML Java Service Provider. |
||||||
|
* |
||||||
|
* The Initial Developer of the Original Code is Trifork A/S. Portions |
||||||
|
* created by Trifork A/S are Copyright (C) 2008 Danish National IT |
||||||
|
* and Telecom Agency (http://www.itst.dk). All Rights Reserved.
|
||||||
|
* |
||||||
|
* Contributor(s): |
||||||
|
* Joakim Recht <jre@trifork.com> |
||||||
|
* Rolf Njor Jensen <rolf@trifork.com> |
||||||
|
* Aage Nielsen <ani@openminds.dk> |
||||||
|
* |
||||||
|
*/ |
||||||
|
package com.fr.plugin.adfs.saml; |
||||||
|
|
||||||
|
import com.fr.base.TemplateUtils; |
||||||
|
import com.fr.data.NetworkHelper; |
||||||
|
import com.fr.decision.authority.data.User; |
||||||
|
import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider; |
||||||
|
import com.fr.decision.mobile.terminal.TerminalHandler; |
||||||
|
import com.fr.decision.webservice.utils.DecisionServiceConstants; |
||||||
|
import com.fr.decision.webservice.utils.WebServiceUtils; |
||||||
|
import com.fr.decision.webservice.v10.login.LoginService; |
||||||
|
import com.fr.decision.webservice.v10.login.TokenResource; |
||||||
|
import com.fr.decision.webservice.v10.user.UserService; |
||||||
|
import com.fr.general.PropertiesUtils; |
||||||
|
import com.fr.locale.InterProviderFactory; |
||||||
|
import com.fr.log.FineLoggerFactory; |
||||||
|
import com.fr.plugin.transform.FunctionRecorder; |
||||||
|
import com.fr.stable.StringUtils; |
||||||
|
import com.fr.stable.web.Device; |
||||||
|
import com.fr.web.utils.WebUtils; |
||||||
|
|
||||||
|
import javax.servlet.FilterChain; |
||||||
|
import javax.servlet.http.HttpServletRequest; |
||||||
|
import javax.servlet.http.HttpServletResponse; |
||||||
|
import java.io.IOException; |
||||||
|
import java.io.PrintWriter; |
||||||
|
import java.text.SimpleDateFormat; |
||||||
|
import java.time.Instant; |
||||||
|
import java.util.Date; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
/** |
||||||
|
* @Author fr.open |
||||||
|
* @Date 2021/7/21 |
||||||
|
* @Description |
||||||
|
**/ |
||||||
|
@FunctionRecorder |
||||||
|
public class SsoFilter extends AbstractGlobalRequestFilterProvider { |
||||||
|
|
||||||
|
private static final String[] notFilter = { |
||||||
|
"/decision/file", |
||||||
|
"/decision/resources", |
||||||
|
"/decision/login/config", |
||||||
|
"/decision/system", |
||||||
|
"/decision/login/slider", |
||||||
|
"/decision/remote", |
||||||
|
"/decision/login", |
||||||
|
}; |
||||||
|
|
||||||
|
@Override |
||||||
|
public String filterName() { |
||||||
|
return "ynhg"; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String[] urlPatterns() { |
||||||
|
return new String[]{"/*"}; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) { |
||||||
|
String samlToken = req.getParameter("samlToken"); |
||||||
|
try { |
||||||
|
if(isAccept(req) || isLogin(req)){ |
||||||
|
if(req.getRequestURI().endsWith("hello.html")){ |
||||||
|
String root = TemplateUtils.render("${fineServletURL}"); |
||||||
|
res.sendRedirect(root); |
||||||
|
return; |
||||||
|
} |
||||||
|
next(req, res, filterChain); |
||||||
|
return; |
||||||
|
} |
||||||
|
if(req.getRequestURI().endsWith("hello.html")){ |
||||||
|
FineLoggerFactory.getLogger().info("start oa sso"); |
||||||
|
SimpleDateFormat sdfDay = new SimpleDateFormat( |
||||||
|
"yyyy-MM-dd"); |
||||||
|
Date date = new Date();//系统当前日期
|
||||||
|
String username = req.getParameter("loginid");; |
||||||
|
//解密
|
||||||
|
try { |
||||||
|
username = KeysUtil .decrypt(username, sdfDay.format(date)); |
||||||
|
} catch (Exception e1) { |
||||||
|
FineLoggerFactory.getLogger().error(e1.getMessage(),e1); |
||||||
|
} |
||||||
|
FineLoggerFactory.getLogger().info("get oa user is {}",username); |
||||||
|
if (StringUtils.isNotEmpty(username)) { |
||||||
|
loginFromToken(req,res,username); |
||||||
|
//next(req, res, filterChain);
|
||||||
|
String root = TemplateUtils.render("${fineServletURL}"); |
||||||
|
res.sendRedirect(root); |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(samlToken)) { |
||||||
|
String key = PropertiesUtils.getProperties("conf").getProperty("key"); |
||||||
|
FineLoggerFactory.getLogger().info("get key config is {}", key); |
||||||
|
String format = DesECBUtil.decryptDES(samlToken, key); |
||||||
|
FineLoggerFactory.getLogger().info("decode format is {}",format); |
||||||
|
String user = format.split("_")[0]; |
||||||
|
String timeout = format.split("_")[1]; |
||||||
|
String out = PropertiesUtils.getProperties("conf").getProperty("timeout"); |
||||||
|
FineLoggerFactory.getLogger().info("get timeout config is {}", out); |
||||||
|
if(StringUtils.isBlank(out)){ |
||||||
|
out = "10"; |
||||||
|
} |
||||||
|
if (Instant.ofEpochMilli(Long.valueOf(timeout)).plusSeconds(Long.valueOf(out)).isBefore(Instant.now())) { |
||||||
|
setError(res, "format timeout!"); |
||||||
|
return; |
||||||
|
} |
||||||
|
if(!checkUser(user)){ |
||||||
|
setError(res, "user: 【"+user+"】 not exist !"); |
||||||
|
return; |
||||||
|
} |
||||||
|
loginFromToken(req,res,user); |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||||
|
} |
||||||
|
FineLoggerFactory.getLogger().info("current request {} not login send redirect login",getUrl(req)); |
||||||
|
String saml = PropertiesUtils.getProperties("conf").getProperty("saml"); |
||||||
|
try { |
||||||
|
res.sendRedirect(saml); |
||||||
|
} catch (IOException e) { |
||||||
|
FineLoggerFactory.getLogger().error(e.getMessage(),e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private String getUrl(HttpServletRequest req) { |
||||||
|
String requestURL = req.getRequestURL().toString(); |
||||||
|
String queryString = req.getQueryString(); |
||||||
|
if(StringUtils.isNotBlank(queryString)){ |
||||||
|
requestURL +="?"+queryString; |
||||||
|
} |
||||||
|
return requestURL; |
||||||
|
} |
||||||
|
|
||||||
|
private boolean isLogin(HttpServletRequest request) throws Exception { |
||||||
|
String oldToken = TokenResource.COOKIE.getToken(request); |
||||||
|
return oldToken != null && checkTokenValid(request, (String) oldToken); |
||||||
|
} |
||||||
|
|
||||||
|
private boolean checkTokenValid(HttpServletRequest req, String token) { |
||||||
|
try { |
||||||
|
Device device = NetworkHelper.getDevice(req); |
||||||
|
LoginService.getInstance().loginStatusValid(token, TerminalHandler.getTerminal(req, device)); |
||||||
|
return true; |
||||||
|
} catch (Exception ignore) { |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
private boolean isAccept(HttpServletRequest req) { |
||||||
|
for (int i = 0; i < notFilter.length; i++) { |
||||||
|
if (req.getRequestURI().contains(notFilter[i])) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
if (req.getRequestURI().endsWith("/.css") || req.getRequestURI().endsWith("/.js")) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
if(req.getRequestURI().endsWith("/view/form") || req.getRequestURI().endsWith("/view/report")){ |
||||||
|
return StringUtils.isBlank(WebUtils.getHTTPRequestParameter(req, "viewlet")); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
private void next(HttpServletRequest request, HttpServletResponse response, FilterChain chain) { |
||||||
|
try { |
||||||
|
chain.doFilter(request, response); |
||||||
|
} catch (Exception e) { |
||||||
|
throw new RuntimeException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private boolean checkUser(String username) { |
||||||
|
User user = null; |
||||||
|
try { |
||||||
|
user = UserService.getInstance().getUserByUserName(username); |
||||||
|
FineLoggerFactory.getLogger().info("get user:" + user); |
||||||
|
if (user != null) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
private boolean loginFromToken(HttpServletRequest req, HttpServletResponse res, String username) throws Exception { |
||||||
|
try { |
||||||
|
if (StringUtils.isNotEmpty(username)) { |
||||||
|
FineLoggerFactory.getLogger().info("current username:" + username); |
||||||
|
String token = LoginService.getInstance().login(req, res, username); |
||||||
|
FineLoggerFactory.getLogger().info("get login token:" + token); |
||||||
|
req.setAttribute(DecisionServiceConstants.FINE_AUTH_TOKEN_NAME, token); |
||||||
|
FineLoggerFactory.getLogger().info("username:" + username + "login success"); |
||||||
|
return true; |
||||||
|
} else { |
||||||
|
FineLoggerFactory.getLogger().warn("username is null!"); |
||||||
|
return false; |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
private void setError(HttpServletResponse res, String reason) { |
||||||
|
try { |
||||||
|
PrintWriter printWriter = WebUtils.createPrintWriter(res); |
||||||
|
Map<String, Object> map = new HashMap<>(); |
||||||
|
map.put("result", InterProviderFactory.getProvider().getLocText("Fine-Engine_Error_Page_Result")); |
||||||
|
map.put("reason", reason); |
||||||
|
map.put("solution", InterProviderFactory.getProvider().getLocText("Fine-Engine_Please_Contact_Platform_Admin")); |
||||||
|
String page = WebServiceUtils.parseWebPageResourceSafe("com/fr/web/controller/decision/entrance/resources/unavailable.html", map); |
||||||
|
printWriter.write(page); |
||||||
|
printWriter.flush(); |
||||||
|
printWriter.close(); |
||||||
|
} catch (Exception e) { |
||||||
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
Loading…
Reference in new issue