From bfc70f58f9977dc74baf70c220b8a97be54bfff0 Mon Sep 17 00:00:00 2001 From: CaptainB Date: Thu, 14 Sep 2023 13:56:21 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=89=A7=E8=A1=8C=E6=9C=BA?= =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E8=B5=84=E6=BA=90=E6=97=B6=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?totp=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../metersphere/sdk/config/ShiroConfig.java | 4 ++ .../metersphere/sdk/security/TotpFilter.java | 38 +++++++++++++++++++ .../sdk/util/FilterChainUtils.java | 10 ++++- 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 backend/framework/sdk/src/main/java/io/metersphere/sdk/security/TotpFilter.java diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/config/ShiroConfig.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/config/ShiroConfig.java index bf798725bc..3518d93f63 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/config/ShiroConfig.java +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/config/ShiroConfig.java @@ -4,6 +4,7 @@ package io.metersphere.sdk.config; import io.metersphere.sdk.security.ApiKeyFilter; import io.metersphere.sdk.security.CsrfFilter; import io.metersphere.sdk.security.MsPermissionAnnotationMethodInterceptor; +import io.metersphere.sdk.security.TotpFilter; import io.metersphere.sdk.security.realm.LocalRealm; import io.metersphere.sdk.util.FilterChainUtils; import jakarta.servlet.DispatcherType; @@ -42,10 +43,13 @@ public class ShiroConfig { shiroFilterFactoryBean.getFilters().put("apikey", new ApiKeyFilter()); shiroFilterFactoryBean.getFilters().put("csrf", new CsrfFilter()); + shiroFilterFactoryBean.getFilters().put("totp", new TotpFilter()); Map filterChainDefinitionMap = shiroFilterFactoryBean.getFilterChainDefinitionMap(); filterChainDefinitionMap.putAll(FilterChainUtils.loadBaseFilterChain()); + filterChainDefinitionMap.putAll(FilterChainUtils.totpFilterChain()); + filterChainDefinitionMap.putAll(FilterChainUtils.ignoreCsrfFilter()); filterChainDefinitionMap.put("/**", "apikey, csrf, authc"); diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/security/TotpFilter.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/security/TotpFilter.java new file mode 100644 index 0000000000..ee016f6937 --- /dev/null +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/security/TotpFilter.java @@ -0,0 +1,38 @@ +package io.metersphere.sdk.security; + + +import com.bastiaanjansen.otp.TOTPGenerator; +import io.metersphere.sdk.constants.MsHttpHeaders; +import io.metersphere.sdk.util.CommonBeanFactory; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import org.apache.commons.lang.StringUtils; +import org.apache.shiro.web.filter.authc.AnonymousFilter; +import org.apache.shiro.web.util.WebUtils; + +public class TotpFilter extends AnonymousFilter { + + @Override + protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) { + HttpServletRequest httpServletRequest = WebUtils.toHttp(request); + + // 请求头取出的token value + String token = httpServletRequest.getHeader(MsHttpHeaders.OTP_TOKEN); + // 校验 token + validateToken(token); + + return true; + } + + private void validateToken(String token) { + if (StringUtils.isBlank(token)) { + throw new RuntimeException("token is empty"); + } + + TOTPGenerator totpGenerator = CommonBeanFactory.getBean(TOTPGenerator.class); + if (!totpGenerator.verify(token)) { + throw new RuntimeException("token is not valid"); + } + } +} diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/FilterChainUtils.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/FilterChainUtils.java index 0d5bd3dd2e..dda6d055e7 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/FilterChainUtils.java +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/FilterChainUtils.java @@ -22,9 +22,8 @@ public class FilterChainUtils { filterChainDefinitionMap.put("/display/info", "anon"); filterChainDefinitionMap.put("/favicon.ico", "anon"); filterChainDefinitionMap.put("/base-display/**", "anon"); - filterChainDefinitionMap.put("/jmeter/download/**", "anon"); filterChainDefinitionMap.put("/jmeter/ping", "anon"); - filterChainDefinitionMap.put("/jmeter/ready/**", "anon"); + filterChainDefinitionMap.put("/jmeter/ready/**", "totp"); filterChainDefinitionMap.put("/authsource/list/allenable", "anon"); filterChainDefinitionMap.put("/sso/callback/**", "anon"); filterChainDefinitionMap.put("/license/validate", "anon"); @@ -72,4 +71,11 @@ public class FilterChainUtils { filterChainDefinitionMap.put("/mock", "apikey, authc"); // 跳转到 /mock接口 不用校验 csrf return filterChainDefinitionMap; } + + public static Map totpFilterChain() { + Map filterChainDefinitionMap = new HashMap<>(); + // 执行机下载执行资源需要验证totp + filterChainDefinitionMap.put("/jmeter/download/**", "totp"); + return filterChainDefinitionMap; + } }