Showing
4 changed files
with
113 additions
and
7 deletions
... | ... | @@ -52,6 +52,7 @@ import org.thingsboard.server.service.security.auth.oauth2.HttpCookieOAuth2Autho |
52 | 52 | import org.thingsboard.server.service.security.auth.rest.RestAuthenticationProvider; |
53 | 53 | import org.thingsboard.server.service.security.auth.rest.RestLoginProcessingFilter; |
54 | 54 | import org.thingsboard.server.service.security.auth.rest.RestPublicLoginProcessingFilter; |
55 | +import org.thingsboard.server.service.security.auth.yunteng.CodeLoginProcessingFilter; | |
55 | 56 | |
56 | 57 | import java.util.ArrayList; |
57 | 58 | import java.util.Arrays; |
... | ... | @@ -70,9 +71,10 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt |
70 | 71 | public static final String WEBJARS_ENTRY_POINT = "/webjars/**"; |
71 | 72 | public static final String DEVICE_API_ENTRY_POINT = "/api/v1/**"; |
72 | 73 | public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/api/auth/login"; |
74 | + public static final String CODE_BASED_LOGIN_ENTRY_POINT = "/api/yt/auth/code/login"; | |
73 | 75 | public static final String PUBLIC_LOGIN_ENTRY_POINT = "/api/auth/login/public"; |
74 | 76 | public static final String TOKEN_REFRESH_ENTRY_POINT = "/api/auth/token"; |
75 | - protected static final String[] NON_TOKEN_BASED_AUTH_ENTRY_POINTS = new String[] {"/index.html", "/assets/**", "/static/**", "/api/noauth/**", "/webjars/**", "/api/license/**"}; | |
77 | + protected static final String[] NON_TOKEN_BASED_AUTH_ENTRY_POINTS = new String[] {"/index.html", "/assets/**", "/static/**", "/api/noauth/**", "/webjars/**", "/api/license/**", "/api/yt/noauth/**"}; | |
76 | 78 | public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**"; |
77 | 79 | public static final String WS_TOKEN_BASED_AUTH_ENTRY_POINT = "/api/ws/**"; |
78 | 80 | |
... | ... | @@ -125,6 +127,13 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt |
125 | 127 | } |
126 | 128 | |
127 | 129 | @Bean |
130 | + protected CodeLoginProcessingFilter buildSmsCodeLoginProcessingFilter() throws Exception{ | |
131 | + CodeLoginProcessingFilter filter = new CodeLoginProcessingFilter(CODE_BASED_LOGIN_ENTRY_POINT, successHandler, failureHandler, objectMapper); | |
132 | + filter.setAuthenticationManager(this.authenticationManager); | |
133 | + return filter; | |
134 | + } | |
135 | + | |
136 | + @Bean | |
128 | 137 | protected RestPublicLoginProcessingFilter buildRestPublicLoginProcessingFilter() throws Exception { |
129 | 138 | RestPublicLoginProcessingFilter filter = new RestPublicLoginProcessingFilter(PUBLIC_LOGIN_ENTRY_POINT, successHandler, failureHandler, objectMapper); |
130 | 139 | filter.setAuthenticationManager(this.authenticationManager); |
... | ... | @@ -133,7 +142,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt |
133 | 142 | |
134 | 143 | protected JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter() throws Exception { |
135 | 144 | List<String> pathsToSkip = new ArrayList<>(Arrays.asList(NON_TOKEN_BASED_AUTH_ENTRY_POINTS)); |
136 | - pathsToSkip.addAll(Arrays.asList(WS_TOKEN_BASED_AUTH_ENTRY_POINT, TOKEN_REFRESH_ENTRY_POINT, FORM_BASED_LOGIN_ENTRY_POINT, | |
145 | + pathsToSkip.addAll(Arrays.asList(WS_TOKEN_BASED_AUTH_ENTRY_POINT, TOKEN_REFRESH_ENTRY_POINT, FORM_BASED_LOGIN_ENTRY_POINT,CODE_BASED_LOGIN_ENTRY_POINT, | |
137 | 146 | PUBLIC_LOGIN_ENTRY_POINT, DEVICE_API_ENTRY_POINT, WEBJARS_ENTRY_POINT)); |
138 | 147 | SkipPathRequestMatcher matcher = new SkipPathRequestMatcher(pathsToSkip, TOKEN_BASED_AUTH_ENTRY_POINT); |
139 | 148 | JwtTokenAuthenticationProcessingFilter filter |
... | ... | @@ -200,6 +209,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt |
200 | 209 | .antMatchers(WEBJARS_ENTRY_POINT).permitAll() // Webjars |
201 | 210 | .antMatchers(DEVICE_API_ENTRY_POINT).permitAll() // Device HTTP Transport API |
202 | 211 | .antMatchers(FORM_BASED_LOGIN_ENTRY_POINT).permitAll() // Login end-point |
212 | + .antMatchers(CODE_BASED_LOGIN_ENTRY_POINT).permitAll() // SmsCode Login end-point | |
203 | 213 | .antMatchers(PUBLIC_LOGIN_ENTRY_POINT).permitAll() // Public login end-point |
204 | 214 | .antMatchers(TOKEN_REFRESH_ENTRY_POINT).permitAll() // Token refresh end-point |
205 | 215 | .antMatchers(NON_TOKEN_BASED_AUTH_ENTRY_POINTS).permitAll() // static resources, user activation and password reset end-points |
... | ... | @@ -211,6 +221,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt |
211 | 221 | .exceptionHandling().accessDeniedHandler(restAccessDeniedHandler) |
212 | 222 | .and() |
213 | 223 | .addFilterBefore(buildRestLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class) |
224 | + .addFilterBefore(buildSmsCodeLoginProcessingFilter(),UsernamePasswordAuthenticationFilter.class) | |
214 | 225 | .addFilterBefore(buildRestPublicLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class) |
215 | 226 | .addFilterBefore(buildJwtTokenAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class) |
216 | 227 | .addFilterBefore(buildRefreshTokenProcessingFilter(), UsernamePasswordAuthenticationFilter.class) | ... | ... |
1 | +package org.thingsboard.server.service.security.auth.yunteng; | |
2 | + | |
3 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
4 | +import lombok.extern.slf4j.Slf4j; | |
5 | +import org.apache.commons.lang3.StringUtils; | |
6 | +import org.springframework.http.HttpMethod; | |
7 | +import org.springframework.security.authentication.AuthenticationServiceException; | |
8 | +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | |
9 | +import org.springframework.security.core.Authentication; | |
10 | +import org.springframework.security.core.AuthenticationException; | |
11 | +import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; | |
12 | +import org.springframework.security.web.authentication.AuthenticationFailureHandler; | |
13 | +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; | |
14 | +import org.thingsboard.server.common.data.yunteng.dto.request.CodeLoginRequest; | |
15 | +import org.thingsboard.server.service.security.exception.AuthMethodNotSupportedException; | |
16 | +import org.thingsboard.server.service.security.model.UserPrincipal; | |
17 | + | |
18 | +import javax.servlet.FilterChain; | |
19 | +import javax.servlet.ServletException; | |
20 | +import javax.servlet.http.HttpServletRequest; | |
21 | +import javax.servlet.http.HttpServletResponse; | |
22 | +import java.io.IOException; | |
23 | + | |
24 | +@Slf4j | |
25 | +public class CodeLoginProcessingFilter extends AbstractAuthenticationProcessingFilter { | |
26 | + | |
27 | + private final AuthenticationSuccessHandler successHandler; | |
28 | + private final AuthenticationFailureHandler failureHandler; | |
29 | + private final ObjectMapper objectMapper; | |
30 | + | |
31 | + public CodeLoginProcessingFilter( | |
32 | + String defaultProcessUrl, | |
33 | + AuthenticationSuccessHandler successHandler, | |
34 | + AuthenticationFailureHandler failureHandler, | |
35 | + ObjectMapper mapper) { | |
36 | + super(defaultProcessUrl); | |
37 | + this.successHandler = successHandler; | |
38 | + this.failureHandler = failureHandler; | |
39 | + this.objectMapper = mapper; | |
40 | + } | |
41 | + | |
42 | + @Override | |
43 | + public Authentication attemptAuthentication( | |
44 | + HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { | |
45 | + if (!HttpMethod.POST.name().equals(request.getMethod())) { | |
46 | + if (log.isDebugEnabled()) { | |
47 | + log.debug("Authentication method not supported. Request method: " + request.getMethod()); | |
48 | + } | |
49 | + throw new AuthMethodNotSupportedException("Authentication method not supported"); | |
50 | + } | |
51 | + CodeLoginRequest loginRequest; | |
52 | + try { | |
53 | + loginRequest = objectMapper.readValue(request.getReader(), CodeLoginRequest.class); | |
54 | + } catch (Exception e) { | |
55 | + throw new AuthenticationServiceException("Invalid login request payload"); | |
56 | + } | |
57 | + if (StringUtils.isBlank(loginRequest.getCode()) | |
58 | + || StringUtils.isBlank(loginRequest.getPhoneNumber())) { | |
59 | + throw new AuthenticationServiceException("phone number or sms code not provided"); | |
60 | + } | |
61 | + UserPrincipal principal = | |
62 | + new UserPrincipal(UserPrincipal.Type.SMS_CODE, loginRequest.getPhoneNumber()); | |
63 | + UsernamePasswordAuthenticationToken token = | |
64 | + new UsernamePasswordAuthenticationToken(principal, loginRequest.getCode()); | |
65 | + token.setDetails(authenticationDetailsSource.buildDetails(request)); | |
66 | + return this.getAuthenticationManager().authenticate(token); | |
67 | + } | |
68 | + | |
69 | + @Override | |
70 | + protected void successfulAuthentication( | |
71 | + HttpServletRequest request, | |
72 | + HttpServletResponse response, | |
73 | + FilterChain chain, | |
74 | + Authentication authResult) | |
75 | + throws IOException, ServletException { | |
76 | + successHandler.onAuthenticationSuccess(request, response, chain, authResult); | |
77 | + } | |
78 | + | |
79 | + @Override | |
80 | + protected void unsuccessfulAuthentication( | |
81 | + HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) | |
82 | + throws IOException, ServletException { | |
83 | + failureHandler.onAuthenticationFailure(request, response, failed); | |
84 | + } | |
85 | +} | ... | ... |
... | ... | @@ -423,6 +423,15 @@ caffeine: |
423 | 423 | edges: |
424 | 424 | timeToLiveInMinutes: 1440 |
425 | 425 | maxSize: 10000 |
426 | + yunTengIotCache: | |
427 | + timeToLiveInMinutes: 1440 | |
428 | + maxSize: 10000 | |
429 | + userPermissionFor: | |
430 | + timeToLiveInMinutes: 1440 | |
431 | + maxSize: 10000 | |
432 | + mobileLoginSmsCode: | |
433 | + timeToLiveInMinutes: 2 | |
434 | + maxSize: 10000 | |
426 | 435 | |
427 | 436 | redis: |
428 | 437 | # standalone or cluster | ... | ... |
... | ... | @@ -25,7 +25,9 @@ public interface FastIotConstants { |
25 | 25 | class ConfigJSONKey { |
26 | 26 | public static final String BASE_URL = "baseUrl"; |
27 | 27 | } |
28 | - | |
28 | + class Relation { | |
29 | + public static final String relationType = "Created"; | |
30 | + } | |
29 | 31 | String DEFAULT_DELIMITER = "#"; |
30 | 32 | |
31 | 33 | class StateValue { |
... | ... | @@ -56,10 +58,9 @@ public interface FastIotConstants { |
56 | 58 | } |
57 | 59 | |
58 | 60 | interface CacheConfigKey { |
59 | - String CACHE_CONFIG_KEY = "YUN_TENG_IOT_CACHE"; | |
60 | - String USER_PERMISSION_PREFIX = "user_permission_for_"; | |
61 | - String MOBILE_LOGIN_SMS_CODE = "mobile_login_sms_code"; | |
62 | - String DEFAULT_RULE_CHAIN = "default_rule_chain"; | |
61 | + String CACHE_CONFIG_KEY = "yunTengIotCache"; | |
62 | + String USER_PERMISSION_PREFIX = "userPermissionFor_"; | |
63 | + String MOBILE_LOGIN_SMS_CODE = "mobileLoginSmsCode"; | |
63 | 64 | } |
64 | 65 | |
65 | 66 | String DEFAULT_EMAIL_SUFFIX_FOR_TB ="@yunteng.com"; | ... | ... |