From dff96fbd260a1e68f03bd55934ca19f90be819ec Mon Sep 17 00:00:00 2001 From: jamiesun <âœjamiesun.net@gmail.com> Date: Fri, 24 May 2019 15:55:53 +0800 Subject: [PATCH 1/8] routeros wifi --- .../controller/RouterOSController.java | 74 ++++++++++ .../org/toughradius/form/RouterOSParam.java | 131 ++++++++++++++++++ .../resources/portal/default/roslogin.html | 62 +++++++++ .../resources/portal/default/rosstatus.html | 51 +++++++ .../portal/default/static/css/main.css | 12 +- 5 files changed, 329 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/toughradius/controller/RouterOSController.java create mode 100644 src/main/java/org/toughradius/form/RouterOSParam.java create mode 100644 src/main/resources/portal/default/roslogin.html create mode 100644 src/main/resources/portal/default/rosstatus.html diff --git a/src/main/java/org/toughradius/controller/RouterOSController.java b/src/main/java/org/toughradius/controller/RouterOSController.java new file mode 100644 index 00000000..7514f6df --- /dev/null +++ b/src/main/java/org/toughradius/controller/RouterOSController.java @@ -0,0 +1,74 @@ +package org.toughradius.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.ModelAndView; +import org.toughradius.common.ValidateUtil; +import org.toughradius.component.ConfigService; +import org.toughradius.component.Memarylogger; +import org.toughradius.config.Constant; +import org.toughradius.form.RouterOSParam; +import org.toughradius.form.WlanParam; + +import javax.servlet.http.HttpServletRequest; + +@Controller +public class RouterOSController implements Constant{ + + @Autowired + private ConfigService configService; + + @Autowired + protected Memarylogger logger; + + + private String getWlanemplate(){ + String template = configService.getStringValue(WLAN_MODULE,WLAN_TEMPLATE); + if(ValidateUtil.isEmpty(template)){ + return "default"; + } + return template; + } + + /** + * portal 首页 + * @param rosParam + * @return + */ + @RequestMapping("/routeros/login") + public ModelAndView wlanIndexHandler(RouterOSParam rosParam, HttpServletRequest request){ + logger.info(rosParam.getUsername(),"接收到RouterOS 认证请求 "+rosParam.toString(),Memarylogger.PORTAL); + String joinUrl = configService.getStringValue(WLAN_MODULE, WLAN_JOIN_URL); + String template = getWlanemplate(); + ModelAndView modelAndView = new ModelAndView(template+"/roslogin"); + modelAndView.addObject("param", rosParam); + modelAndView.addObject("joinUrl", joinUrl); + return modelAndView; + } + + + /** + * portal 首页 + * @param rosParam + * @return + */ + @GetMapping("/routeros/status") + public ModelAndView wlanStatusHandler(RouterOSParam rosParam, HttpServletRequest request){ + logger.info(rosParam.getUsername(),"RouterOS 认证状态 "+rosParam.toString(),Memarylogger.PORTAL); + String resultUrl = configService.getStringValue(WLAN_MODULE, Constant.WLAN_RESULT_URL); + if(ValidateUtil.isEmpty(resultUrl)){ + resultUrl = "http://www.baidu.com"; + } + String template = getWlanemplate(); + ModelAndView modelAndView = new ModelAndView(template+"/rosstatus"); + modelAndView.addObject("param", rosParam); + modelAndView.addObject("resultUrl", resultUrl); + return modelAndView; + } + + + + +} diff --git a/src/main/java/org/toughradius/form/RouterOSParam.java b/src/main/java/org/toughradius/form/RouterOSParam.java new file mode 100644 index 00000000..480d17bc --- /dev/null +++ b/src/main/java/org/toughradius/form/RouterOSParam.java @@ -0,0 +1,131 @@ +package org.toughradius.form; + +public class RouterOSParam { + + private String ssid; + private String mac; + private String ip; + private String username; + private String linkLogin; + private String linkLogout; + private String linkStatus; + private String linkOrig; + private Long uptimeSecs; + private Long bytesIn; + private Long bytesOut; + private String error; + + public String getSsid() { + return ssid; + } + + public void setSsid(String ssid) { + this.ssid = ssid; + } + + public String getMac() { + return mac; + } + + public void setMac(String mac) { + this.mac = mac; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getLinkLogin() { + return linkLogin; + } + + public void setLinkLogin(String linkLogin) { + this.linkLogin = linkLogin; + } + + public String getLinkOrig() { + return linkOrig; + } + + public void setLinkOrig(String linkOrig) { + this.linkOrig = linkOrig; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public String getLinkLogout() { + return linkLogout; + } + + public void setLinkLogout(String linkLogout) { + this.linkLogout = linkLogout; + } + + public String getLinkStatus() { + return linkStatus; + } + + public void setLinkStatus(String linkStatus) { + this.linkStatus = linkStatus; + } + + public Long getUptimeSecs() { + return uptimeSecs; + } + + public void setUptimeSecs(Long uptimeSecs) { + this.uptimeSecs = uptimeSecs; + } + + public Long getBytesIn() { + return bytesIn; + } + + public void setBytesIn(Long bytesIn) { + this.bytesIn = bytesIn; + } + + public Long getBytesOut() { + return bytesOut; + } + + public void setBytesOut(Long bytesOut) { + this.bytesOut = bytesOut; + } + + @Override + public String toString() { + return "RouterOSParam{" + + "ssid='" + ssid + '\'' + + ", mac='" + mac + '\'' + + ", ip='" + ip + '\'' + + ", username='" + username + '\'' + + ", linkLogin='" + linkLogin + '\'' + + ", linkLogout='" + linkLogout + '\'' + + ", linkStatus='" + linkStatus + '\'' + + ", linkOrig='" + linkOrig + '\'' + + ", uptimeSecs=" + uptimeSecs + + ", bytesIn=" + bytesIn + + ", bytesOut=" + bytesOut + + ", error='" + error + '\'' + + '}'; + } +} diff --git a/src/main/resources/portal/default/roslogin.html b/src/main/resources/portal/default/roslogin.html new file mode 100644 index 00000000..772b6a21 --- /dev/null +++ b/src/main/resources/portal/default/roslogin.html @@ -0,0 +1,62 @@ + + + + ToughRADIUS Wlan Portal + + + + + + + + + + + + + + + + +
+
+
+
+
+ 用户认证 +
+
+ + +
+
+ + + + + +
+
+ +
+ <#if param.error?? && param.error != ""> + ${param.error!} + +
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/portal/default/rosstatus.html b/src/main/resources/portal/default/rosstatus.html new file mode 100644 index 00000000..23000fcc --- /dev/null +++ b/src/main/resources/portal/default/rosstatus.html @@ -0,0 +1,51 @@ + + + + ToughRADIUS Wlan Portal + + + + + + + + + + + + + + + + +
+
+
+
+ <#if param.error?? && param.error != ""> + ${param.error!} + +
+ + +
+
+
+
+
+ + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/portal/default/static/css/main.css b/src/main/resources/portal/default/static/css/main.css index edd99565..5a939512 100644 --- a/src/main/resources/portal/default/static/css/main.css +++ b/src/main/resources/portal/default/static/css/main.css @@ -1,4 +1,4 @@ - +login100-form-message @@ -226,6 +226,16 @@ iframe { display: block; } + +.login100-form-error { + font-family: Oswald-Medium; + font-size: 14px; + color: #fceb54; + line-height: 1.2; + text-align: center; + display: block; +} + .btn-sms-with { font-family: Oswald-Medium; font-size: 16px; From 5ba51c1c658c6eda5d897461e1fd991fa3ed1ac3 Mon Sep 17 00:00:00 2001 From: jamiesun <âœjamiesun.net@gmail.com> Date: Sun, 2 Jun 2019 13:04:17 +0800 Subject: [PATCH 2/8] config --- changelogs | 52 ------------------- changelogs.md | 35 +++++++++++++ .../toughradius/component/OnlineCache.java | 18 +++++++ .../toughradius/config/AccessInterceptor.java | 48 +++++++++++++++++ .../java/org/toughradius/config/Constant.java | 2 + .../org/toughradius/config/RadsecConfig.java | 31 +++++++---- .../controller/ConfigController.java | 2 + .../controller/OnlineController.java | 9 ++++ .../org/toughradius/form/ApiConfigForm.java | 18 +++++++ .../handler/RadiusAuthHandler.java | 5 ++ src/main/resources/static/admin/config.js | 2 + 11 files changed, 161 insertions(+), 61 deletions(-) delete mode 100644 changelogs create mode 100644 changelogs.md diff --git a/changelogs b/changelogs deleted file mode 100644 index 39176009..00000000 --- a/changelogs +++ /dev/null @@ -1,52 +0,0 @@ -# v6.0.0.1 20190326 - -- developed based on Java & SpringBoot,which implements the standard Radius protocol and supports the extension of Radius protocol. -- Provides the basic management interface - -Radius features - -1. Authentication message: support BAS to initiate Authentication message, use RADIUS protocol to authenticate AAA system - -2. Authentication PAP authentication: PAP authentication is used to support BAS initiating Authentication messages - -3. Authentication CHAP authentication: support BAS to initiate Authentication message using CHAP authentication - -4. Authentication MS CHAP V2 authentication mode: support BAS to initiate Authentication message using MS CHAP V2 authentication mode - -5. Authentication Authorization: After receiving BAS Authentication request message, RADIUS Server encapsulates user authorization information according to user information resources, and authorizes user bandwidth limitation, maximum time, IP and other information to BAS through Authentication response message. - -6. Accounting-On message: Support BAS to initiate Accounting-On message, inform RADIUS that the BAS started successfully and start billing - -7. Accounting-Off message: Support BAS to initiate Accounting-Off message, notify RADIUS that the BAS ends billing, online users unify offline, and BAS enters maintenance or switching status. - -8. Accounting-Start message: Support the standard RADIUS billing message analysis function. BAS initiates the Accounting-Start message and notifies the user to start billing. - -9. Accounting-Interium-Update message: Support the standard RADIUS billing message analysis function. BAS initiates Accounting-Start message to inform users of billing updates. - -10. Accounting-Stop message: Support the standard RADIUS billing message analysis function. BAS initiates the Accounting-Start message to notify users of the end of billing. - -11. Distribution of Maximum Session Length Attribute: Supports sending maximum session length to BAS authentication message, requiring users to go offline within a specified length of time in order to record online records. - -12. User's fixed IP address issuance: support to send IP address information to BAS authentication message. Users use the fixed IP to access the Internet after dialing up, which is suitable for special line users. - -13. Subpooling of user address pool: It supports sending address pool information to BAS authentication message, and users can access the Internet using the address allocated by the address pool after dialing up. - -14. COA Dynamic Authorization: Support the implementation of COA Dynamic Authorization to BRAS system after user authentication, and change the user accounting strategy (requiring BRAS support). - -RADIUS Interface Management - -1. A control panel is provided. - -2. System parameter configuration management - -3. Bras Equipment Intervention Management - -4. User Management - -5. Online User Query - -6. Online Logging Query - -7. System Logging Query - -8. Manage password modification diff --git a/changelogs.md b/changelogs.md new file mode 100644 index 00000000..2f623f4f --- /dev/null +++ b/changelogs.md @@ -0,0 +1,35 @@ +# v6.1.1.2 + +- API 访问控制支持白名单和黑名单 + +# v6.1.1.1 + +- 加入 routeros hostpot wifi 认证支持 + +# v6.1.1.0 + +- 加入radsec 协议支持 + +# v6.1.0.1 + +- 增加无线认证模块,支持帐号,固定密码, 短信,微信连WiFi四种认证模式 +- 增加无线认证的配置模块 +- 增加批量创建用户功能 +- 增加用户模拟拨号测试功能 +- 控制面板扩展,增加认证结果统计,认证耗时统计,在线趋势统计 +- 优化UI界面 +- 修复上一版本的BUG + + +# v6.0.1.1 + +- 数据库结构调整 +- 大量界面调整,添加标签模式 +- 修复以前版本中的错误 +- 内存日志模块优化 + + +# v6.0.0.1 20190326 + +- 基于Java语言重新开发。提供了一个高性能的 RADIUS 处理引擎,同时提供了一个简洁易用的 WEB管理界面,可以轻松上手。 +- [基本功能清单见](https://github.com/talkincode/ToughRADIUS/wiki/features) diff --git a/src/main/java/org/toughradius/component/OnlineCache.java b/src/main/java/org/toughradius/component/OnlineCache.java index f4c70df3..2e39df03 100644 --- a/src/main/java/org/toughradius/component/OnlineCache.java +++ b/src/main/java/org/toughradius/component/OnlineCache.java @@ -516,6 +516,24 @@ public List queryOnlineByIds(String ids){ } + + /** + * 根据用户名强制下线 + */ + public void unlockOnlineByUser(String username) + { + try{ + lock.unLock(); + for (RadiusOnline _online : cacheData.values()) { + if (username.equals(_online.getUsername())) { + asyncUnlockOnline(_online.getAcctSessionId()); + } + } + }finally { + lock.unLock(); + } + } + public int clearOnlineByFilter(String nodeId, Integer invlan,Integer outVlan,String nasAddr, String nasId, String beginTime, String endTime, String keyword){ try{ lock.lock(); diff --git a/src/main/java/org/toughradius/config/AccessInterceptor.java b/src/main/java/org/toughradius/config/AccessInterceptor.java index 2ccdbf0d..2667188e 100644 --- a/src/main/java/org/toughradius/config/AccessInterceptor.java +++ b/src/main/java/org/toughradius/config/AccessInterceptor.java @@ -15,6 +15,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.net.InetAddress; +import java.util.Objects; @Configuration public class AccessInterceptor extends HandlerInterceptorAdapter implements Constant { @@ -34,9 +36,55 @@ public class AccessInterceptor extends HandlerInterceptorAdapter implements Cons @Autowired protected ConfigService cfgService; + private String getIpAddr(HttpServletRequest request) { + String ip = request.getHeader("x-forwarded-for"); + if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + if(ip.equals("127.0.0.1")){ + //根据网卡取本机配置的IP + InetAddress inet=null; + try { + inet = InetAddress.getLocalHost(); + } catch (Exception e) { + e.printStackTrace(); + } + ip= Objects.requireNonNull(inet).getHostAddress(); + } + } + // 多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 + if(ip != null && ip.length() > 15){ + if(ip.indexOf(",")>0){ + ip = ip.substring(0,ip.indexOf(",")); + } + } + return ip; + } + @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + String ip = getIpAddr(request); + + // 白名单检测 + String allows = cfgService.getStringValue(API_MODULE,API_ALLOW_IPLIST); + if(ValidateUtil.isNotEmpty(allows) && allows.contains(ip)){ + return true; + } + + // 黑名单检测 + String blacks = cfgService.getStringValue(API_MODULE,API_BLACK_IPLIST); + if(ValidateUtil.isNotEmpty(blacks) && blacks.contains(ip)){ + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + response.getWriter().print(gson.toJson(new RestResult(1,"Forbidden, black ip " + ip))); + return false; + } + String header = request.getHeader("Authorization"); response.setContentType("application/json;charset=UTF-8"); if(ValidateUtil.isEmpty(header)){ diff --git a/src/main/java/org/toughradius/config/Constant.java b/src/main/java/org/toughradius/config/Constant.java index 6ffd8cc4..718c9911 100644 --- a/src/main/java/org/toughradius/config/Constant.java +++ b/src/main/java/org/toughradius/config/Constant.java @@ -18,6 +18,8 @@ public interface Constant { public final static String API_TYPE = "apiType"; public final static String API_USERNAME = "apiUsername"; public final static String API_PASSWD = "apiPasswd"; + public final static String API_ALLOW_IPLIST = "apiAllowIplist"; + public final static String API_BLACK_IPLIST = "apiBlackIplist"; public final static String SMS_MODULE = "sms"; public final static String SMS_GATEWAY = "smsGateway"; diff --git a/src/main/java/org/toughradius/config/RadsecConfig.java b/src/main/java/org/toughradius/config/RadsecConfig.java index 1a7399b4..7ff8e0e1 100644 --- a/src/main/java/org/toughradius/config/RadsecConfig.java +++ b/src/main/java/org/toughradius/config/RadsecConfig.java @@ -4,7 +4,6 @@ import org.apache.commons.logging.LogFactory; import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder; import org.apache.mina.core.filterchain.IoFilter; -import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.executor.ExecutorFilter; import org.apache.mina.filter.ssl.KeyStoreFactory; import org.apache.mina.filter.ssl.SslContextFactory; @@ -18,8 +17,7 @@ import org.toughradius.handler.RadsecHandler; import javax.net.ssl.SSLContext; -import java.io.File; -import java.io.IOException; +import java.io.*; import java.net.InetSocketAddress; import java.security.KeyStore; import java.util.*; @@ -112,22 +110,34 @@ class SSLContextGenerator public SSLContext getSslContext() { SSLContext sslContext = null; + InputStream infs = null; + ByteArrayOutputStream bos = null; try { + File _keyStoreFile = new File(getKeyStoreFile()); if(!_keyStoreFile.exists()){ - _keyStoreFile = new File(Objects.requireNonNull(SSLContextGenerator.class.getClassLoader().getResource("radsec/server.p12")).toURI()); + infs = SSLContextGenerator.class.getClassLoader().getResourceAsStream("radsec/server.p12"); + }else{ + infs = new FileInputStream(_keyStoreFile); + } + if(infs==null){ + throw new Exception("read keystore error"); + } + bos = new ByteArrayOutputStream(); + byte[] buf = new byte[1024]; + int i = 0; + while ((i = infs.read(buf)) != -1) { + bos.write(buf, 0, i); } - logger.info("Use keyStoreFile: " + _keyStoreFile.getAbsolutePath()); + byte[] cdata = bos.toByteArray(); final KeyStoreFactory keyStoreFactory = new KeyStoreFactory(); - keyStoreFactory.setDataFile(_keyStoreFile); -// keyStoreFactory.setType("PKCS12"); + keyStoreFactory.setData(cdata); keyStoreFactory.setPassword("radsec"); final KeyStoreFactory trustStoreFactory = new KeyStoreFactory(); - trustStoreFactory.setDataFile(_keyStoreFile); -// trustStoreFactory.setType("PKCS12"); + trustStoreFactory.setData(cdata); trustStoreFactory.setPassword("radsec"); final SslContextFactory sslContextFactory = new SslContextFactory(); @@ -143,6 +153,9 @@ public SSLContext getSslContext() catch (Exception ex) { logger.error("getSslContext error",ex); + }finally { + try {if(infs!=null) infs.close(); }catch (Exception ignore){} + try {if(bos!=null) bos.close(); }catch (Exception ignore){} } return sslContext; } diff --git a/src/main/java/org/toughradius/controller/ConfigController.java b/src/main/java/org/toughradius/controller/ConfigController.java index f941fc52..37a314bf 100644 --- a/src/main/java/org/toughradius/controller/ConfigController.java +++ b/src/main/java/org/toughradius/controller/ConfigController.java @@ -97,6 +97,8 @@ public RestResult updateApiConfig(ApiConfigForm form){ configService.updateConfig(new Config(API_MODULE,API_TYPE,form.getApiType())); configService.updateConfig(new Config(API_MODULE,API_USERNAME,form.getApiUsername())); configService.updateConfig(new Config(API_MODULE,API_PASSWD,form.getApiPasswd())); + configService.updateConfig(new Config(API_MODULE,API_ALLOW_IPLIST,form.getApiAllowIplist())); + configService.updateConfig(new Config(API_MODULE,API_BLACK_IPLIST,form.getApiBlackIplist())); }catch(Exception e){ logger.error("update config error",e, Memarylogger.SYSTEM); } diff --git a/src/main/java/org/toughradius/controller/OnlineController.java b/src/main/java/org/toughradius/controller/OnlineController.java index 191b7499..2ae3e3c5 100644 --- a/src/main/java/org/toughradius/controller/OnlineController.java +++ b/src/main/java/org/toughradius/controller/OnlineController.java @@ -45,6 +45,15 @@ public RestResult clearOnlineHandler( String nodeId,Integer invlan, Integer outV onlineCache.clearOnlineByFilter(nodeId,invlan, outVlan,nasAddr,nasId,beginTime,endTime,keyword); return new RestResult(0,"success"); } + + + @GetMapping("/api/v6/online/fc") + public RestResult forceClearOnlineHandler(String username){ + onlineCache.unlockOnlineByUser(username); + return new RestResult(0,"success"); + } + + //一个下线 @GetMapping({"/api/v6/online/delete","/admin/online/delete"}) public RestResult DeleteOnlineHandler(String ids){ diff --git a/src/main/java/org/toughradius/form/ApiConfigForm.java b/src/main/java/org/toughradius/form/ApiConfigForm.java index 6e69b274..053b26ed 100644 --- a/src/main/java/org/toughradius/form/ApiConfigForm.java +++ b/src/main/java/org/toughradius/form/ApiConfigForm.java @@ -5,6 +5,8 @@ public class ApiConfigForm { private String apiType; private String apiUsername; private String apiPasswd; + private String apiAllowIplist; + private String apiBlackIplist; public String getApiType() { return apiType; @@ -29,4 +31,20 @@ public String getApiPasswd() { public void setApiPasswd(String apiPasswd) { this.apiPasswd = apiPasswd; } + + public String getApiAllowIplist() { + return apiAllowIplist; + } + + public void setApiAllowIplist(String apiAllowIplist) { + this.apiAllowIplist = apiAllowIplist; + } + + public String getApiBlackIplist() { + return apiBlackIplist; + } + + public void setApiBlackIplist(String apiBlackIplist) { + this.apiBlackIplist = apiBlackIplist; + } } diff --git a/src/main/java/org/toughradius/handler/RadiusAuthHandler.java b/src/main/java/org/toughradius/handler/RadiusAuthHandler.java index ba7319f5..27b2bc13 100644 --- a/src/main/java/org/toughradius/handler/RadiusAuthHandler.java +++ b/src/main/java/org/toughradius/handler/RadiusAuthHandler.java @@ -12,11 +12,14 @@ import java.net.InetSocketAddress; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; @Component public class RadiusAuthHandler extends RadiusBasicHandler { + /** * 异常处理 * @param session @@ -100,6 +103,8 @@ public void messageReceived(IoSession session, Object message) } int cast = (int) (System.currentTimeMillis()-start); radiusCastStat.updateAuth(cast); + + } } diff --git a/src/main/resources/static/admin/config.js b/src/main/resources/static/admin/config.js index 08acfbdd..e5539b05 100644 --- a/src/main/resources/static/admin/config.js +++ b/src/main/resources/static/admin/config.js @@ -168,6 +168,8 @@ toughradius.admin.config.loadPage = function(session){ {view: "richselect", name: "apiType", label: "API 类型:",value:"basic", options:[{id:"basic",value:"Basic"}]}, {view: "text", name: "apiUsername", label: "Basic 用户"}, {view: "text", type:"password", name: "apiPasswd", label: "Basic 密码"}, + {view: "text", name: "apiAllowIplist", label: "IP 白名单"}, + {view: "text", name: "apiBlackIplist", label: "IP 黑名单"} ] }}, { From 4f08d27ca25f218712ffabd6efd839889220562d Mon Sep 17 00:00:00 2001 From: jamiesun <âœjamiesun.net@gmail.com> Date: Mon, 10 Jun 2019 12:51:45 +0800 Subject: [PATCH 3/8] wlan cookie --- genkey.sh | 25 ------ scripts/startup.bat | 2 +- .../org/toughradius/common/CookieUtils.java | 34 ++++++++ .../java/org/toughradius/config/Constant.java | 3 + .../controller/PortalController.java | 84 +++++++++++++++---- .../java/org/toughradius/form/WlanParam.java | 12 +++ .../handler/RadiusAcceptFilter.java | 17 ++++ .../toughradius/handler/RadiusConstant.java | 2 +- .../resources/portal/default/pwdauth.html | 6 +- .../portal/default/static/css/main.css | 7 ++ .../portal/default/static/css/util.css | 2 + .../resources/portal/default/userauth.html | 4 +- src/main/resources/radius_dictionary | 8 +- src/main/resources/static/admin/constant.js | 1 + 14 files changed, 158 insertions(+), 49 deletions(-) delete mode 100644 genkey.sh create mode 100644 src/main/java/org/toughradius/common/CookieUtils.java diff --git a/genkey.sh b/genkey.sh deleted file mode 100644 index b444d3d3..00000000 --- a/genkey.sh +++ /dev/null @@ -1,25 +0,0 @@ - -#生成服务器端证书 - -keytool -genkey -keyalg RSA -dname “cn=toughstruct,ou=toughstruct,o=toughstruct,l=cs,st=hn,c=cn” -alias server -storetype PKCS12 -keypass radsec -keystore server.jks -storepass radsec -validity 3650 - - - -# 生成客户端证书 - -keytool -genkey -keyalg RSA -dname “cn=toughstruct,ou=toughstruct,o=toughstruct,l=cs,st=hn,c=cn” -alias client -storetype PKCS12 -keypass radsec -keystore client.p12 -storepass radsec -validity 3650 - -keytool -export -alias client -file client.cer -keystore client.p12 -storepass radsec -storetype PKCS12 -rfc - - -#添加客户端证书到服务器中(将已签名数字证书导入密钥库) - -keytool -import -v -alias client -file client.cer -keystore server.jks -storepass radsec - - - - - - - - diff --git a/scripts/startup.bat b/scripts/startup.bat index f619e745..63b92c99 100644 --- a/scripts/startup.bat +++ b/scripts/startup.bat @@ -1 +1 @@ -java -jar -Xms256m -Xmx1024G toughradius-latest.jar --spring.profiles.active=prod \ No newline at end of file +java -jar -Xms256m -Xmx1024M toughradius-latest.jar --spring.profiles.active=prod \ No newline at end of file diff --git a/src/main/java/org/toughradius/common/CookieUtils.java b/src/main/java/org/toughradius/common/CookieUtils.java new file mode 100644 index 00000000..1b31feb0 --- /dev/null +++ b/src/main/java/org/toughradius/common/CookieUtils.java @@ -0,0 +1,34 @@ +package org.toughradius.common; +import org.toughradius.common.coder.Encypt; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class CookieUtils { + + public static String getCookie(HttpServletRequest request,String cookieName){ + Cookie[] cookies = request.getCookies(); + String ename = Encypt.encrypt(cookieName); + if(cookies != null){ + for(Cookie cookie : cookies){ + if(cookie.getName().equals(ename)){ + return Encypt.decrypt(cookie.getValue()); + } + } + } + return null; + } + + + + public static void writeCookie(HttpServletResponse response, String cookieName,String value){ + Cookie cookie = new Cookie(Encypt.encrypt(cookieName),Encypt.encrypt(value)); + cookie.setPath("/"); + cookie.setMaxAge(86400*30); + response.addCookie(cookie); + } + + + +} diff --git a/src/main/java/org/toughradius/config/Constant.java b/src/main/java/org/toughradius/config/Constant.java index 718c9911..11e158e8 100644 --- a/src/main/java/org/toughradius/config/Constant.java +++ b/src/main/java/org/toughradius/config/Constant.java @@ -1,5 +1,7 @@ package org.toughradius.config; +import org.toughradius.common.CoderUtil; + public interface Constant { public static final String SESSION_USER_KEY = "SESSION_USER_KEY"; @@ -45,4 +47,5 @@ public interface Constant { public final static String PORTAL_AUTH_PASSWORD = "pwdauth"; public final static String PORTAL_AUTH_SMS = "smsauth"; public final static String PORTAL_AUTH_WEIXIN = "wxauth"; + public final static String PORTAL_REMBERPWD_COOKIE = "PORTAL_REMBERPWD_COOKIE"; } diff --git a/src/main/java/org/toughradius/controller/PortalController.java b/src/main/java/org/toughradius/controller/PortalController.java index 5ea08c8c..10d8fff3 100644 --- a/src/main/java/org/toughradius/controller/PortalController.java +++ b/src/main/java/org/toughradius/controller/PortalController.java @@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import org.toughradius.common.*; +import org.toughradius.common.coder.Encypt; import org.toughradius.component.*; import org.toughradius.config.Constant; import org.toughradius.config.PortalConfig; @@ -125,7 +126,16 @@ public ModelAndView wlanIndexHandler(WlanParam wlanParam,HttpServletRequest requ * @return */ @GetMapping("/wlan/login") - public ModelAndView wlanLoginHandler(WlanParam wlanParam,HttpServletRequest request){ + public ModelAndView wlanLoginHandler(WlanParam wlanParam,HttpSession session,HttpServletRequest request,HttpServletResponse response){ + String autoAuthUsername = CookieUtils.getCookie(request,wlanParam.getWlanusermac()); + if(ValidateUtil.isNotEmpty(autoAuthUsername)){ + Subscribe subs = subscribeCache.findSubscribe(autoAuthUsername); + if(subs!=null){ + wlanParam.setUsername(subs.getSubscriber()); + return authAuthAction(session,request,response,wlanParam,subs); + } + } + ModelAndView modelAndView = new ModelAndView(getWlanemplate()+"/"+wlanParam.getAuthmode()); wlanParam.setSrcacip(request.getRemoteAddr()); modelAndView.addObject("param", wlanParam); @@ -133,6 +143,37 @@ public ModelAndView wlanLoginHandler(WlanParam wlanParam,HttpServletRequest requ return modelAndView; } + + /** + * 自动认证 + * @param session + * @param request + * @param param + * @return + */ + public ModelAndView authAuthAction(HttpSession session, HttpServletRequest request, HttpServletResponse response, WlanParam param, + Subscribe subscribe){ + ModelAndView modelAndView = new ModelAndView(getWlanemplate()+"/result"); + modelAndView.addObject("param",param); + // 预处理参数 + if(ValidateUtil.isEmpty(param.getWlanuserfirsturl())){ + if(ValidateUtil.isNotEmpty(param.getUrl())){ + param.setWlanuserfirsturl(param.getUrl()); + } + } + setResultUrl(param); + + // 查找 AC 设备 + Bras nas = null; + try { + nas = brasService.findBras(param.getWlanacip(),param.getSrcacip(),param.getWlanacname()); + } catch (ServiceException e) { + return processModel(modelAndView,param.getUsername(), MODEL_FAIL,"接入设备不存在"); + } + return userPwdAuth(session, request, response, param, nas, subscribe.getPassword()); + } + + private ModelAndView processModel(ModelAndView mv, String username, String code, String message){ mv.addObject("code",code); mv.addObject("username",username); @@ -154,7 +195,8 @@ private ModelAndView processModel(ModelAndView mv, String username, String code, * @return */ @PostMapping("/wlan/login") - public ModelAndView wlanLoginPostHandler(HttpSession session,HttpServletRequest request, WlanParam param, String password){ + public ModelAndView wlanLoginPostHandler(HttpSession session,HttpServletRequest request,HttpServletResponse response, WlanParam param, + String password){ ModelAndView modelAndView = new ModelAndView(getWlanemplate()+"/result"); modelAndView.addObject("param",param); // 预处理参数 @@ -178,22 +220,22 @@ public ModelAndView wlanLoginPostHandler(HttpSession session,HttpServletRequest //用户密码认证 if(PORTAL_AUTH_USERPWD.equals(authMode)){ - return userPwdAuth(session, request, param, nas, password); + return userPwdAuth(session, request,response, param, nas, password); } //固定密码认证 if(PORTAL_AUTH_PASSWORD.equals(authMode)){ - return passwordAuth(session, request, param,nas, password); + return passwordAuth(session, request,response, param,nas, password); } //微信认证 if(PORTAL_AUTH_WEIXIN.equals(authMode)){ - return weixinAuth(session, request, param, nas); + return weixinAuth(session, request,response, param, nas); } //短信认证 if(PORTAL_AUTH_SMS.equals(authMode)){ - return smsAuth(session, request, param, nas); + return smsAuth(session, request, response, param, nas); } return processModel(modelAndView,param.getUsername(), MODEL_FAIL,"不支持的认证模式"); } @@ -207,7 +249,8 @@ public ModelAndView wlanLoginPostHandler(HttpSession session,HttpServletRequest * @param password * @return */ - private ModelAndView userPwdAuth(HttpSession session, HttpServletRequest request, WlanParam param, Bras nas,String password){ + private ModelAndView userPwdAuth(HttpSession session, HttpServletRequest request,HttpServletResponse response, WlanParam param, Bras nas, + String password){ ModelAndView mv = new ModelAndView(getWlanemplate()+"/result"); mv.addObject("param",param); if(ValidateUtil.isEmpty(param.getUsername())){ @@ -217,7 +260,7 @@ private ModelAndView userPwdAuth(HttpSession session, HttpServletRequest request return processModel(mv,param.getUsername(), MODEL_FAIL,"密码不能为空"); } setResultUrl(param); - return doPortalAuth(session, request, mv, param, nas, param.getUsername(), password); + return doPortalAuth(session, request, response, mv, param, nas, param.getUsername(), password); } /** @@ -229,7 +272,8 @@ private ModelAndView userPwdAuth(HttpSession session, HttpServletRequest request * @param password * @return */ - private ModelAndView passwordAuth(HttpSession session,HttpServletRequest request, WlanParam param,Bras nas, String password){ + private ModelAndView passwordAuth(HttpSession session,HttpServletRequest request,HttpServletResponse response, WlanParam param,Bras nas, + String password){ ModelAndView mv = new ModelAndView(getWlanemplate()+"/result"); mv.addObject("param",param); if(ValidateUtil.isEmpty(password)){ @@ -239,7 +283,7 @@ private ModelAndView passwordAuth(HttpSession session,HttpServletRequest request subscribeCache.createTempSubscribe(username,password,1); param.setUsername(username); setResultUrl(param); - return doPortalAuth(session, request, mv, param, nas, username, password); + return doPortalAuth(session, request, response, mv, param, nas, username, password); } /** @@ -250,7 +294,7 @@ private ModelAndView passwordAuth(HttpSession session,HttpServletRequest request * @param nas * @return */ - private ModelAndView weixinAuth(HttpSession session, HttpServletRequest request, WlanParam param, Bras nas){ + private ModelAndView weixinAuth(HttpSession session, HttpServletRequest request,HttpServletResponse response, WlanParam param, Bras nas){ ModelAndView mv = new ModelAndView(getWlanemplate()+"/weixin"); mv.addObject("param",param); String username = "wxu_"+ CoderUtil.random16str(); @@ -278,7 +322,7 @@ private ModelAndView weixinAuth(HttpSession session, HttpServletRequest request, mv.addObject("bssid",param.getWlanapmac()); mv.addObject("sign",sign); setResultUrl(param); - return doPortalAuth(session, request, mv, param, nas, username, password); + return doPortalAuth(session, request, response, mv, param, nas, username, password); } /** @@ -311,7 +355,7 @@ public void wechatCallback(HttpServletRequest request,HttpServletResponse respon * @param nas * @return */ - private ModelAndView smsAuth(HttpSession session,HttpServletRequest request, WlanParam param,Bras nas){ + private ModelAndView smsAuth(HttpSession session,HttpServletRequest request, HttpServletResponse response,WlanParam param,Bras nas){ ModelAndView mv = new ModelAndView(getWlanemplate()+"/result"); mv.addObject("param",param); String phone = param.getPhone(); @@ -345,7 +389,7 @@ private ModelAndView smsAuth(HttpSession session,HttpServletRequest request, Wla } param.setUsername(username); setResultUrl(param); - return doPortalAuth(session, request, mv, param, nas, username, password); + return doPortalAuth(session, request,response, mv, param, nas, username, password); } /** @@ -390,7 +434,8 @@ public RestResult sendSms(String phone)throws ServiceException{ * @param password * @return */ - private ModelAndView doPortalAuth(HttpSession session,HttpServletRequest request,ModelAndView mv, WlanParam param, Bras nas, String username, String password){ + private ModelAndView doPortalAuth(HttpSession session,HttpServletRequest request,HttpServletResponse response,ModelAndView mv, WlanParam param, + Bras nas, String username, String password){ //认证参数 String userIp = param.getWlanuserip(); String secret = nas.getSecret(); @@ -438,7 +483,7 @@ private ModelAndView doPortalAuth(HttpSession session,HttpServletRequest request logger.info(username, String.format("<< 接收到 ACK_AUTH <- %s: %s", basip, authResp.toString()),Memarylogger.PORTAL); if(authResp.getErrCode()>0){ if(authResp.getErrCode()==2){ - authSucess(session,param); + authSucess(session,response,param); return processModel(mv,username, MODEL_OK,"认证成功"); }else{ return processModel(mv,username, MODEL_FAIL,authResp.getErrMessage()+authResp.getTextInfo() ); @@ -461,7 +506,7 @@ private ModelAndView doPortalAuth(HttpSession session,HttpServletRequest request logger.error(username,"发送 AFF_ACK_AUTH 错误",e,Memarylogger.PORTAL); } - authSucess(session,param); + authSucess(session,response,param); return processModel(mv,username, MODEL_OK,"认证成功"); } @@ -472,11 +517,14 @@ private ModelAndView doPortalAuth(HttpSession session,HttpServletRequest request * @param param * @return */ - private void authSucess(HttpSession session,WlanParam param){ + private void authSucess(HttpSession session,HttpServletResponse response,WlanParam param){ WlanSession wss = new WlanSession(); wss.setWlanParam(param); wss.setLoginStatus(1); session.setAttribute(WLAN_SESSION_KEY,wss); + if("enabled".equals(param.getRememberPwd())){ + CookieUtils.writeCookie(response,PORTAL_REMBERPWD_COOKIE, param.getUsername()); + } } /** diff --git a/src/main/java/org/toughradius/form/WlanParam.java b/src/main/java/org/toughradius/form/WlanParam.java index e1809a35..49159a33 100644 --- a/src/main/java/org/toughradius/form/WlanParam.java +++ b/src/main/java/org/toughradius/form/WlanParam.java @@ -24,6 +24,7 @@ public class WlanParam { private String srcacip; private String phone; private String smscode; + private String rememberPwd; private long starttime; private boolean rmflag; @@ -213,6 +214,14 @@ public void setRmflag(boolean rmflag) { this.rmflag = rmflag; } + public String getRememberPwd() { + return rememberPwd; + } + + public void setRememberPwd(String rememberPwd) { + this.rememberPwd = rememberPwd; + } + public String encodeParams() { StringBuilder buff = new StringBuilder(); buff.append(String.format("wlanuserip=%s&", emptyStr(wlanuserip))); @@ -248,6 +257,9 @@ public String toString() { ", srcacip='" + srcacip + '\'' + ", phone='" + phone + '\'' + ", smscode='" + smscode + '\'' + + ", rememberPwd='" + rememberPwd + '\'' + + ", starttime=" + starttime + + ", rmflag=" + rmflag + '}'; } diff --git a/src/main/java/org/toughradius/handler/RadiusAcceptFilter.java b/src/main/java/org/toughradius/handler/RadiusAcceptFilter.java index 7dc1afc1..024e30b7 100644 --- a/src/main/java/org/toughradius/handler/RadiusAcceptFilter.java +++ b/src/main/java/org/toughradius/handler/RadiusAcceptFilter.java @@ -29,6 +29,8 @@ public class RadiusAcceptFilter implements RadiusConstant{ public AccessAccept doFilter(AccessAccept accept, Bras nas, Subscribe user){ accept = filterDefault(accept,user, nas); switch (nas.getVendorId()){ + case VENDOR_TOUGHSOCKS: + return filterToughSocks(accept, user); case VENDOR_MIKROTIK: return filterMikrotik(accept, user); case VENDOR_IKUAI: @@ -98,6 +100,21 @@ private AccessAccept filterMikrotik(AccessAccept accept, Subscribe user){ return accept; } + /** + * Toughsocks 属性下发 + * @param accept + * @param user + * @return + */ + private AccessAccept filterToughSocks(AccessAccept accept, Subscribe user){ + long up = user.getUpRate() * 1024; + long down = user.getDownRate() * 1024; + accept.addAttribute("ToughSocks-Up-Limit", String.valueOf(up)); + accept.addAttribute("ToughSocks-Down-Limit", String.valueOf(down)); + accept.addAttribute("ToughSocks-Max-Session", String.valueOf(user.getActiveNum())); + return accept; + } + private AccessAccept filterIkuai(AccessAccept accept, Subscribe user){ long up = user.getUpRate() * 1024 * 8; diff --git a/src/main/java/org/toughradius/handler/RadiusConstant.java b/src/main/java/org/toughradius/handler/RadiusConstant.java index 2f6fcf0a..5384f732 100644 --- a/src/main/java/org/toughradius/handler/RadiusConstant.java +++ b/src/main/java/org/toughradius/handler/RadiusConstant.java @@ -2,6 +2,7 @@ public interface RadiusConstant { + public final static String VENDOR_TOUGHSOCKS = "18168"; public final static String VENDOR_MIKROTIK = "14988"; public final static String VENDOR_IKUAI = "10055"; public final static String VENDOR_HUAWEI = "2011"; @@ -10,5 +11,4 @@ public interface RadiusConstant { public final static String VENDOR_RADBACK = "2352"; public final static String VENDOR_CISCO = "9"; - } diff --git a/src/main/resources/portal/default/pwdauth.html b/src/main/resources/portal/default/pwdauth.html index b3091917..d4b54269 100644 --- a/src/main/resources/portal/default/pwdauth.html +++ b/src/main/resources/portal/default/pwdauth.html @@ -32,8 +32,10 @@ - -
+
+ 记住密码
+
+
diff --git a/src/main/resources/portal/default/static/css/main.css b/src/main/resources/portal/default/static/css/main.css index 5a939512..2185d214 100644 --- a/src/main/resources/portal/default/static/css/main.css +++ b/src/main/resources/portal/default/static/css/main.css @@ -523,4 +523,11 @@ iframe { .wrap-login100 { padding-top: 20px } +} + +.checkboxDiv{ + color: white; + font-weight: 600; + font-size: 14px; + padding-left: 20px; } \ No newline at end of file diff --git a/src/main/resources/portal/default/static/css/util.css b/src/main/resources/portal/default/static/css/util.css index 44d41a4d..99d6b986 100644 --- a/src/main/resources/portal/default/static/css/util.css +++ b/src/main/resources/portal/default/static/css/util.css @@ -2991,3 +2991,5 @@ + + diff --git a/src/main/resources/portal/default/userauth.html b/src/main/resources/portal/default/userauth.html index e8371c4a..589e4611 100644 --- a/src/main/resources/portal/default/userauth.html +++ b/src/main/resources/portal/default/userauth.html @@ -36,7 +36,9 @@
- +
+ 记住密码
+