You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
355 lines
16 KiB
355 lines
16 KiB
package com.fr.plugin.xxxx.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.bean.authentication.OriginUrlResponseBean; |
|
import com.fr.decision.webservice.exception.user.UserNotExistException; |
|
import com.fr.decision.webservice.utils.DecisionServiceConstants; |
|
import com.fr.decision.webservice.utils.DecisionStatusService; |
|
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.xxxx.saml.xxxx.saml.SAMLException; |
|
import com.fr.plugin.xxxx.saml.xxxx.saml.SAMLResponseValidator; |
|
import com.fr.plugin.xxxx.saml.xxxx.saml.constant.SsoConstants; |
|
import com.fr.plugin.xxxx.saml.xxxx.saml.impl.SAMLRequestImpl; |
|
import com.fr.plugin.xxxx.saml.xxxx.saml.impl.SAMLResponseValidatorImpl; |
|
import com.fr.plugin.xxxx.saml.schedule.SyncThread; |
|
import com.fr.plugin.transform.FunctionRecorder; |
|
import com.fr.scheduler.QuartzContext; |
|
import com.fr.scheduler.ScheduleJobManager; |
|
import com.fr.stable.StringUtils; |
|
import com.fr.stable.web.Device; |
|
import com.fr.third.v2.org.quartz.CronScheduleBuilder; |
|
import com.fr.third.v2.org.quartz.JobKey; |
|
import com.fr.third.v2.org.quartz.SchedulerException; |
|
import com.fr.third.v2.org.quartz.TriggerBuilder; |
|
import com.fr.web.utils.WebUtils; |
|
import com.fr.third.org.apache.commons.codec.binary.Base64; |
|
|
|
import javax.servlet.FilterChain; |
|
import javax.servlet.ServletException; |
|
import javax.servlet.http.Cookie; |
|
import javax.servlet.http.HttpServletRequest; |
|
import javax.servlet.http.HttpServletResponse; |
|
import javax.servlet.http.HttpSession; |
|
import java.io.IOException; |
|
import java.io.PrintWriter; |
|
import java.io.UnsupportedEncodingException; |
|
import java.net.URLEncoder; |
|
import java.nio.charset.StandardCharsets; |
|
import java.util.HashMap; |
|
import java.util.Map; |
|
import java.util.UUID; |
|
|
|
/** |
|
* @Author fr.open |
|
* @Date 2020/9/10 |
|
* @Description |
|
**/ |
|
@FunctionRecorder |
|
public class SsoFilter extends AbstractGlobalRequestFilterProvider { |
|
|
|
|
|
private static String[] notFilter = { |
|
"/decision/file", "/decision/resources", |
|
"/decision/login/config", "/decision/system/info", "/decision/login/slider", |
|
"/decision/remote", "/share", "/mobileTip.html", "/link" |
|
}; |
|
|
|
@Override |
|
public String filterName() { |
|
return "honor"; |
|
} |
|
|
|
@Override |
|
public String[] urlPatterns() { |
|
initSchedule(); |
|
return new String[]{"/*"}; |
|
} |
|
|
|
@Override |
|
public void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) { |
|
if (isLogin(req) || isResource(req)) { |
|
filter(req, res, filterChain); |
|
return; |
|
} |
|
String samlResp = req.getParameter("SAMLResponse"); |
|
String viewlet = WebUtils.getHTTPRequestParameter(req, "viewlet"); |
|
String reportlet = WebUtils.getHTTPRequestParameter(req, "reportlet"); |
|
String formlet = WebUtils.getHTTPRequestParameter(req, "formlet"); |
|
String let = StringUtils.isNotBlank(viewlet) ? viewlet : StringUtils.isNotBlank(reportlet) ? reportlet : formlet; |
|
//在判断是否是需授权报表 |
|
if (StringUtils.isBlank(samlResp) && StringUtils.isNotBlank(let) && !ReportService.getInstance().isAuth(let)) { |
|
filter(req, res, filterChain); |
|
return; |
|
} |
|
|
|
if (isMobileDevice(req) && new MobileFilter().doFilter(req, res, filterChain)) { |
|
return; |
|
} |
|
|
|
HttpSession session = req.getSession(true); |
|
if (session == null || session.getAttribute(SsoConstants.SESSION_USER_INFO_KEY) == null) { |
|
FineLoggerFactory.getLogger().info("samlResp is {}", samlResp); |
|
if (samlResp != null && !samlResp.equals("")) { |
|
try { |
|
byte[] buffer = new Base64().decode(samlResp.getBytes(req.getCharacterEncoding() == null ? "UTF-8" : req.getCharacterEncoding())); |
|
FineLoggerFactory.getLogger().info("decode base64 result is {}", new String(buffer, StandardCharsets.UTF_8)); |
|
SAMLResponseValidator vld = new SAMLResponseValidatorImpl( |
|
new String(buffer, StandardCharsets.UTF_8)); |
|
vld.validate(); |
|
//UserInfoBean uiBean = vld.getUIBean(); |
|
FineLoggerFactory.getLogger().info("decode user bean is [{}]", vld.getUid()); |
|
loginFromToken(req, res, vld.getUid()); |
|
FineLoggerFactory.getLogger().info("login bean set session!"); |
|
session.setAttribute(SsoConstants.SESSION_USER_INFO_KEY, vld.getUid()); |
|
String prefix = TemplateUtils.render("${fineServletURL}"); |
|
if (isMobileDevice(req) && (req.getRequestURI().endsWith(prefix + "/") || req.getRequestURI().endsWith(prefix))) { |
|
String url = req.getRequestURL().toString().endsWith("/") ? req.getRequestURL().toString() + "url/mobile" : req.getRequestURL().toString() + "/url/mobile"; |
|
FineLoggerFactory.getLogger().info("forward {} to {}", req.getRequestURI(), url); |
|
String jump = getOrigin(req); |
|
FineLoggerFactory.getLogger().info("get Origin path is {}", jump); |
|
if (StringUtils.isNotBlank(jump)) { |
|
res.sendRedirect(jump); |
|
} else { |
|
res.sendRedirect(url); |
|
} |
|
return; |
|
} |
|
String jump = getOrigin(req); |
|
FineLoggerFactory.getLogger().info("get Origin path is {}", jump); |
|
if (StringUtils.isNotBlank(jump)) { |
|
res.sendRedirect(jump); |
|
return; |
|
} |
|
filter(req, res, filterChain); |
|
return; |
|
} catch (SAMLException | UnsupportedEncodingException e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
req.setAttribute("SAMLRequest", e.getMessage()); |
|
setResError(res, e); |
|
} catch (UserNotExistException e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
setResError(res, e); |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
} else { |
|
try { |
|
FineLoggerFactory.getLogger().info("samlResp is null,redirect login!"); |
|
/*byte[] samlRequest = new SAMLRequestImpl().generate().getBytes(StandardCharsets.UTF_8); |
|
samlRequest = new Base64().encode(samlRequest); |
|
req.setAttribute("SAMLRequest", new String(samlRequest, StandardCharsets.UTF_8)); |
|
FineLoggerFactory.getLogger().info("return page is:{}",PropertiesUtils.getProperties("conf").getProperty("return")); |
|
req.getRequestDispatcher(PropertiesUtils.getProperties("conf").getProperty("return")).forward(req, res);*/ |
|
byte[] samlRequest = new SAMLRequestImpl().generate().getBytes(StandardCharsets.UTF_8); |
|
String saml = new String(new Base64().encode(samlRequest), StandardCharsets.UTF_8.name()); |
|
String url = PropertiesUtils.getProperties("conf").getProperty("return"); |
|
String back = String.format("%s?SAMLRequest=%s&RelayState=null", url, URLEncoder.encode(saml, StandardCharsets.UTF_8.toString())); |
|
FineLoggerFactory.getLogger().info("back login :{}", back); |
|
String jump = req.getRequestURL() + (req.getQueryString() == null ? StringUtils.EMPTY : "?" + req.getQueryString()); |
|
String id = UUID.randomUUID().toString(); |
|
DecisionStatusService.originUrlStatusService().put(id, new OriginUrlResponseBean(jump));//添加重定向地址 |
|
Cookie cookie = new Cookie("ORIGIN_URL", id); |
|
cookie.setPath("/"); |
|
cookie.setHttpOnly(true); |
|
res.addCookie(cookie); |
|
res.sendRedirect(back); |
|
return; |
|
} catch (SAMLException e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
req.setAttribute("SAMLRequest", e.getMessage()); |
|
setResError(res, e); |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
} |
|
} |
|
|
|
String id = (String) session.getAttribute(SsoConstants.SESSION_USER_INFO_KEY); |
|
if (StringUtils.isNotBlank(id)) { |
|
FineLoggerFactory.getLogger().info("get user:{} form session", id); |
|
loginFromToken(req, res, id); |
|
filter(req, res, filterChain); |
|
} |
|
return; |
|
|
|
} |
|
|
|
private void setError(HttpServletResponse res) { |
|
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", "权限生效时间为2小时,如有疑问,请联系运维人员"); |
|
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); |
|
} |
|
} |
|
|
|
private String getViewlet(HttpServletRequest req) { |
|
return WebUtils.getHTTPRequestParameter(req, "viewlet") == null ? |
|
WebUtils.getHTTPRequestParameter(req, "formlet") |
|
: WebUtils.getHTTPRequestParameter(req, "viewlet"); |
|
} |
|
|
|
private String getOrigin(HttpServletRequest req) throws Exception { |
|
Cookie[] cookies = req.getCookies(); |
|
if (cookies == null) { |
|
return null; |
|
} |
|
for (int i = 0; i < cookies.length; i++) { |
|
if ("ORIGIN_URL".equals(cookies[i].getName())) { |
|
String id = cookies[i].getValue(); |
|
OriginUrlResponseBean path = DecisionStatusService.originUrlStatusService().get(id); |
|
return path == null ? StringUtils.EMPTY : path.getOriginUrl(); |
|
} |
|
} |
|
return StringUtils.EMPTY; |
|
} |
|
|
|
private boolean isResource(HttpServletRequest req) { |
|
String viewlet = WebUtils.getHTTPRequestParameter(req, "viewlet"); |
|
String reportlet = WebUtils.getHTTPRequestParameter(req, "reportlet"); |
|
String formlet = WebUtils.getHTTPRequestParameter(req, "formlet"); |
|
String let = StringUtils.isNotBlank(viewlet) ? viewlet : StringUtils.isNotBlank(reportlet) ? reportlet : formlet; |
|
String op = WebUtils.getHTTPRequestParameter(req, "op"); |
|
if (StringUtils.isNotBlank(op) && StringUtils.isBlank(let)) { |
|
return true; |
|
} |
|
if (req.getRequestURI().endsWith("js") || req.getRequestURI().endsWith("css")) { |
|
return true; |
|
} |
|
for (int i = 0; i < notFilter.length; i++) { |
|
if (req.getRequestURI().contains(notFilter[i])) { |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
private void setResError(HttpServletResponse res, Exception e) { |
|
try { |
|
WebUtils.printAsString(res, e.getMessage()); |
|
} catch (Exception exception) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
} |
|
|
|
private boolean loginFromToken(HttpServletRequest req, HttpServletResponse res, String username) { |
|
try { |
|
if (StringUtils.isNotEmpty(username)) { |
|
FineLoggerFactory.getLogger().info("current username:" + username); |
|
User user = UserService.getInstance().getUserByUserName(username); |
|
FineLoggerFactory.getLogger().info("get user:" + user); |
|
if (user == null) { |
|
throw new UserNotExistException(); |
|
} |
|
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 (UserNotExistException e) { |
|
throw new UserNotExistException(); |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
|
|
return false; |
|
} |
|
|
|
private void filter(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) { |
|
try { |
|
filterChain.doFilter(req, res); |
|
} catch (IOException e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} catch (ServletException e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
} |
|
|
|
private boolean isLogin(HttpServletRequest request) { |
|
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; |
|
} |
|
|
|
public boolean isMobileDevice(HttpServletRequest request) { |
|
String deviceType = WebUtils.getHTTPRequestParameter(request,"deviceType"); |
|
if(StringUtils.isNotBlank(deviceType)){ |
|
FineLoggerFactory.getLogger().info("get deviceType is {}",deviceType); |
|
return StringUtils.equals(deviceType,"mobile"); |
|
} |
|
String requestHeader = request.getHeader("user-agent"); |
|
String[] deviceArray = new String[]{"android", "iphone", "ios", "windows phone"}; |
|
if (requestHeader == null) { |
|
return false; |
|
} |
|
requestHeader = requestHeader.toLowerCase(); |
|
for (int i = 0; i < deviceArray.length; i++) { |
|
if (requestHeader.contains(deviceArray[i])) { |
|
FineLoggerFactory.getLogger().info("current request:{} is mobile request!", request.getRequestURI()); |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
public static void initSchedule() { |
|
JobKey jobKey = new JobKey("syncRole", "syncGroup"); |
|
try { |
|
if (QuartzContext.getInstance().getScheduler().checkExists(jobKey)) { |
|
ScheduleJobManager.getInstance().removeJob(jobKey.getName(), jobKey.getGroup()); |
|
} |
|
} catch (SchedulerException e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
|
|
addSchedule(jobKey); |
|
} |
|
|
|
private static void addSchedule(JobKey jobKey) { |
|
Map<String, Object> param = new HashMap(); |
|
TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger(); |
|
triggerBuilder.forJob(jobKey.getName(), jobKey.getGroup()).withIdentity(jobKey.getName(), jobKey.getGroup()).startNow(); |
|
String cron = com.fr.base.PropertiesUtils.getProperties("conf").getProperty("cron"); |
|
if (StringUtils.isBlank(cron)) { |
|
FineLoggerFactory.getLogger().error("cron is null schedule start failed"); |
|
return; |
|
} |
|
CronScheduleBuilder schedule = CronScheduleBuilder.cronSchedule(cron); |
|
triggerBuilder.withSchedule(schedule); |
|
try { |
|
ScheduleJobManager.getInstance().addJob(jobKey.getName(), jobKey.getGroup(), "sync job", SyncThread.class, triggerBuilder.build(), param); |
|
} catch (Exception e) { |
|
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
|
} |
|
} |
|
}
|
|
|