Commit 5fdbb51cd7acfff633b62446c85be4ae6d36d771
1 parent
c22bf33d
DAO layer, services, configuration and UI
Showing
54 changed files
with
4754 additions
and
0 deletions
Too many changes to show.
To preserve performance only 54 of 495 files are displayed.
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.config; | |
17 | + | |
18 | +import org.springframework.boot.context.properties.ConfigurationProperties; | |
19 | +import org.springframework.context.annotation.Configuration; | |
20 | +import org.thingsboard.server.service.security.model.token.JwtToken; | |
21 | + | |
22 | +@Configuration | |
23 | +@ConfigurationProperties(prefix = "security.jwt") | |
24 | +public class JwtSettings { | |
25 | + /** | |
26 | + * {@link JwtToken} will expire after this time. | |
27 | + */ | |
28 | + private Integer tokenExpirationTime; | |
29 | + | |
30 | + /** | |
31 | + * Token issuer. | |
32 | + */ | |
33 | + private String tokenIssuer; | |
34 | + | |
35 | + /** | |
36 | + * Key is used to sign {@link JwtToken}. | |
37 | + */ | |
38 | + private String tokenSigningKey; | |
39 | + | |
40 | + /** | |
41 | + * {@link JwtToken} can be refreshed during this timeframe. | |
42 | + */ | |
43 | + private Integer refreshTokenExpTime; | |
44 | + | |
45 | + public Integer getRefreshTokenExpTime() { | |
46 | + return refreshTokenExpTime; | |
47 | + } | |
48 | + | |
49 | + public void setRefreshTokenExpTime(Integer refreshTokenExpTime) { | |
50 | + this.refreshTokenExpTime = refreshTokenExpTime; | |
51 | + } | |
52 | + | |
53 | + public Integer getTokenExpirationTime() { | |
54 | + return tokenExpirationTime; | |
55 | + } | |
56 | + | |
57 | + public void setTokenExpirationTime(Integer tokenExpirationTime) { | |
58 | + this.tokenExpirationTime = tokenExpirationTime; | |
59 | + } | |
60 | + | |
61 | + public String getTokenIssuer() { | |
62 | + return tokenIssuer; | |
63 | + } | |
64 | + public void setTokenIssuer(String tokenIssuer) { | |
65 | + this.tokenIssuer = tokenIssuer; | |
66 | + } | |
67 | + | |
68 | + public String getTokenSigningKey() { | |
69 | + return tokenSigningKey; | |
70 | + } | |
71 | + | |
72 | + public void setTokenSigningKey(String tokenSigningKey) { | |
73 | + this.tokenSigningKey = tokenSigningKey; | |
74 | + } | |
75 | +} | |
\ No newline at end of file | ... | ... |
application/src/main/java/org/thingsboard/server/config/ThingsboardMessageConfiguration.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.config; | |
17 | + | |
18 | +import org.springframework.context.MessageSource; | |
19 | +import org.springframework.context.annotation.Bean; | |
20 | +import org.springframework.context.annotation.Configuration; | |
21 | +import org.springframework.context.support.ResourceBundleMessageSource; | |
22 | + | |
23 | +@Configuration | |
24 | +public class ThingsboardMessageConfiguration { | |
25 | + | |
26 | + @Bean | |
27 | + public MessageSource messageSource() { | |
28 | + ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); | |
29 | + messageSource.setBasename("i18n/messages"); | |
30 | + messageSource.setDefaultEncoding("UTF-8"); | |
31 | + return messageSource; | |
32 | + } | |
33 | + | |
34 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.config; | |
17 | + | |
18 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
19 | +import org.springframework.beans.factory.annotation.Autowired; | |
20 | +import org.springframework.beans.factory.annotation.Qualifier; | |
21 | +import org.springframework.boot.autoconfigure.security.SecurityProperties; | |
22 | +import org.springframework.context.annotation.Bean; | |
23 | +import org.springframework.context.annotation.Configuration; | |
24 | +import org.springframework.core.annotation.Order; | |
25 | +import org.springframework.security.authentication.AuthenticationManager; | |
26 | +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; | |
27 | +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; | |
28 | +import org.springframework.security.config.annotation.web.builders.HttpSecurity; | |
29 | +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; | |
30 | +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; | |
31 | +import org.springframework.security.config.http.SessionCreationPolicy; | |
32 | +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; | |
33 | +import org.springframework.security.web.authentication.AuthenticationFailureHandler; | |
34 | +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; | |
35 | +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; | |
36 | +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; | |
37 | +import org.thingsboard.server.exception.ThingsboardErrorResponseHandler; | |
38 | +import org.thingsboard.server.service.security.auth.rest.RestAuthenticationProvider; | |
39 | +import org.thingsboard.server.service.security.auth.rest.RestLoginProcessingFilter; | |
40 | +import org.thingsboard.server.service.security.auth.jwt.*; | |
41 | +import org.thingsboard.server.service.security.auth.jwt.extractor.TokenExtractor; | |
42 | + | |
43 | +import java.util.ArrayList; | |
44 | +import java.util.Arrays; | |
45 | +import java.util.List; | |
46 | + | |
47 | +@Configuration | |
48 | +@EnableWebSecurity | |
49 | +@EnableGlobalMethodSecurity(prePostEnabled=true) | |
50 | +@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) | |
51 | +public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapter { | |
52 | + | |
53 | + public static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization"; | |
54 | + public static final String JWT_TOKEN_QUERY_PARAM = "token"; | |
55 | + | |
56 | + public static final String DEVICE_API_ENTRY_POINT = "/api/v1/**"; | |
57 | + public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/api/auth/login"; | |
58 | + public static final String TOKEN_REFRESH_ENTRY_POINT = "/api/auth/token"; | |
59 | + public static final String[] NON_TOKEN_BASED_AUTH_ENTRY_POINTS = new String[] {"/index.html", "/static/**", "/api/noauth/**"}; | |
60 | + public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**"; | |
61 | + public static final String WS_TOKEN_BASED_AUTH_ENTRY_POINT = "/api/ws/**"; | |
62 | + | |
63 | + @Autowired private ThingsboardErrorResponseHandler restAccessDeniedHandler; | |
64 | + @Autowired private AuthenticationSuccessHandler successHandler; | |
65 | + @Autowired private AuthenticationFailureHandler failureHandler; | |
66 | + @Autowired private RestAuthenticationProvider restAuthenticationProvider; | |
67 | + @Autowired private JwtAuthenticationProvider jwtAuthenticationProvider; | |
68 | + @Autowired private RefreshTokenAuthenticationProvider refreshTokenAuthenticationProvider; | |
69 | + | |
70 | + @Autowired | |
71 | + @Qualifier("jwtHeaderTokenExtractor") | |
72 | + private TokenExtractor jwtHeaderTokenExtractor; | |
73 | + | |
74 | + @Autowired | |
75 | + @Qualifier("jwtQueryTokenExtractor") | |
76 | + private TokenExtractor jwtQueryTokenExtractor; | |
77 | + | |
78 | + @Autowired private AuthenticationManager authenticationManager; | |
79 | + | |
80 | + @Autowired private ObjectMapper objectMapper; | |
81 | + | |
82 | + @Bean | |
83 | + protected RestLoginProcessingFilter buildRestLoginProcessingFilter() throws Exception { | |
84 | + RestLoginProcessingFilter filter = new RestLoginProcessingFilter(FORM_BASED_LOGIN_ENTRY_POINT, successHandler, failureHandler, objectMapper); | |
85 | + filter.setAuthenticationManager(this.authenticationManager); | |
86 | + return filter; | |
87 | + } | |
88 | + | |
89 | + @Bean | |
90 | + protected JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter() throws Exception { | |
91 | + List<String> pathsToSkip = new ArrayList(Arrays.asList(NON_TOKEN_BASED_AUTH_ENTRY_POINTS)); | |
92 | + pathsToSkip.addAll(Arrays.asList(WS_TOKEN_BASED_AUTH_ENTRY_POINT, TOKEN_REFRESH_ENTRY_POINT, FORM_BASED_LOGIN_ENTRY_POINT, DEVICE_API_ENTRY_POINT)); | |
93 | + SkipPathRequestMatcher matcher = new SkipPathRequestMatcher(pathsToSkip, TOKEN_BASED_AUTH_ENTRY_POINT); | |
94 | + JwtTokenAuthenticationProcessingFilter filter | |
95 | + = new JwtTokenAuthenticationProcessingFilter(failureHandler, jwtHeaderTokenExtractor, matcher); | |
96 | + filter.setAuthenticationManager(this.authenticationManager); | |
97 | + return filter; | |
98 | + } | |
99 | + | |
100 | + @Bean | |
101 | + protected RefreshTokenProcessingFilter buildRefreshTokenProcessingFilter() throws Exception { | |
102 | + RefreshTokenProcessingFilter filter = new RefreshTokenProcessingFilter(TOKEN_REFRESH_ENTRY_POINT, successHandler, failureHandler, objectMapper); | |
103 | + filter.setAuthenticationManager(this.authenticationManager); | |
104 | + return filter; | |
105 | + } | |
106 | + | |
107 | + @Bean | |
108 | + protected JwtTokenAuthenticationProcessingFilter buildWsJwtTokenAuthenticationProcessingFilter() throws Exception { | |
109 | + AntPathRequestMatcher matcher = new AntPathRequestMatcher(WS_TOKEN_BASED_AUTH_ENTRY_POINT); | |
110 | + JwtTokenAuthenticationProcessingFilter filter | |
111 | + = new JwtTokenAuthenticationProcessingFilter(failureHandler, jwtQueryTokenExtractor, matcher); | |
112 | + filter.setAuthenticationManager(this.authenticationManager); | |
113 | + return filter; | |
114 | + } | |
115 | + | |
116 | + @Bean | |
117 | + @Override | |
118 | + public AuthenticationManager authenticationManagerBean() throws Exception { | |
119 | + return super.authenticationManagerBean(); | |
120 | + } | |
121 | + | |
122 | + @Override | |
123 | + protected void configure(AuthenticationManagerBuilder auth) { | |
124 | + auth.authenticationProvider(restAuthenticationProvider); | |
125 | + auth.authenticationProvider(jwtAuthenticationProvider); | |
126 | + auth.authenticationProvider(refreshTokenAuthenticationProvider); | |
127 | + } | |
128 | + | |
129 | + @Bean | |
130 | + protected BCryptPasswordEncoder passwordEncoder() { | |
131 | + return new BCryptPasswordEncoder(); | |
132 | + } | |
133 | + | |
134 | + @Override | |
135 | + protected void configure(HttpSecurity http) throws Exception { | |
136 | + http.headers().frameOptions().disable() | |
137 | + .and() | |
138 | + .csrf().disable() | |
139 | + .exceptionHandling() | |
140 | + .and() | |
141 | + .sessionManagement() | |
142 | + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) | |
143 | + .and() | |
144 | + .authorizeRequests() | |
145 | + .antMatchers(DEVICE_API_ENTRY_POINT).permitAll() // Device HTTP Transport API | |
146 | + .antMatchers(FORM_BASED_LOGIN_ENTRY_POINT).permitAll() // Login end-point | |
147 | + .antMatchers(TOKEN_REFRESH_ENTRY_POINT).permitAll() // Token refresh end-point | |
148 | + .antMatchers(NON_TOKEN_BASED_AUTH_ENTRY_POINTS).permitAll() // static resources, user activation and password reset end-points | |
149 | + .and() | |
150 | + .authorizeRequests() | |
151 | + .antMatchers(WS_TOKEN_BASED_AUTH_ENTRY_POINT).authenticated() // Protected WebSocket API End-points | |
152 | + .antMatchers(TOKEN_BASED_AUTH_ENTRY_POINT).authenticated() // Protected API End-points | |
153 | + .and() | |
154 | + .exceptionHandling().accessDeniedHandler(restAccessDeniedHandler) | |
155 | + .and() | |
156 | + .addFilterBefore(buildRestLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class) | |
157 | + .addFilterBefore(buildJwtTokenAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class) | |
158 | + .addFilterBefore(buildRefreshTokenProcessingFilter(), UsernamePasswordAuthenticationFilter.class) | |
159 | + .addFilterBefore(buildWsJwtTokenAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class); | |
160 | + } | |
161 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.config; | |
17 | + | |
18 | +import org.springframework.stereotype.Controller; | |
19 | +import org.springframework.web.bind.annotation.RequestMapping; | |
20 | + | |
21 | +@Controller | |
22 | +public class WebConfig { | |
23 | + | |
24 | + @RequestMapping(value = "/{path:^(?!api$)(?!static$)[^\\.]*}/**") | |
25 | + public String redirect() { | |
26 | + return "forward:/index.html"; | |
27 | + } | |
28 | + | |
29 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.config; | |
17 | + | |
18 | +import java.util.Map; | |
19 | + | |
20 | +import org.thingsboard.server.exception.ThingsboardErrorCode; | |
21 | +import org.thingsboard.server.exception.ThingsboardException; | |
22 | +import org.thingsboard.server.controller.plugin.PluginWebSocketHandler; | |
23 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
24 | +import org.springframework.context.annotation.Bean; | |
25 | +import org.springframework.context.annotation.Configuration; | |
26 | +import org.springframework.http.HttpStatus; | |
27 | +import org.springframework.http.server.ServerHttpRequest; | |
28 | +import org.springframework.http.server.ServerHttpResponse; | |
29 | +import org.springframework.security.core.Authentication; | |
30 | +import org.springframework.security.core.context.SecurityContextHolder; | |
31 | +import org.springframework.web.socket.WebSocketHandler; | |
32 | +import org.springframework.web.socket.config.annotation.EnableWebSocket; | |
33 | +import org.springframework.web.socket.config.annotation.WebSocketConfigurer; | |
34 | +import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; | |
35 | +import org.springframework.web.socket.server.HandshakeInterceptor; | |
36 | +import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean; | |
37 | +import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor; | |
38 | + | |
39 | +@Configuration | |
40 | +@EnableWebSocket | |
41 | +public class WebSocketConfiguration implements WebSocketConfigurer { | |
42 | + | |
43 | + public static final String WS_PLUGIN_PREFIX = "/api/ws/plugins/"; | |
44 | + public static final String WS_SECURITY_USER_ATTRIBUTE = "SECURITY_USER"; | |
45 | + private static final String WS_PLUGIN_MAPPING = WS_PLUGIN_PREFIX + "**"; | |
46 | + | |
47 | + @Bean | |
48 | + public ServletServerContainerFactoryBean createWebSocketContainer() { | |
49 | + ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean(); | |
50 | + container.setMaxTextMessageBufferSize(8192); | |
51 | + container.setMaxBinaryMessageBufferSize(8192); | |
52 | + return container; | |
53 | + } | |
54 | + | |
55 | + @Override | |
56 | + public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { | |
57 | + registry.addHandler(pluginWsHandler(), WS_PLUGIN_MAPPING).setAllowedOrigins("*") | |
58 | + .addInterceptors(new HttpSessionHandshakeInterceptor(), new HandshakeInterceptor() { | |
59 | + | |
60 | + @Override | |
61 | + public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, | |
62 | + Map<String, Object> attributes) throws Exception { | |
63 | + SecurityUser user = null; | |
64 | + try { | |
65 | + user = getCurrentUser(); | |
66 | + } catch (ThingsboardException ex) {} | |
67 | + if (user == null) { | |
68 | + response.setStatusCode(HttpStatus.UNAUTHORIZED); | |
69 | + return false; | |
70 | + } else { | |
71 | + attributes.put(WS_SECURITY_USER_ATTRIBUTE, user); | |
72 | + return true; | |
73 | + } | |
74 | + } | |
75 | + | |
76 | + @Override | |
77 | + public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, | |
78 | + Exception exception) { | |
79 | + } | |
80 | + }); | |
81 | + } | |
82 | + | |
83 | + @Bean | |
84 | + public WebSocketHandler pluginWsHandler() { | |
85 | + return new PluginWebSocketHandler(); | |
86 | + } | |
87 | + | |
88 | + protected SecurityUser getCurrentUser() throws ThingsboardException { | |
89 | + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); | |
90 | + if (authentication != null && authentication.getPrincipal() instanceof SecurityUser) { | |
91 | + return (SecurityUser) authentication.getPrincipal(); | |
92 | + } else { | |
93 | + throw new ThingsboardException("You aren't authorized to perform this operation!", ThingsboardErrorCode.AUTHENTICATION); | |
94 | + } | |
95 | + } | |
96 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller; | |
17 | + | |
18 | +import org.springframework.beans.factory.annotation.Autowired; | |
19 | +import org.springframework.security.access.prepost.PreAuthorize; | |
20 | +import org.springframework.web.bind.annotation.*; | |
21 | +import org.thingsboard.server.common.data.AdminSettings; | |
22 | +import org.thingsboard.server.dao.settings.AdminSettingsService; | |
23 | +import org.thingsboard.server.exception.ThingsboardException; | |
24 | +import org.thingsboard.server.service.mail.MailService; | |
25 | + | |
26 | +@RestController | |
27 | +@RequestMapping("/api/admin") | |
28 | +public class AdminController extends BaseController { | |
29 | + | |
30 | + @Autowired | |
31 | + private MailService mailService; | |
32 | + | |
33 | + @Autowired | |
34 | + private AdminSettingsService adminSettingsService; | |
35 | + | |
36 | + @PreAuthorize("hasAuthority('SYS_ADMIN')") | |
37 | + @RequestMapping(value = "/settings/{key}", method = RequestMethod.GET) | |
38 | + @ResponseBody | |
39 | + public AdminSettings getAdminSettings(@PathVariable("key") String key) throws ThingsboardException { | |
40 | + try { | |
41 | + return checkNotNull(adminSettingsService.findAdminSettingsByKey(key)); | |
42 | + } catch (Exception e) { | |
43 | + throw handleException(e); | |
44 | + } | |
45 | + } | |
46 | + | |
47 | + @PreAuthorize("hasAuthority('SYS_ADMIN')") | |
48 | + @RequestMapping(value = "/settings", method = RequestMethod.POST) | |
49 | + @ResponseBody | |
50 | + public AdminSettings saveAdminSettings(@RequestBody AdminSettings adminSettings) throws ThingsboardException { | |
51 | + try { | |
52 | + adminSettings = checkNotNull(adminSettingsService.saveAdminSettings(adminSettings)); | |
53 | + if (adminSettings.getKey().equals("mail")) { | |
54 | + mailService.updateMailConfiguration(); | |
55 | + } | |
56 | + return adminSettings; | |
57 | + } catch (Exception e) { | |
58 | + throw handleException(e); | |
59 | + } | |
60 | + } | |
61 | + | |
62 | + @PreAuthorize("hasAuthority('SYS_ADMIN')") | |
63 | + @RequestMapping(value = "/settings/testMail", method = RequestMethod.POST) | |
64 | + public void sendTestMail(@RequestBody AdminSettings adminSettings) throws ThingsboardException { | |
65 | + try { | |
66 | + adminSettings = checkNotNull(adminSettings); | |
67 | + if (adminSettings.getKey().equals("mail")) { | |
68 | + String email = getCurrentUser().getEmail(); | |
69 | + mailService.sendTestMail(adminSettings.getJsonValue(), email); | |
70 | + } | |
71 | + } catch (Exception e) { | |
72 | + throw handleException(e); | |
73 | + } | |
74 | + } | |
75 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller; | |
17 | + | |
18 | +import com.fasterxml.jackson.databind.JsonNode; | |
19 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
20 | +import com.fasterxml.jackson.databind.node.ObjectNode; | |
21 | +import lombok.extern.slf4j.Slf4j; | |
22 | +import org.slf4j.Logger; | |
23 | +import org.slf4j.LoggerFactory; | |
24 | +import org.springframework.beans.factory.annotation.Autowired; | |
25 | +import org.springframework.http.HttpHeaders; | |
26 | +import org.springframework.http.HttpStatus; | |
27 | +import org.springframework.http.ResponseEntity; | |
28 | +import org.springframework.security.access.prepost.PreAuthorize; | |
29 | +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; | |
30 | +import org.springframework.web.bind.annotation.*; | |
31 | +import org.thingsboard.server.common.data.User; | |
32 | +import org.thingsboard.server.common.data.security.UserCredentials; | |
33 | +import org.thingsboard.server.dao.user.UserService; | |
34 | +import org.thingsboard.server.exception.ThingsboardErrorCode; | |
35 | +import org.thingsboard.server.exception.ThingsboardException; | |
36 | +import org.thingsboard.server.service.mail.MailService; | |
37 | +import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository; | |
38 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
39 | +import org.thingsboard.server.service.security.model.token.JwtToken; | |
40 | +import org.thingsboard.server.service.security.model.token.JwtTokenFactory; | |
41 | + | |
42 | +import javax.servlet.http.HttpServletRequest; | |
43 | +import java.net.URI; | |
44 | +import java.net.URISyntaxException; | |
45 | + | |
46 | +@RestController | |
47 | +@RequestMapping("/api") | |
48 | +@Slf4j | |
49 | +public class AuthController extends BaseController { | |
50 | + | |
51 | + | |
52 | + | |
53 | + @Autowired | |
54 | + private BCryptPasswordEncoder passwordEncoder; | |
55 | + | |
56 | + @Autowired | |
57 | + private JwtTokenFactory tokenFactory; | |
58 | + | |
59 | + @Autowired | |
60 | + private RefreshTokenRepository refreshTokenRepository; | |
61 | + | |
62 | + @Autowired | |
63 | + private UserService userService; | |
64 | + | |
65 | + @Autowired | |
66 | + private MailService mailService; | |
67 | + | |
68 | + @PreAuthorize("isAuthenticated()") | |
69 | + @RequestMapping(value = "/auth/user", method = RequestMethod.GET) | |
70 | + public @ResponseBody User getUser() throws ThingsboardException { | |
71 | + try { | |
72 | + SecurityUser securityUser = getCurrentUser(); | |
73 | + return userService.findUserById(securityUser.getId()); | |
74 | + } catch (Exception e) { | |
75 | + throw handleException(e); | |
76 | + } | |
77 | + } | |
78 | + | |
79 | + @PreAuthorize("isAuthenticated()") | |
80 | + @RequestMapping(value = "/auth/changePassword", method = RequestMethod.POST) | |
81 | + @ResponseStatus(value = HttpStatus.OK) | |
82 | + public void changePassword ( | |
83 | + @RequestParam(value = "currentPassword") String currentPassword, | |
84 | + @RequestParam(value = "newPassword") String newPassword) throws ThingsboardException { | |
85 | + try { | |
86 | + SecurityUser securityUser = getCurrentUser(); | |
87 | + UserCredentials userCredentials = userService.findUserCredentialsByUserId(securityUser.getId()); | |
88 | + if (!passwordEncoder.matches(currentPassword, userCredentials.getPassword())) { | |
89 | + throw new ThingsboardException("Current password doesn't match!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); | |
90 | + } | |
91 | + userCredentials.setPassword(passwordEncoder.encode(newPassword)); | |
92 | + userService.saveUserCredentials(userCredentials); | |
93 | + } catch (Exception e) { | |
94 | + throw handleException(e); | |
95 | + } | |
96 | + } | |
97 | + | |
98 | + @RequestMapping(value = "/noauth/activate", params = { "activateToken" }, method = RequestMethod.GET) | |
99 | + public ResponseEntity<String> checkActivateToken( | |
100 | + @RequestParam(value = "activateToken") String activateToken) { | |
101 | + HttpHeaders headers = new HttpHeaders(); | |
102 | + HttpStatus responseStatus; | |
103 | + UserCredentials userCredentials = userService.findUserCredentialsByActivateToken(activateToken); | |
104 | + if (userCredentials != null) { | |
105 | + String createPasswordURI = "/login/createPassword"; | |
106 | + try { | |
107 | + URI location = new URI(createPasswordURI + "?activateToken=" + activateToken); | |
108 | + headers.setLocation(location); | |
109 | + responseStatus = HttpStatus.PERMANENT_REDIRECT; | |
110 | + } catch (URISyntaxException e) { | |
111 | + log.error("Unable to create URI with address [{}]", createPasswordURI); | |
112 | + responseStatus = HttpStatus.BAD_REQUEST; | |
113 | + } | |
114 | + } else { | |
115 | + responseStatus = HttpStatus.CONFLICT; | |
116 | + } | |
117 | + return new ResponseEntity<>(headers, responseStatus); | |
118 | + } | |
119 | + | |
120 | + @RequestMapping(value = "/noauth/resetPasswordByEmail", method = RequestMethod.POST) | |
121 | + @ResponseStatus(value = HttpStatus.OK) | |
122 | + public void requestResetPasswordByEmail ( | |
123 | + @RequestParam(value = "email") String email, | |
124 | + HttpServletRequest request) throws ThingsboardException { | |
125 | + try { | |
126 | + UserCredentials userCredentials = userService.requestPasswordReset(email); | |
127 | + | |
128 | + String baseUrl = String.format("%s://%s:%d", | |
129 | + request.getScheme(), | |
130 | + request.getServerName(), | |
131 | + request.getServerPort()); | |
132 | + String resetPasswordUrl = String.format("%s/api/noauth/resetPassword?resetToken=%s", baseUrl, | |
133 | + userCredentials.getResetToken()); | |
134 | + | |
135 | + mailService.sendResetPasswordEmail(resetPasswordUrl, email); | |
136 | + } catch (Exception e) { | |
137 | + throw handleException(e); | |
138 | + } | |
139 | + } | |
140 | + | |
141 | + @RequestMapping(value = "/noauth/resetPassword", params = { "resetToken" }, method = RequestMethod.GET) | |
142 | + public ResponseEntity<String> checkResetToken( | |
143 | + @RequestParam(value = "resetToken") String resetToken) { | |
144 | + HttpHeaders headers = new HttpHeaders(); | |
145 | + HttpStatus responseStatus; | |
146 | + String resetPasswordURI = "/login/resetPassword"; | |
147 | + UserCredentials userCredentials = userService.findUserCredentialsByResetToken(resetToken); | |
148 | + if (userCredentials != null) { | |
149 | + try { | |
150 | + URI location = new URI(resetPasswordURI + "?resetToken=" + resetToken); | |
151 | + headers.setLocation(location); | |
152 | + responseStatus = HttpStatus.PERMANENT_REDIRECT; | |
153 | + } catch (URISyntaxException e) { | |
154 | + log.error("Unable to create URI with address [{}]", resetPasswordURI); | |
155 | + responseStatus = HttpStatus.BAD_REQUEST; | |
156 | + } | |
157 | + } else { | |
158 | + responseStatus = HttpStatus.CONFLICT; | |
159 | + } | |
160 | + return new ResponseEntity<>(headers, responseStatus); | |
161 | + } | |
162 | + | |
163 | + @RequestMapping(value = "/noauth/activate", method = RequestMethod.POST) | |
164 | + @ResponseStatus(value = HttpStatus.OK) | |
165 | + @ResponseBody | |
166 | + public JsonNode activateUser( | |
167 | + @RequestParam(value = "activateToken") String activateToken, | |
168 | + @RequestParam(value = "password") String password, | |
169 | + HttpServletRequest request) throws ThingsboardException { | |
170 | + try { | |
171 | + String encodedPassword = passwordEncoder.encode(password); | |
172 | + UserCredentials credentials = userService.activateUserCredentials(activateToken, encodedPassword); | |
173 | + User user = userService.findUserById(credentials.getUserId()); | |
174 | + SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled()); | |
175 | + String baseUrl = String.format("%s://%s:%d", | |
176 | + request.getScheme(), | |
177 | + request.getServerName(), | |
178 | + request.getServerPort()); | |
179 | + String loginUrl = String.format("%s/login", baseUrl); | |
180 | + String email = user.getEmail(); | |
181 | + mailService.sendAccountActivatedEmail(loginUrl, email); | |
182 | + | |
183 | + JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser); | |
184 | + JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser); | |
185 | + | |
186 | + ObjectMapper objectMapper = new ObjectMapper(); | |
187 | + ObjectNode tokenObject = objectMapper.createObjectNode(); | |
188 | + tokenObject.put("token", accessToken.getToken()); | |
189 | + tokenObject.put("refreshToken", refreshToken.getToken()); | |
190 | + return tokenObject; | |
191 | + } catch (Exception e) { | |
192 | + throw handleException(e); | |
193 | + } | |
194 | + } | |
195 | + | |
196 | + @RequestMapping(value = "/noauth/resetPassword", method = RequestMethod.POST) | |
197 | + @ResponseStatus(value = HttpStatus.OK) | |
198 | + @ResponseBody | |
199 | + public JsonNode resetPassword( | |
200 | + @RequestParam(value = "resetToken") String resetToken, | |
201 | + @RequestParam(value = "password") String password, | |
202 | + HttpServletRequest request) throws ThingsboardException { | |
203 | + try { | |
204 | + UserCredentials userCredentials = userService.findUserCredentialsByResetToken(resetToken); | |
205 | + if (userCredentials != null) { | |
206 | + String encodedPassword = passwordEncoder.encode(password); | |
207 | + userCredentials.setPassword(encodedPassword); | |
208 | + userCredentials.setResetToken(null); | |
209 | + userCredentials = userService.saveUserCredentials(userCredentials); | |
210 | + User user = userService.findUserById(userCredentials.getUserId()); | |
211 | + SecurityUser securityUser = new SecurityUser(user, userCredentials.isEnabled()); | |
212 | + String baseUrl = String.format("%s://%s:%d", | |
213 | + request.getScheme(), | |
214 | + request.getServerName(), | |
215 | + request.getServerPort()); | |
216 | + String loginUrl = String.format("%s/login", baseUrl); | |
217 | + String email = user.getEmail(); | |
218 | + mailService.sendPasswordWasResetEmail(loginUrl, email); | |
219 | + | |
220 | + JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser); | |
221 | + JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser); | |
222 | + | |
223 | + ObjectMapper objectMapper = new ObjectMapper(); | |
224 | + ObjectNode tokenObject = objectMapper.createObjectNode(); | |
225 | + tokenObject.put("token", accessToken.getToken()); | |
226 | + tokenObject.put("refreshToken", refreshToken.getToken()); | |
227 | + return tokenObject; | |
228 | + } else { | |
229 | + throw new ThingsboardException("Invalid reset token!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); | |
230 | + } | |
231 | + } catch (Exception e) { | |
232 | + throw handleException(e); | |
233 | + } | |
234 | + } | |
235 | + | |
236 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller; | |
17 | + | |
18 | +import com.fasterxml.jackson.databind.JsonNode; | |
19 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
20 | +import lombok.extern.slf4j.Slf4j; | |
21 | +import org.apache.commons.lang3.StringUtils; | |
22 | +import org.springframework.beans.factory.annotation.Autowired; | |
23 | +import org.springframework.security.core.Authentication; | |
24 | +import org.springframework.security.core.context.SecurityContextHolder; | |
25 | +import org.springframework.web.bind.annotation.ExceptionHandler; | |
26 | +import org.thingsboard.server.actors.service.ActorService; | |
27 | +import org.thingsboard.server.common.data.Customer; | |
28 | +import org.thingsboard.server.common.data.Dashboard; | |
29 | +import org.thingsboard.server.common.data.Device; | |
30 | +import org.thingsboard.server.common.data.User; | |
31 | +import org.thingsboard.server.common.data.id.*; | |
32 | +import org.thingsboard.server.common.data.page.TextPageLink; | |
33 | +import org.thingsboard.server.common.data.page.TimePageLink; | |
34 | +import org.thingsboard.server.common.data.plugin.ComponentDescriptor; | |
35 | +import org.thingsboard.server.common.data.plugin.ComponentType; | |
36 | +import org.thingsboard.server.common.data.plugin.PluginMetaData; | |
37 | +import org.thingsboard.server.common.data.rule.RuleMetaData; | |
38 | +import org.thingsboard.server.common.data.security.Authority; | |
39 | +import org.thingsboard.server.common.data.widget.WidgetType; | |
40 | +import org.thingsboard.server.common.data.widget.WidgetsBundle; | |
41 | +import org.thingsboard.server.dao.customer.CustomerService; | |
42 | +import org.thingsboard.server.dao.dashboard.DashboardService; | |
43 | +import org.thingsboard.server.dao.device.DeviceCredentialsService; | |
44 | +import org.thingsboard.server.dao.device.DeviceService; | |
45 | +import org.thingsboard.server.dao.exception.DataValidationException; | |
46 | +import org.thingsboard.server.dao.exception.IncorrectParameterException; | |
47 | +import org.thingsboard.server.dao.model.ModelConstants; | |
48 | +import org.thingsboard.server.dao.plugin.PluginService; | |
49 | +import org.thingsboard.server.dao.rule.RuleService; | |
50 | +import org.thingsboard.server.dao.user.UserService; | |
51 | +import org.thingsboard.server.dao.widget.WidgetTypeService; | |
52 | +import org.thingsboard.server.dao.widget.WidgetsBundleService; | |
53 | +import org.thingsboard.server.exception.ThingsboardErrorCode; | |
54 | +import org.thingsboard.server.exception.ThingsboardErrorResponseHandler; | |
55 | +import org.thingsboard.server.exception.ThingsboardException; | |
56 | +import org.thingsboard.server.service.component.ComponentDiscoveryService; | |
57 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
58 | + | |
59 | +import javax.mail.MessagingException; | |
60 | +import javax.servlet.http.HttpServletResponse; | |
61 | +import java.util.List; | |
62 | +import java.util.Optional; | |
63 | +import java.util.UUID; | |
64 | + | |
65 | +import static org.thingsboard.server.dao.service.Validator.validateId; | |
66 | + | |
67 | +@Slf4j | |
68 | +public abstract class BaseController { | |
69 | + | |
70 | + @Autowired | |
71 | + private ThingsboardErrorResponseHandler errorResponseHandler; | |
72 | + | |
73 | + @Autowired | |
74 | + protected CustomerService customerService; | |
75 | + | |
76 | + @Autowired | |
77 | + protected UserService userService; | |
78 | + | |
79 | + @Autowired | |
80 | + protected DeviceService deviceService; | |
81 | + | |
82 | + @Autowired | |
83 | + protected DeviceCredentialsService deviceCredentialsService; | |
84 | + | |
85 | + @Autowired | |
86 | + protected WidgetsBundleService widgetsBundleService; | |
87 | + | |
88 | + @Autowired | |
89 | + protected WidgetTypeService widgetTypeService; | |
90 | + | |
91 | + @Autowired | |
92 | + protected DashboardService dashboardService; | |
93 | + | |
94 | + @Autowired | |
95 | + protected ComponentDiscoveryService componentDescriptorService; | |
96 | + | |
97 | + @Autowired | |
98 | + protected RuleService ruleService; | |
99 | + | |
100 | + @Autowired | |
101 | + protected PluginService pluginService; | |
102 | + | |
103 | + @Autowired | |
104 | + protected ActorService actorService; | |
105 | + | |
106 | + | |
107 | + @ExceptionHandler(ThingsboardException.class) | |
108 | + public void handleThingsboardException(ThingsboardException ex, HttpServletResponse response) { | |
109 | + errorResponseHandler.handle(ex, response); | |
110 | + } | |
111 | + | |
112 | + ThingsboardException handleException(Exception exception) { | |
113 | + return handleException(exception, true); | |
114 | + } | |
115 | + | |
116 | + private ThingsboardException handleException(Exception exception, boolean logException) { | |
117 | + if (logException) { | |
118 | + log.error("Error [{}]", exception.getMessage()); | |
119 | + } | |
120 | + | |
121 | + String cause = ""; | |
122 | + if (exception.getCause() != null) { | |
123 | + cause = exception.getCause().getClass().getCanonicalName(); | |
124 | + } | |
125 | + | |
126 | + if (exception instanceof ThingsboardException) { | |
127 | + return (ThingsboardException) exception; | |
128 | + } else if (exception instanceof IllegalArgumentException || exception instanceof IncorrectParameterException | |
129 | + || exception instanceof DataValidationException || cause.contains("IncorrectParameterException")) { | |
130 | + return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.BAD_REQUEST_PARAMS); | |
131 | + } else if (exception instanceof MessagingException) { | |
132 | + return new ThingsboardException("Unable to send mail: " + exception.getMessage(), ThingsboardErrorCode.GENERAL); | |
133 | + } else { | |
134 | + return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.GENERAL); | |
135 | + } | |
136 | + } | |
137 | + | |
138 | + <T> T checkNotNull(T reference) throws ThingsboardException { | |
139 | + if (reference == null) { | |
140 | + throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND); | |
141 | + } | |
142 | + return reference; | |
143 | + } | |
144 | + | |
145 | + <T> T checkNotNull(Optional<T> reference) throws ThingsboardException { | |
146 | + if (reference.isPresent()) { | |
147 | + return reference.get(); | |
148 | + } else { | |
149 | + throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND); | |
150 | + } | |
151 | + } | |
152 | + | |
153 | + void checkParameter(String name, String param) throws ThingsboardException { | |
154 | + if (StringUtils.isEmpty(param)) { | |
155 | + throw new ThingsboardException("Parameter '" + name + "' can't be empty!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); | |
156 | + } | |
157 | + } | |
158 | + | |
159 | + UUID toUUID(String id) { | |
160 | + return UUID.fromString(id); | |
161 | + } | |
162 | + | |
163 | + TimePageLink createPageLink(int limit, Long startTime, Long endTime, boolean ascOrder, String idOffset) { | |
164 | + UUID idOffsetUuid = null; | |
165 | + if (StringUtils.isNotEmpty(idOffset)) { | |
166 | + idOffsetUuid = toUUID(idOffset); | |
167 | + } | |
168 | + return new TimePageLink(limit, startTime, endTime, ascOrder, idOffsetUuid); | |
169 | + } | |
170 | + | |
171 | + | |
172 | + TextPageLink createPageLink(int limit, String textSearch, String idOffset, String textOffset) { | |
173 | + UUID idOffsetUuid = null; | |
174 | + if (StringUtils.isNotEmpty(idOffset)) { | |
175 | + idOffsetUuid = toUUID(idOffset); | |
176 | + } | |
177 | + return new TextPageLink(limit, textSearch, idOffsetUuid, textOffset); | |
178 | + } | |
179 | + | |
180 | + protected SecurityUser getCurrentUser() throws ThingsboardException { | |
181 | + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); | |
182 | + if (authentication != null && authentication.getPrincipal() instanceof SecurityUser) { | |
183 | + return (SecurityUser) authentication.getPrincipal(); | |
184 | + } else { | |
185 | + throw new ThingsboardException("You aren't authorized to perform this operation!", ThingsboardErrorCode.AUTHENTICATION); | |
186 | + } | |
187 | + } | |
188 | + | |
189 | + void checkTenantId(TenantId tenantId) throws ThingsboardException { | |
190 | + validateId(tenantId, "Incorrect tenantId " + tenantId); | |
191 | + SecurityUser authUser = getCurrentUser(); | |
192 | + if (authUser.getAuthority() != Authority.SYS_ADMIN && | |
193 | + (authUser.getTenantId() == null || !authUser.getTenantId().equals(tenantId))) { | |
194 | + throw new ThingsboardException("You don't have permission to perform this operation!", | |
195 | + ThingsboardErrorCode.PERMISSION_DENIED); | |
196 | + } | |
197 | + } | |
198 | + | |
199 | + protected TenantId getTenantId() throws ThingsboardException { | |
200 | + return getCurrentUser().getTenantId(); | |
201 | + } | |
202 | + | |
203 | + Customer checkCustomerId(CustomerId customerId) throws ThingsboardException { | |
204 | + try { | |
205 | + validateId(customerId, "Incorrect customerId " + customerId); | |
206 | + SecurityUser authUser = getCurrentUser(); | |
207 | + if (authUser.getAuthority() == Authority.SYS_ADMIN || | |
208 | + (authUser.getAuthority() != Authority.TENANT_ADMIN && | |
209 | + (authUser.getCustomerId() == null || !authUser.getCustomerId().equals(customerId)))) { | |
210 | + throw new ThingsboardException("You don't have permission to perform this operation!", | |
211 | + ThingsboardErrorCode.PERMISSION_DENIED); | |
212 | + } | |
213 | + Customer customer = customerService.findCustomerById(customerId); | |
214 | + checkCustomer(customer); | |
215 | + return customer; | |
216 | + } catch (Exception e) { | |
217 | + throw handleException(e, false); | |
218 | + } | |
219 | + } | |
220 | + | |
221 | + private void checkCustomer(Customer customer) throws ThingsboardException { | |
222 | + checkNotNull(customer); | |
223 | + checkTenantId(customer.getTenantId()); | |
224 | + } | |
225 | + | |
226 | + User checkUserId(UserId userId) throws ThingsboardException { | |
227 | + try { | |
228 | + validateId(userId, "Incorrect userId " + userId); | |
229 | + User user = userService.findUserById(userId); | |
230 | + checkUser(user); | |
231 | + return user; | |
232 | + } catch (Exception e) { | |
233 | + throw handleException(e, false); | |
234 | + } | |
235 | + } | |
236 | + | |
237 | + private void checkUser(User user) throws ThingsboardException { | |
238 | + checkNotNull(user); | |
239 | + checkTenantId(user.getTenantId()); | |
240 | + if (user.getAuthority() == Authority.CUSTOMER_USER) { | |
241 | + checkCustomerId(user.getCustomerId()); | |
242 | + } | |
243 | + } | |
244 | + | |
245 | + Device checkDeviceId(DeviceId deviceId) throws ThingsboardException { | |
246 | + try { | |
247 | + validateId(deviceId, "Incorrect deviceId " + deviceId); | |
248 | + Device device = deviceService.findDeviceById(deviceId); | |
249 | + checkDevice(device); | |
250 | + return device; | |
251 | + } catch (Exception e) { | |
252 | + throw handleException(e, false); | |
253 | + } | |
254 | + } | |
255 | + | |
256 | + private void checkDevice(Device device) throws ThingsboardException { | |
257 | + checkNotNull(device); | |
258 | + checkTenantId(device.getTenantId()); | |
259 | + if (device.getCustomerId() != null && !device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { | |
260 | + checkCustomerId(device.getCustomerId()); | |
261 | + } | |
262 | + } | |
263 | + | |
264 | + WidgetsBundle checkWidgetsBundleId(WidgetsBundleId widgetsBundleId, boolean modify) throws ThingsboardException { | |
265 | + try { | |
266 | + validateId(widgetsBundleId, "Incorrect widgetsBundleId " + widgetsBundleId); | |
267 | + WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleById(widgetsBundleId); | |
268 | + checkWidgetsBundle(widgetsBundle, modify); | |
269 | + return widgetsBundle; | |
270 | + } catch (Exception e) { | |
271 | + throw handleException(e, false); | |
272 | + } | |
273 | + } | |
274 | + | |
275 | + private void checkWidgetsBundle(WidgetsBundle widgetsBundle, boolean modify) throws ThingsboardException { | |
276 | + checkNotNull(widgetsBundle); | |
277 | + if (widgetsBundle.getTenantId() != null && !widgetsBundle.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { | |
278 | + checkTenantId(widgetsBundle.getTenantId()); | |
279 | + } else if (modify && getCurrentUser().getAuthority() != Authority.SYS_ADMIN) { | |
280 | + throw new ThingsboardException("You don't have permission to perform this operation!", | |
281 | + ThingsboardErrorCode.PERMISSION_DENIED); | |
282 | + } | |
283 | + } | |
284 | + | |
285 | + WidgetType checkWidgetTypeId(WidgetTypeId widgetTypeId, boolean modify) throws ThingsboardException { | |
286 | + try { | |
287 | + validateId(widgetTypeId, "Incorrect widgetTypeId " + widgetTypeId); | |
288 | + WidgetType widgetType = widgetTypeService.findWidgetTypeById(widgetTypeId); | |
289 | + checkWidgetType(widgetType, modify); | |
290 | + return widgetType; | |
291 | + } catch (Exception e) { | |
292 | + throw handleException(e, false); | |
293 | + } | |
294 | + } | |
295 | + | |
296 | + void checkWidgetType(WidgetType widgetType, boolean modify) throws ThingsboardException { | |
297 | + checkNotNull(widgetType); | |
298 | + if (widgetType.getTenantId() != null && !widgetType.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { | |
299 | + checkTenantId(widgetType.getTenantId()); | |
300 | + } else if (modify && getCurrentUser().getAuthority() != Authority.SYS_ADMIN) { | |
301 | + throw new ThingsboardException("You don't have permission to perform this operation!", | |
302 | + ThingsboardErrorCode.PERMISSION_DENIED); | |
303 | + } | |
304 | + } | |
305 | + | |
306 | + Dashboard checkDashboardId(DashboardId dashboardId) throws ThingsboardException { | |
307 | + try { | |
308 | + validateId(dashboardId, "Incorrect dashboardId " + dashboardId); | |
309 | + Dashboard dashboard = dashboardService.findDashboardById(dashboardId); | |
310 | + checkDashboard(dashboard); | |
311 | + return dashboard; | |
312 | + } catch (Exception e) { | |
313 | + throw handleException(e, false); | |
314 | + } | |
315 | + } | |
316 | + | |
317 | + private void checkDashboard(Dashboard dashboard) throws ThingsboardException { | |
318 | + checkNotNull(dashboard); | |
319 | + checkTenantId(dashboard.getTenantId()); | |
320 | + if (dashboard.getCustomerId() != null && !dashboard.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { | |
321 | + checkCustomerId(dashboard.getCustomerId()); | |
322 | + } | |
323 | + } | |
324 | + | |
325 | + ComponentDescriptor checkComponentDescriptorByClazz(String clazz) throws ThingsboardException { | |
326 | + try { | |
327 | + log.debug("[{}] Lookup component descriptor", clazz); | |
328 | + ComponentDescriptor componentDescriptor = checkNotNull(componentDescriptorService.getComponent(clazz)); | |
329 | + return componentDescriptor; | |
330 | + } catch (Exception e) { | |
331 | + throw handleException(e, false); | |
332 | + } | |
333 | + } | |
334 | + | |
335 | + List<ComponentDescriptor> checkComponentDescriptorsByType(ComponentType type) throws ThingsboardException { | |
336 | + try { | |
337 | + log.debug("[{}] Lookup component descriptors", type); | |
338 | + return componentDescriptorService.getComponents(type); | |
339 | + } catch (Exception e) { | |
340 | + throw handleException(e, false); | |
341 | + } | |
342 | + } | |
343 | + | |
344 | + List<ComponentDescriptor> checkPluginActionsByPluginClazz(String pluginClazz) throws ThingsboardException { | |
345 | + try { | |
346 | + checkComponentDescriptorByClazz(pluginClazz); | |
347 | + log.debug("[{}] Lookup plugin actions", pluginClazz); | |
348 | + return componentDescriptorService.getPluginActions(pluginClazz); | |
349 | + } catch (Exception e) { | |
350 | + throw handleException(e, false); | |
351 | + } | |
352 | + } | |
353 | + | |
354 | + protected PluginMetaData checkPlugin(PluginMetaData plugin) throws ThingsboardException { | |
355 | + checkNotNull(plugin); | |
356 | + SecurityUser authUser = getCurrentUser(); | |
357 | + TenantId tenantId = plugin.getTenantId(); | |
358 | + validateId(tenantId, "Incorrect tenantId " + tenantId); | |
359 | + if (authUser.getAuthority() != Authority.SYS_ADMIN) { | |
360 | + if (authUser.getTenantId() == null || | |
361 | + !tenantId.getId().equals(ModelConstants.NULL_UUID) && !authUser.getTenantId().equals(tenantId)) { | |
362 | + throw new ThingsboardException("You don't have permission to perform this operation!", | |
363 | + ThingsboardErrorCode.PERMISSION_DENIED); | |
364 | + | |
365 | + } else if (tenantId.getId().equals(ModelConstants.NULL_UUID)) { | |
366 | + plugin.setConfiguration(null); | |
367 | + } | |
368 | + } | |
369 | + return plugin; | |
370 | + } | |
371 | + | |
372 | + protected RuleMetaData checkRule(RuleMetaData rule) throws ThingsboardException { | |
373 | + checkNotNull(rule); | |
374 | + checkTenantId(rule.getTenantId()); | |
375 | + return rule; | |
376 | + } | |
377 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller; | |
17 | + | |
18 | +import org.springframework.security.access.prepost.PreAuthorize; | |
19 | +import org.springframework.web.bind.annotation.*; | |
20 | +import org.thingsboard.server.common.data.plugin.ComponentDescriptor; | |
21 | +import org.thingsboard.server.common.data.plugin.ComponentType; | |
22 | +import org.thingsboard.server.exception.ThingsboardException; | |
23 | + | |
24 | +import java.util.List; | |
25 | + | |
26 | +@RestController | |
27 | +@RequestMapping("/api") | |
28 | +public class ComponentDescriptorController extends BaseController { | |
29 | + | |
30 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')") | |
31 | + @RequestMapping(value = "/component/{componentDescriptorClazz:.+}", method = RequestMethod.GET) | |
32 | + @ResponseBody | |
33 | + public ComponentDescriptor getComponentDescriptorByClazz(@PathVariable("componentDescriptorClazz") String strComponentDescriptorClazz) throws ThingsboardException { | |
34 | + checkParameter("strComponentDescriptorClazz", strComponentDescriptorClazz); | |
35 | + try { | |
36 | + return checkComponentDescriptorByClazz(strComponentDescriptorClazz); | |
37 | + } catch (Exception e) { | |
38 | + throw handleException(e); | |
39 | + } | |
40 | + } | |
41 | + | |
42 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')") | |
43 | + @RequestMapping(value = "/components/{componentType}", method = RequestMethod.GET) | |
44 | + @ResponseBody | |
45 | + public List<ComponentDescriptor> getComponentDescriptorsByType(@PathVariable("componentType") String strComponentType) throws ThingsboardException { | |
46 | + checkParameter("componentType", strComponentType); | |
47 | + try { | |
48 | + return checkComponentDescriptorsByType(ComponentType.valueOf(strComponentType)); | |
49 | + } catch (Exception e) { | |
50 | + throw handleException(e); | |
51 | + } | |
52 | + } | |
53 | + | |
54 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')") | |
55 | + @RequestMapping(value = "/components/actions/{pluginClazz:.+}", method = RequestMethod.GET) | |
56 | + @ResponseBody | |
57 | + public List<ComponentDescriptor> getPluginActionsByPluginClazz(@PathVariable("pluginClazz") String pluginClazz) throws ThingsboardException { | |
58 | + checkParameter("pluginClazz", pluginClazz); | |
59 | + try { | |
60 | + return checkPluginActionsByPluginClazz(pluginClazz); | |
61 | + } catch (Exception e) { | |
62 | + throw handleException(e); | |
63 | + } | |
64 | + } | |
65 | + | |
66 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller; | |
17 | + | |
18 | +import org.springframework.http.HttpStatus; | |
19 | +import org.springframework.security.access.prepost.PreAuthorize; | |
20 | +import org.springframework.web.bind.annotation.*; | |
21 | +import org.thingsboard.server.common.data.Customer; | |
22 | +import org.thingsboard.server.common.data.id.CustomerId; | |
23 | +import org.thingsboard.server.common.data.id.TenantId; | |
24 | +import org.thingsboard.server.common.data.page.TextPageData; | |
25 | +import org.thingsboard.server.common.data.page.TextPageLink; | |
26 | +import org.thingsboard.server.exception.ThingsboardException; | |
27 | + | |
28 | +@RestController | |
29 | +@RequestMapping("/api") | |
30 | +public class CustomerController extends BaseController { | |
31 | + | |
32 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
33 | + @RequestMapping(value = "/customer/{customerId}", method = RequestMethod.GET) | |
34 | + @ResponseBody | |
35 | + public Customer getCustomerById(@PathVariable("customerId") String strCustomerId) throws ThingsboardException { | |
36 | + checkParameter("customerId", strCustomerId); | |
37 | + try { | |
38 | + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | |
39 | + return checkCustomerId(customerId); | |
40 | + } catch (Exception e) { | |
41 | + throw handleException(e); | |
42 | + } | |
43 | + } | |
44 | + | |
45 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
46 | + @RequestMapping(value = "/customer", method = RequestMethod.POST) | |
47 | + @ResponseBody | |
48 | + public Customer saveCustomer(@RequestBody Customer customer) throws ThingsboardException { | |
49 | + try { | |
50 | + customer.setTenantId(getCurrentUser().getTenantId()); | |
51 | + return checkNotNull(customerService.saveCustomer(customer)); | |
52 | + } catch (Exception e) { | |
53 | + throw handleException(e); | |
54 | + } | |
55 | + } | |
56 | + | |
57 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
58 | + @RequestMapping(value = "/customer/{customerId}", method = RequestMethod.DELETE) | |
59 | + @ResponseStatus(value = HttpStatus.OK) | |
60 | + public void deleteCustomer(@PathVariable("customerId") String strCustomerId) throws ThingsboardException { | |
61 | + checkParameter("customerId", strCustomerId); | |
62 | + try { | |
63 | + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | |
64 | + checkCustomerId(customerId); | |
65 | + customerService.deleteCustomer(customerId); | |
66 | + } catch (Exception e) { | |
67 | + throw handleException(e); | |
68 | + } | |
69 | + } | |
70 | + | |
71 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
72 | + @RequestMapping(value = "/customers", params = { "limit" }, method = RequestMethod.GET) | |
73 | + @ResponseBody | |
74 | + public TextPageData<Customer> getCustomers(@RequestParam int limit, | |
75 | + @RequestParam(required = false) String textSearch, | |
76 | + @RequestParam(required = false) String idOffset, | |
77 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
78 | + try { | |
79 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
80 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
81 | + return checkNotNull(customerService.findCustomersByTenantId(tenantId, pageLink)); | |
82 | + } catch (Exception e) { | |
83 | + throw handleException(e); | |
84 | + } | |
85 | + } | |
86 | + | |
87 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller; | |
17 | + | |
18 | +import org.springframework.http.HttpStatus; | |
19 | +import org.springframework.security.access.prepost.PreAuthorize; | |
20 | +import org.springframework.web.bind.annotation.*; | |
21 | +import org.thingsboard.server.common.data.Dashboard; | |
22 | +import org.thingsboard.server.common.data.id.CustomerId; | |
23 | +import org.thingsboard.server.common.data.id.DashboardId; | |
24 | +import org.thingsboard.server.common.data.id.TenantId; | |
25 | +import org.thingsboard.server.common.data.page.TextPageData; | |
26 | +import org.thingsboard.server.common.data.page.TextPageLink; | |
27 | +import org.thingsboard.server.dao.exception.IncorrectParameterException; | |
28 | +import org.thingsboard.server.dao.model.ModelConstants; | |
29 | +import org.thingsboard.server.exception.ThingsboardException; | |
30 | + | |
31 | +@RestController | |
32 | +@RequestMapping("/api") | |
33 | +public class DashboardController extends BaseController { | |
34 | + | |
35 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
36 | + @RequestMapping(value = "/dashboard/{dashboardId}", method = RequestMethod.GET) | |
37 | + @ResponseBody | |
38 | + public Dashboard getDashboardById(@PathVariable("dashboardId") String strDashboardId) throws ThingsboardException { | |
39 | + checkParameter("dashboardId", strDashboardId); | |
40 | + try { | |
41 | + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); | |
42 | + return checkDashboardId(dashboardId); | |
43 | + } catch (Exception e) { | |
44 | + throw handleException(e); | |
45 | + } | |
46 | + } | |
47 | + | |
48 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
49 | + @RequestMapping(value = "/dashboard", method = RequestMethod.POST) | |
50 | + @ResponseBody | |
51 | + public Dashboard saveDashboard(@RequestBody Dashboard dashboard) throws ThingsboardException { | |
52 | + try { | |
53 | + dashboard.setTenantId(getCurrentUser().getTenantId()); | |
54 | + return checkNotNull(dashboardService.saveDashboard(dashboard)); | |
55 | + } catch (Exception e) { | |
56 | + throw handleException(e); | |
57 | + } | |
58 | + } | |
59 | + | |
60 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
61 | + @RequestMapping(value = "/dashboard/{dashboardId}", method = RequestMethod.DELETE) | |
62 | + @ResponseStatus(value = HttpStatus.OK) | |
63 | + public void deleteDashboard(@PathVariable("dashboardId") String strDashboardId) throws ThingsboardException { | |
64 | + checkParameter("dashboardId", strDashboardId); | |
65 | + try { | |
66 | + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); | |
67 | + checkDashboardId(dashboardId); | |
68 | + dashboardService.deleteDashboard(dashboardId); | |
69 | + } catch (Exception e) { | |
70 | + throw handleException(e); | |
71 | + } | |
72 | + } | |
73 | + | |
74 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
75 | + @RequestMapping(value = "/customer/{customerId}/dashboard/{dashboardId}", method = RequestMethod.POST) | |
76 | + @ResponseBody | |
77 | + public Dashboard assignDashboardToCustomer(@PathVariable("customerId") String strCustomerId, | |
78 | + @PathVariable("dashboardId") String strDashboardId) throws ThingsboardException { | |
79 | + checkParameter("customerId", strCustomerId); | |
80 | + checkParameter("dashboardId", strDashboardId); | |
81 | + try { | |
82 | + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | |
83 | + checkCustomerId(customerId); | |
84 | + | |
85 | + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); | |
86 | + checkDashboardId(dashboardId); | |
87 | + | |
88 | + return checkNotNull(dashboardService.assignDashboardToCustomer(dashboardId, customerId)); | |
89 | + } catch (Exception e) { | |
90 | + throw handleException(e); | |
91 | + } | |
92 | + } | |
93 | + | |
94 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
95 | + @RequestMapping(value = "/customer/dashboard/{dashboardId}", method = RequestMethod.DELETE) | |
96 | + @ResponseBody | |
97 | + public Dashboard unassignDashboardFromCustomer(@PathVariable("dashboardId") String strDashboardId) throws ThingsboardException { | |
98 | + checkParameter("dashboardId", strDashboardId); | |
99 | + try { | |
100 | + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); | |
101 | + Dashboard dashboard = checkDashboardId(dashboardId); | |
102 | + if (dashboard.getCustomerId() == null || dashboard.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { | |
103 | + throw new IncorrectParameterException("Dashboard isn't assigned to any customer!"); | |
104 | + } | |
105 | + return checkNotNull(dashboardService.unassignDashboardFromCustomer(dashboardId)); | |
106 | + } catch (Exception e) { | |
107 | + throw handleException(e); | |
108 | + } | |
109 | + } | |
110 | + | |
111 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
112 | + @RequestMapping(value = "/tenant/dashboards", params = { "limit" }, method = RequestMethod.GET) | |
113 | + @ResponseBody | |
114 | + public TextPageData<Dashboard> getTenantDashboards( | |
115 | + @RequestParam int limit, | |
116 | + @RequestParam(required = false) String textSearch, | |
117 | + @RequestParam(required = false) String idOffset, | |
118 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
119 | + try { | |
120 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
121 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
122 | + return checkNotNull(dashboardService.findDashboardsByTenantId(tenantId, pageLink)); | |
123 | + } catch (Exception e) { | |
124 | + throw handleException(e); | |
125 | + } | |
126 | + } | |
127 | + | |
128 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
129 | + @RequestMapping(value = "/customer/{customerId}/dashboards", params = { "limit" }, method = RequestMethod.GET) | |
130 | + @ResponseBody | |
131 | + public TextPageData<Dashboard> getCustomerDashboards( | |
132 | + @PathVariable("customerId") String strCustomerId, | |
133 | + @RequestParam int limit, | |
134 | + @RequestParam(required = false) String textSearch, | |
135 | + @RequestParam(required = false) String idOffset, | |
136 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
137 | + checkParameter("customerId", strCustomerId); | |
138 | + try { | |
139 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
140 | + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | |
141 | + checkCustomerId(customerId); | |
142 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
143 | + return checkNotNull(dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, pageLink)); | |
144 | + } catch (Exception e) { | |
145 | + throw handleException(e); | |
146 | + } | |
147 | + } | |
148 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller; | |
17 | + | |
18 | +import org.springframework.http.HttpStatus; | |
19 | +import org.springframework.security.access.prepost.PreAuthorize; | |
20 | +import org.springframework.web.bind.annotation.*; | |
21 | +import org.thingsboard.server.common.data.Device; | |
22 | +import org.thingsboard.server.common.data.id.CustomerId; | |
23 | +import org.thingsboard.server.common.data.id.DeviceId; | |
24 | +import org.thingsboard.server.common.data.id.TenantId; | |
25 | +import org.thingsboard.server.common.data.page.TextPageData; | |
26 | +import org.thingsboard.server.common.data.page.TextPageLink; | |
27 | +import org.thingsboard.server.common.data.security.DeviceCredentials; | |
28 | +import org.thingsboard.server.dao.exception.IncorrectParameterException; | |
29 | +import org.thingsboard.server.dao.model.ModelConstants; | |
30 | +import org.thingsboard.server.exception.ThingsboardException; | |
31 | + | |
32 | +@RestController | |
33 | +@RequestMapping("/api") | |
34 | +public class DeviceController extends BaseController { | |
35 | + | |
36 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
37 | + @RequestMapping(value = "/device/{deviceId}", method = RequestMethod.GET) | |
38 | + @ResponseBody | |
39 | + public Device getDeviceById(@PathVariable("deviceId") String strDeviceId) throws ThingsboardException { | |
40 | + checkParameter("deviceId", strDeviceId); | |
41 | + try { | |
42 | + DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); | |
43 | + return checkDeviceId(deviceId); | |
44 | + } catch (Exception e) { | |
45 | + throw handleException(e); | |
46 | + } | |
47 | + } | |
48 | + | |
49 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
50 | + @RequestMapping(value = "/device", method = RequestMethod.POST) | |
51 | + @ResponseBody | |
52 | + public Device saveDevice(@RequestBody Device device) throws ThingsboardException { | |
53 | + try { | |
54 | + device.setTenantId(getCurrentUser().getTenantId()); | |
55 | + return checkNotNull(deviceService.saveDevice(device)); | |
56 | + } catch (Exception e) { | |
57 | + throw handleException(e); | |
58 | + } | |
59 | + } | |
60 | + | |
61 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
62 | + @RequestMapping(value = "/device/{deviceId}", method = RequestMethod.DELETE) | |
63 | + @ResponseStatus(value = HttpStatus.OK) | |
64 | + public void deleteDevice(@PathVariable("deviceId") String strDeviceId) throws ThingsboardException { | |
65 | + checkParameter("deviceId", strDeviceId); | |
66 | + try { | |
67 | + DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); | |
68 | + checkDeviceId(deviceId); | |
69 | + deviceService.deleteDevice(deviceId); | |
70 | + } catch (Exception e) { | |
71 | + throw handleException(e); | |
72 | + } | |
73 | + } | |
74 | + | |
75 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
76 | + @RequestMapping(value = "/customer/{customerId}/device/{deviceId}", method = RequestMethod.POST) | |
77 | + @ResponseBody | |
78 | + public Device assignDeviceToCustomer(@PathVariable("customerId") String strCustomerId, | |
79 | + @PathVariable("deviceId") String strDeviceId) throws ThingsboardException { | |
80 | + checkParameter("customerId", strCustomerId); | |
81 | + checkParameter("deviceId", strDeviceId); | |
82 | + try { | |
83 | + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | |
84 | + checkCustomerId(customerId); | |
85 | + | |
86 | + DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); | |
87 | + checkDeviceId(deviceId); | |
88 | + | |
89 | + return checkNotNull(deviceService.assignDeviceToCustomer(deviceId, customerId)); | |
90 | + } catch (Exception e) { | |
91 | + throw handleException(e); | |
92 | + } | |
93 | + } | |
94 | + | |
95 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
96 | + @RequestMapping(value = "/customer/device/{deviceId}", method = RequestMethod.DELETE) | |
97 | + @ResponseBody | |
98 | + public Device unassignDeviceFromCustomer(@PathVariable("deviceId") String strDeviceId) throws ThingsboardException { | |
99 | + checkParameter("deviceId", strDeviceId); | |
100 | + try { | |
101 | + DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); | |
102 | + Device device = checkDeviceId(deviceId); | |
103 | + if (device.getCustomerId() == null || device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { | |
104 | + throw new IncorrectParameterException("Device isn't assigned to any customer!"); | |
105 | + } | |
106 | + return checkNotNull(deviceService.unassignDeviceFromCustomer(deviceId)); | |
107 | + } catch (Exception e) { | |
108 | + throw handleException(e); | |
109 | + } | |
110 | + } | |
111 | + | |
112 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
113 | + @RequestMapping(value = "/device/{deviceId}/credentials", method = RequestMethod.GET) | |
114 | + @ResponseBody | |
115 | + public DeviceCredentials getDeviceCredentialsByDeviceId(@PathVariable("deviceId") String strDeviceId) throws ThingsboardException { | |
116 | + checkParameter("deviceId", strDeviceId); | |
117 | + try { | |
118 | + DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); | |
119 | + checkDeviceId(deviceId); | |
120 | + return checkNotNull(deviceCredentialsService.findDeviceCredentialsByDeviceId(deviceId)); | |
121 | + } catch (Exception e) { | |
122 | + throw handleException(e); | |
123 | + } | |
124 | + } | |
125 | + | |
126 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
127 | + @RequestMapping(value = "/device/credentials", method = RequestMethod.POST) | |
128 | + @ResponseBody | |
129 | + public DeviceCredentials saveDeviceCredentials(@RequestBody DeviceCredentials deviceCredentials) throws ThingsboardException { | |
130 | + checkNotNull(deviceCredentials); | |
131 | + try { | |
132 | + checkDeviceId(deviceCredentials.getDeviceId()); | |
133 | + return checkNotNull(deviceCredentialsService.updateDeviceCredentials(deviceCredentials)); | |
134 | + } catch (Exception e) { | |
135 | + throw handleException(e); | |
136 | + } | |
137 | + } | |
138 | + | |
139 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
140 | + @RequestMapping(value = "/tenant/devices", params = { "limit" }, method = RequestMethod.GET) | |
141 | + @ResponseBody | |
142 | + public TextPageData<Device> getTenantDevices( | |
143 | + @RequestParam int limit, | |
144 | + @RequestParam(required = false) String textSearch, | |
145 | + @RequestParam(required = false) String idOffset, | |
146 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
147 | + try { | |
148 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
149 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
150 | + return checkNotNull(deviceService.findDevicesByTenantId(tenantId, pageLink)); | |
151 | + } catch (Exception e) { | |
152 | + throw handleException(e); | |
153 | + } | |
154 | + } | |
155 | + | |
156 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
157 | + @RequestMapping(value = "/customer/{customerId}/devices", params = { "limit" }, method = RequestMethod.GET) | |
158 | + @ResponseBody | |
159 | + public TextPageData<Device> getCustomerDevices( | |
160 | + @PathVariable("customerId") String strCustomerId, | |
161 | + @RequestParam int limit, | |
162 | + @RequestParam(required = false) String textSearch, | |
163 | + @RequestParam(required = false) String idOffset, | |
164 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
165 | + checkParameter("customerId", strCustomerId); | |
166 | + try { | |
167 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
168 | + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | |
169 | + checkCustomerId(customerId); | |
170 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
171 | + return checkNotNull(deviceService.findDevicesByTenantIdAndCustomerId(tenantId, customerId, pageLink)); | |
172 | + } catch (Exception e) { | |
173 | + throw handleException(e); | |
174 | + } | |
175 | + } | |
176 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller; | |
17 | + | |
18 | +import org.springframework.beans.factory.annotation.Autowired; | |
19 | +import org.springframework.security.access.prepost.PreAuthorize; | |
20 | +import org.springframework.web.bind.annotation.*; | |
21 | +import org.thingsboard.server.common.data.EntityType; | |
22 | +import org.thingsboard.server.common.data.Event; | |
23 | +import org.thingsboard.server.common.data.id.*; | |
24 | +import org.thingsboard.server.common.data.page.TimePageData; | |
25 | +import org.thingsboard.server.common.data.page.TimePageLink; | |
26 | +import org.thingsboard.server.dao.event.EventService; | |
27 | +import org.thingsboard.server.dao.model.ModelConstants; | |
28 | +import org.thingsboard.server.exception.ThingsboardErrorCode; | |
29 | +import org.thingsboard.server.exception.ThingsboardException; | |
30 | + | |
31 | +@RestController | |
32 | +@RequestMapping("/api") | |
33 | +public class EventController extends BaseController { | |
34 | + | |
35 | + @Autowired | |
36 | + private EventService eventService; | |
37 | + | |
38 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") | |
39 | + @RequestMapping(value = "/events/{entityType}/{entityId}/{eventType}", method = RequestMethod.GET) | |
40 | + @ResponseBody | |
41 | + public TimePageData<Event> getEvents( | |
42 | + @PathVariable("entityType") String strEntityType, | |
43 | + @PathVariable("entityId") String strEntityId, | |
44 | + @PathVariable("eventType") String eventType, | |
45 | + @RequestParam("tenantId") String strTenantId, | |
46 | + @RequestParam int limit, | |
47 | + @RequestParam(required = false) Long startTime, | |
48 | + @RequestParam(required = false) Long endTime, | |
49 | + @RequestParam(required = false, defaultValue = "false") boolean ascOrder, | |
50 | + @RequestParam(required = false) String offset | |
51 | + ) throws ThingsboardException { | |
52 | + checkParameter("EntityId", strEntityId); | |
53 | + checkParameter("EntityType", strEntityType); | |
54 | + try { | |
55 | + TenantId tenantId = new TenantId(toUUID(strTenantId)); | |
56 | + if (!tenantId.getId().equals(ModelConstants.NULL_UUID) && | |
57 | + !tenantId.equals(getCurrentUser().getTenantId())) { | |
58 | + throw new ThingsboardException("You don't have permission to perform this operation!", | |
59 | + ThingsboardErrorCode.PERMISSION_DENIED); | |
60 | + } | |
61 | + TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); | |
62 | + return checkNotNull(eventService.findEvents(tenantId, getEntityId(strEntityType, strEntityId), eventType, pageLink)); | |
63 | + } catch (Exception e) { | |
64 | + throw handleException(e); | |
65 | + } | |
66 | + } | |
67 | + | |
68 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") | |
69 | + @RequestMapping(value = "/events/{entityType}/{entityId}", method = RequestMethod.GET) | |
70 | + @ResponseBody | |
71 | + public TimePageData<Event> getEvents( | |
72 | + @PathVariable("entityType") String strEntityType, | |
73 | + @PathVariable("entityId") String strEntityId, | |
74 | + @RequestParam("tenantId") String strTenantId, | |
75 | + @RequestParam int limit, | |
76 | + @RequestParam(required = false) Long startTime, | |
77 | + @RequestParam(required = false) Long endTime, | |
78 | + @RequestParam(required = false, defaultValue = "false") boolean ascOrder, | |
79 | + @RequestParam(required = false) String offset | |
80 | + ) throws ThingsboardException { | |
81 | + checkParameter("EntityId", strEntityId); | |
82 | + checkParameter("EntityType", strEntityType); | |
83 | + try { | |
84 | + TenantId tenantId = new TenantId(toUUID(strTenantId)); | |
85 | + if (!tenantId.getId().equals(ModelConstants.NULL_UUID) && | |
86 | + !tenantId.equals(getCurrentUser().getTenantId())) { | |
87 | + throw new ThingsboardException("You don't have permission to perform this operation!", | |
88 | + ThingsboardErrorCode.PERMISSION_DENIED); | |
89 | + } | |
90 | + TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); | |
91 | + return checkNotNull(eventService.findEvents(tenantId, getEntityId(strEntityType, strEntityId), pageLink)); | |
92 | + } catch (Exception e) { | |
93 | + throw handleException(e); | |
94 | + } | |
95 | + } | |
96 | + | |
97 | + | |
98 | + private EntityId getEntityId(String strEntityType, String strEntityId) throws ThingsboardException { | |
99 | + EntityId entityId; | |
100 | + EntityType entityType = EntityType.valueOf(strEntityType); | |
101 | + switch (entityType) { | |
102 | + case RULE: | |
103 | + entityId = new RuleId(toUUID(strEntityId)); | |
104 | + break; | |
105 | + case PLUGIN: | |
106 | + entityId = new PluginId(toUUID(strEntityId)); | |
107 | + break; | |
108 | + case DEVICE: | |
109 | + entityId = new DeviceId(toUUID(strEntityId)); | |
110 | + break; | |
111 | + default: | |
112 | + throw new ThingsboardException("EntityType ['" + entityType + "'] is incorrect!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); | |
113 | + } | |
114 | + return entityId; | |
115 | + } | |
116 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller; | |
17 | + | |
18 | +import org.springframework.http.HttpStatus; | |
19 | +import org.springframework.security.access.prepost.PreAuthorize; | |
20 | +import org.springframework.web.bind.annotation.*; | |
21 | +import org.thingsboard.server.common.data.id.PluginId; | |
22 | +import org.thingsboard.server.common.data.id.TenantId; | |
23 | +import org.thingsboard.server.common.data.page.TextPageData; | |
24 | +import org.thingsboard.server.common.data.page.TextPageLink; | |
25 | +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | |
26 | +import org.thingsboard.server.common.data.plugin.PluginMetaData; | |
27 | +import org.thingsboard.server.common.data.security.Authority; | |
28 | +import org.thingsboard.server.common.data.widget.WidgetsBundle; | |
29 | +import org.thingsboard.server.dao.model.ModelConstants; | |
30 | +import org.thingsboard.server.exception.ThingsboardException; | |
31 | + | |
32 | +import java.util.List; | |
33 | + | |
34 | +@RestController | |
35 | +@RequestMapping("/api") | |
36 | +public class PluginController extends BaseController { | |
37 | + | |
38 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
39 | + @RequestMapping(value = "/plugin/{pluginId}", method = RequestMethod.GET) | |
40 | + @ResponseBody | |
41 | + public PluginMetaData getPluginById(@PathVariable("pluginId") String strPluginId) throws ThingsboardException { | |
42 | + checkParameter("pluginId", strPluginId); | |
43 | + try { | |
44 | + PluginId pluginId = new PluginId(toUUID(strPluginId)); | |
45 | + return checkPlugin(pluginService.findPluginById(pluginId)); | |
46 | + } catch (Exception e) { | |
47 | + throw handleException(e); | |
48 | + } | |
49 | + } | |
50 | + | |
51 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
52 | + @RequestMapping(value = "/plugin/token/{pluginToken}", method = RequestMethod.GET) | |
53 | + @ResponseBody | |
54 | + public PluginMetaData getPluginByToken(@PathVariable("pluginToken") String pluginToken) throws ThingsboardException { | |
55 | + checkParameter("pluginToken", pluginToken); | |
56 | + try { | |
57 | + return checkPlugin(pluginService.findPluginByApiToken(pluginToken)); | |
58 | + } catch (Exception e) { | |
59 | + throw handleException(e); | |
60 | + } | |
61 | + } | |
62 | + | |
63 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
64 | + @RequestMapping(value = "/plugin", method = RequestMethod.POST) | |
65 | + @ResponseBody | |
66 | + public PluginMetaData savePlugin(@RequestBody PluginMetaData source) throws ThingsboardException { | |
67 | + try { | |
68 | + boolean created = source.getId() == null; | |
69 | + source.setTenantId(getCurrentUser().getTenantId()); | |
70 | + PluginMetaData plugin = checkNotNull(pluginService.savePlugin(source)); | |
71 | + actorService.onPluginStateChange(plugin.getTenantId(), plugin.getId(), | |
72 | + created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); | |
73 | + return plugin; | |
74 | + } catch (Exception e) { | |
75 | + throw handleException(e); | |
76 | + } | |
77 | + } | |
78 | + | |
79 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
80 | + @RequestMapping(value = "/plugin/{pluginId}/activate", method = RequestMethod.POST) | |
81 | + @ResponseStatus(value = HttpStatus.OK) | |
82 | + public void activatePluginById(@PathVariable("pluginId") String strPluginId) throws ThingsboardException { | |
83 | + checkParameter("pluginId", strPluginId); | |
84 | + try { | |
85 | + PluginId pluginId = new PluginId(toUUID(strPluginId)); | |
86 | + PluginMetaData plugin = checkPlugin(pluginService.findPluginById(pluginId)); | |
87 | + pluginService.activatePluginById(pluginId); | |
88 | + actorService.onPluginStateChange(plugin.getTenantId(), plugin.getId(), ComponentLifecycleEvent.ACTIVATED); | |
89 | + } catch (Exception e) { | |
90 | + throw handleException(e); | |
91 | + } | |
92 | + } | |
93 | + | |
94 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
95 | + @RequestMapping(value = "/plugin/{pluginId}/suspend", method = RequestMethod.POST) | |
96 | + @ResponseStatus(value = HttpStatus.OK) | |
97 | + public void suspendPluginById(@PathVariable("pluginId") String strPluginId) throws ThingsboardException { | |
98 | + checkParameter("pluginId", strPluginId); | |
99 | + try { | |
100 | + PluginId pluginId = new PluginId(toUUID(strPluginId)); | |
101 | + PluginMetaData plugin = checkPlugin(pluginService.findPluginById(pluginId)); | |
102 | + pluginService.suspendPluginById(pluginId); | |
103 | + actorService.onPluginStateChange(plugin.getTenantId(), plugin.getId(), ComponentLifecycleEvent.SUSPENDED); | |
104 | + } catch (Exception e) { | |
105 | + throw handleException(e); | |
106 | + } | |
107 | + } | |
108 | + | |
109 | + @PreAuthorize("hasAuthority('SYS_ADMIN')") | |
110 | + @RequestMapping(value = "/plugin/system", params = {"limit"}, method = RequestMethod.GET) | |
111 | + @ResponseBody | |
112 | + public TextPageData<PluginMetaData> getSystemPlugins( | |
113 | + @RequestParam int limit, | |
114 | + @RequestParam(required = false) String textSearch, | |
115 | + @RequestParam(required = false) String idOffset, | |
116 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
117 | + try { | |
118 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
119 | + return checkNotNull(pluginService.findSystemPlugins(pageLink)); | |
120 | + } catch (Exception e) { | |
121 | + throw handleException(e); | |
122 | + } | |
123 | + } | |
124 | + | |
125 | + @PreAuthorize("hasAuthority('SYS_ADMIN')") | |
126 | + @RequestMapping(value = "/plugin/tenant/{tenantId}", params = {"limit"}, method = RequestMethod.GET) | |
127 | + @ResponseBody | |
128 | + public TextPageData<PluginMetaData> getTenantPlugins( | |
129 | + @PathVariable("tenantId") String strTenantId, | |
130 | + @RequestParam int limit, | |
131 | + @RequestParam(required = false) String textSearch, | |
132 | + @RequestParam(required = false) String idOffset, | |
133 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
134 | + checkParameter("tenantId", strTenantId); | |
135 | + try { | |
136 | + TenantId tenantId = new TenantId(toUUID(strTenantId)); | |
137 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
138 | + return checkNotNull(pluginService.findTenantPlugins(tenantId, pageLink)); | |
139 | + } catch (Exception e) { | |
140 | + throw handleException(e); | |
141 | + } | |
142 | + } | |
143 | + | |
144 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
145 | + @RequestMapping(value = "/plugins", method = RequestMethod.GET) | |
146 | + @ResponseBody | |
147 | + public List<PluginMetaData> getPlugins() throws ThingsboardException { | |
148 | + try { | |
149 | + if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) { | |
150 | + return checkNotNull(pluginService.findSystemPlugins()); | |
151 | + } else { | |
152 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
153 | + List<PluginMetaData> plugins = checkNotNull(pluginService.findAllTenantPluginsByTenantId(tenantId)); | |
154 | + plugins.stream() | |
155 | + .filter(plugin -> plugin.getTenantId().getId().equals(ModelConstants.NULL_UUID)) | |
156 | + .forEach(plugin -> plugin.setConfiguration(null)); | |
157 | + return plugins; | |
158 | + } | |
159 | + } catch (Exception e) { | |
160 | + throw handleException(e); | |
161 | + } | |
162 | + } | |
163 | + | |
164 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
165 | + @RequestMapping(value = "/plugin", params = {"limit"}, method = RequestMethod.GET) | |
166 | + @ResponseBody | |
167 | + public TextPageData<PluginMetaData> getTenantPlugins( | |
168 | + @RequestParam int limit, | |
169 | + @RequestParam(required = false) String textSearch, | |
170 | + @RequestParam(required = false) String idOffset, | |
171 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
172 | + try { | |
173 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
174 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
175 | + return checkNotNull(pluginService.findTenantPlugins(tenantId, pageLink)); | |
176 | + } catch (Exception e) { | |
177 | + throw handleException(e); | |
178 | + } | |
179 | + } | |
180 | + | |
181 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
182 | + @RequestMapping(value = "/plugin/{pluginId}", method = RequestMethod.DELETE) | |
183 | + @ResponseStatus(value = HttpStatus.OK) | |
184 | + public void deletePlugin(@PathVariable("pluginId") String strPluginId) throws ThingsboardException { | |
185 | + checkParameter("pluginId", strPluginId); | |
186 | + try { | |
187 | + PluginId pluginId = new PluginId(toUUID(strPluginId)); | |
188 | + PluginMetaData plugin = checkPlugin(pluginService.findPluginById(pluginId)); | |
189 | + pluginService.deletePluginById(pluginId); | |
190 | + actorService.onPluginStateChange(plugin.getTenantId(), plugin.getId(), ComponentLifecycleEvent.DELETED); | |
191 | + } catch (Exception e) { | |
192 | + throw handleException(e); | |
193 | + } | |
194 | + } | |
195 | + | |
196 | + | |
197 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller; | |
17 | + | |
18 | +import org.springframework.http.HttpStatus; | |
19 | +import org.springframework.security.access.prepost.PreAuthorize; | |
20 | +import org.springframework.web.bind.annotation.*; | |
21 | +import org.thingsboard.server.common.data.id.RuleId; | |
22 | +import org.thingsboard.server.common.data.id.TenantId; | |
23 | +import org.thingsboard.server.common.data.page.TextPageData; | |
24 | +import org.thingsboard.server.common.data.page.TextPageLink; | |
25 | +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | |
26 | +import org.thingsboard.server.common.data.plugin.PluginMetaData; | |
27 | +import org.thingsboard.server.common.data.rule.RuleMetaData; | |
28 | +import org.thingsboard.server.common.data.security.Authority; | |
29 | +import org.thingsboard.server.exception.ThingsboardException; | |
30 | + | |
31 | +import java.util.List; | |
32 | + | |
33 | +@RestController | |
34 | +@RequestMapping("/api") | |
35 | +public class RuleController extends BaseController { | |
36 | + | |
37 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
38 | + @RequestMapping(value = "/rule/{ruleId}", method = RequestMethod.GET) | |
39 | + @ResponseBody | |
40 | + public RuleMetaData getRuleById(@PathVariable("ruleId") String strRuleId) throws ThingsboardException { | |
41 | + checkParameter("ruleId", strRuleId); | |
42 | + try { | |
43 | + RuleId ruleId = new RuleId(toUUID(strRuleId)); | |
44 | + return checkRule(ruleService.findRuleById(ruleId)); | |
45 | + } catch (Exception e) { | |
46 | + throw handleException(e); | |
47 | + } | |
48 | + } | |
49 | + | |
50 | + | |
51 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
52 | + @RequestMapping(value = "/rule/token/{pluginToken}", method = RequestMethod.GET) | |
53 | + @ResponseBody | |
54 | + public List<RuleMetaData> getRulesByPluginToken(@PathVariable("pluginToken") String pluginToken) throws ThingsboardException { | |
55 | + checkParameter("pluginToken", pluginToken); | |
56 | + try { | |
57 | + PluginMetaData plugin = checkPlugin(pluginService.findPluginByApiToken(pluginToken)); | |
58 | + return ruleService.findPluginRules(plugin.getApiToken()); | |
59 | + } catch (Exception e) { | |
60 | + throw handleException(e); | |
61 | + } | |
62 | + } | |
63 | + | |
64 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
65 | + @RequestMapping(value = "/rule", method = RequestMethod.POST) | |
66 | + @ResponseBody | |
67 | + public RuleMetaData saveRule(@RequestBody RuleMetaData source) throws ThingsboardException { | |
68 | + try { | |
69 | + boolean created = source.getId() == null; | |
70 | + source.setTenantId(getCurrentUser().getTenantId()); | |
71 | + RuleMetaData rule = checkNotNull(ruleService.saveRule(source)); | |
72 | + actorService.onRuleStateChange(rule.getTenantId(), rule.getId(), | |
73 | + created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); | |
74 | + return rule; | |
75 | + } catch (Exception e) { | |
76 | + throw handleException(e); | |
77 | + } | |
78 | + } | |
79 | + | |
80 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
81 | + @RequestMapping(value = "/rule/{ruleId}/activate", method = RequestMethod.POST) | |
82 | + @ResponseStatus(value = HttpStatus.OK) | |
83 | + public void activateRuleById(@PathVariable("ruleId") String strRuleId) throws ThingsboardException { | |
84 | + checkParameter("ruleId", strRuleId); | |
85 | + try { | |
86 | + RuleId ruleId = new RuleId(toUUID(strRuleId)); | |
87 | + RuleMetaData rule = checkRule(ruleService.findRuleById(ruleId)); | |
88 | + ruleService.activateRuleById(ruleId); | |
89 | + actorService.onRuleStateChange(rule.getTenantId(), rule.getId(), ComponentLifecycleEvent.ACTIVATED); | |
90 | + } catch (Exception e) { | |
91 | + throw handleException(e); | |
92 | + } | |
93 | + } | |
94 | + | |
95 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
96 | + @RequestMapping(value = "/rule/{ruleId}/suspend", method = RequestMethod.POST) | |
97 | + @ResponseStatus(value = HttpStatus.OK) | |
98 | + public void suspendRuleById(@PathVariable("ruleId") String strRuleId) throws ThingsboardException { | |
99 | + checkParameter("ruleId", strRuleId); | |
100 | + try { | |
101 | + RuleId ruleId = new RuleId(toUUID(strRuleId)); | |
102 | + RuleMetaData rule = checkRule(ruleService.findRuleById(ruleId)); | |
103 | + ruleService.suspendRuleById(ruleId); | |
104 | + actorService.onRuleStateChange(rule.getTenantId(), rule.getId(), ComponentLifecycleEvent.SUSPENDED); | |
105 | + } catch (Exception e) { | |
106 | + throw handleException(e); | |
107 | + } | |
108 | + } | |
109 | + | |
110 | + @PreAuthorize("hasAuthority('SYS_ADMIN')") | |
111 | + @RequestMapping(value = "/rule/system", params = {"limit"}, method = RequestMethod.GET) | |
112 | + @ResponseBody | |
113 | + public TextPageData<RuleMetaData> getSystemRules( | |
114 | + @RequestParam int limit, | |
115 | + @RequestParam(required = false) String textSearch, | |
116 | + @RequestParam(required = false) String idOffset, | |
117 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
118 | + try { | |
119 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
120 | + return checkNotNull(ruleService.findSystemRules(pageLink)); | |
121 | + } catch (Exception e) { | |
122 | + throw handleException(e); | |
123 | + } | |
124 | + } | |
125 | + | |
126 | + @PreAuthorize("hasAuthority('SYS_ADMIN')") | |
127 | + @RequestMapping(value = "/rule/tenant/{tenantId}", params = {"limit"}, method = RequestMethod.GET) | |
128 | + @ResponseBody | |
129 | + public TextPageData<RuleMetaData> getTenantRules( | |
130 | + @PathVariable("tenantId") String strTenantId, | |
131 | + @RequestParam int limit, | |
132 | + @RequestParam(required = false) String textSearch, | |
133 | + @RequestParam(required = false) String idOffset, | |
134 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
135 | + checkParameter("tenantId", strTenantId); | |
136 | + try { | |
137 | + TenantId tenantId = new TenantId(toUUID(strTenantId)); | |
138 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
139 | + return checkNotNull(ruleService.findTenantRules(tenantId, pageLink)); | |
140 | + } catch (Exception e) { | |
141 | + throw handleException(e); | |
142 | + } | |
143 | + } | |
144 | + | |
145 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
146 | + @RequestMapping(value = "/rules", method = RequestMethod.GET) | |
147 | + @ResponseBody | |
148 | + public List<RuleMetaData> getRules() throws ThingsboardException { | |
149 | + try { | |
150 | + if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) { | |
151 | + return checkNotNull(ruleService.findSystemRules()); | |
152 | + } else { | |
153 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
154 | + return checkNotNull(ruleService.findAllTenantRulesByTenantId(tenantId)); | |
155 | + } | |
156 | + } catch (Exception e) { | |
157 | + throw handleException(e); | |
158 | + } | |
159 | + } | |
160 | + | |
161 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
162 | + @RequestMapping(value = "/rule", params = {"limit"}, method = RequestMethod.GET) | |
163 | + @ResponseBody | |
164 | + public TextPageData<RuleMetaData> getTenantRules( | |
165 | + @RequestParam int limit, | |
166 | + @RequestParam(required = false) String textSearch, | |
167 | + @RequestParam(required = false) String idOffset, | |
168 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
169 | + try { | |
170 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
171 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
172 | + return checkNotNull(ruleService.findTenantRules(tenantId, pageLink)); | |
173 | + } catch (Exception e) { | |
174 | + throw handleException(e); | |
175 | + } | |
176 | + } | |
177 | + | |
178 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
179 | + @RequestMapping(value = "/rule/{ruleId}", method = RequestMethod.DELETE) | |
180 | + @ResponseStatus(value = HttpStatus.OK) | |
181 | + public void deleteRule(@PathVariable("ruleId") String strRuleId) throws ThingsboardException { | |
182 | + checkParameter("ruleId", strRuleId); | |
183 | + try { | |
184 | + RuleId ruleId = new RuleId(toUUID(strRuleId)); | |
185 | + RuleMetaData rule = checkRule(ruleService.findRuleById(ruleId)); | |
186 | + ruleService.deleteRuleById(ruleId); | |
187 | + actorService.onRuleStateChange(rule.getTenantId(), rule.getId(), ComponentLifecycleEvent.DELETED); | |
188 | + } catch (Exception e) { | |
189 | + throw handleException(e); | |
190 | + } | |
191 | + } | |
192 | + | |
193 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller; | |
17 | + | |
18 | +import org.springframework.beans.factory.annotation.Autowired; | |
19 | +import org.springframework.http.HttpStatus; | |
20 | +import org.springframework.security.access.prepost.PreAuthorize; | |
21 | +import org.springframework.web.bind.annotation.*; | |
22 | +import org.thingsboard.server.common.data.Tenant; | |
23 | +import org.thingsboard.server.common.data.id.TenantId; | |
24 | +import org.thingsboard.server.common.data.page.TextPageData; | |
25 | +import org.thingsboard.server.common.data.page.TextPageLink; | |
26 | +import org.thingsboard.server.dao.tenant.TenantService; | |
27 | +import org.thingsboard.server.exception.ThingsboardException; | |
28 | + | |
29 | +@RestController | |
30 | +@RequestMapping("/api") | |
31 | +public class TenantController extends BaseController { | |
32 | + | |
33 | + @Autowired | |
34 | + private TenantService tenantService; | |
35 | + | |
36 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
37 | + @RequestMapping(value = "/tenant/{tenantId}", method = RequestMethod.GET) | |
38 | + @ResponseBody | |
39 | + public Tenant getTenantById(@PathVariable("tenantId") String strTenantId) throws ThingsboardException { | |
40 | + checkParameter("tenantId", strTenantId); | |
41 | + try { | |
42 | + TenantId tenantId = new TenantId(toUUID(strTenantId)); | |
43 | + checkTenantId(tenantId); | |
44 | + return checkNotNull(tenantService.findTenantById(tenantId)); | |
45 | + } catch (Exception e) { | |
46 | + throw handleException(e); | |
47 | + } | |
48 | + } | |
49 | + | |
50 | + @PreAuthorize("hasAuthority('SYS_ADMIN')") | |
51 | + @RequestMapping(value = "/tenant", method = RequestMethod.POST) | |
52 | + @ResponseBody | |
53 | + public Tenant saveTenant(@RequestBody Tenant tenant) throws ThingsboardException { | |
54 | + try { | |
55 | + return checkNotNull(tenantService.saveTenant(tenant)); | |
56 | + } catch (Exception e) { | |
57 | + throw handleException(e); | |
58 | + } | |
59 | + } | |
60 | + | |
61 | + @PreAuthorize("hasAuthority('SYS_ADMIN')") | |
62 | + @RequestMapping(value = "/tenant/{tenantId}", method = RequestMethod.DELETE) | |
63 | + @ResponseStatus(value = HttpStatus.OK) | |
64 | + public void deleteTenant(@PathVariable("tenantId") String strTenantId) throws ThingsboardException { | |
65 | + checkParameter("tenantId", strTenantId); | |
66 | + try { | |
67 | + TenantId tenantId = new TenantId(toUUID(strTenantId)); | |
68 | + tenantService.deleteTenant(tenantId); | |
69 | + } catch (Exception e) { | |
70 | + throw handleException(e); | |
71 | + } | |
72 | + } | |
73 | + | |
74 | + @PreAuthorize("hasAuthority('SYS_ADMIN')") | |
75 | + @RequestMapping(value = "/tenants", params = { "limit" }, method = RequestMethod.GET) | |
76 | + @ResponseBody | |
77 | + public TextPageData<Tenant> getTenants(@RequestParam int limit, | |
78 | + @RequestParam(required = false) String textSearch, | |
79 | + @RequestParam(required = false) String idOffset, | |
80 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
81 | + try { | |
82 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
83 | + return checkNotNull(tenantService.findTenants(pageLink)); | |
84 | + } catch (Exception e) { | |
85 | + throw handleException(e); | |
86 | + } | |
87 | + } | |
88 | + | |
89 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller; | |
17 | + | |
18 | +import org.springframework.beans.factory.annotation.Autowired; | |
19 | +import org.springframework.http.HttpStatus; | |
20 | +import org.springframework.security.access.prepost.PreAuthorize; | |
21 | +import org.springframework.web.bind.annotation.*; | |
22 | +import org.thingsboard.server.common.data.User; | |
23 | +import org.thingsboard.server.common.data.id.CustomerId; | |
24 | +import org.thingsboard.server.common.data.id.TenantId; | |
25 | +import org.thingsboard.server.common.data.id.UserId; | |
26 | +import org.thingsboard.server.common.data.page.TextPageData; | |
27 | +import org.thingsboard.server.common.data.page.TextPageLink; | |
28 | +import org.thingsboard.server.common.data.security.Authority; | |
29 | +import org.thingsboard.server.common.data.security.UserCredentials; | |
30 | +import org.thingsboard.server.exception.ThingsboardErrorCode; | |
31 | +import org.thingsboard.server.exception.ThingsboardException; | |
32 | +import org.thingsboard.server.service.mail.MailService; | |
33 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
34 | + | |
35 | +import javax.servlet.http.HttpServletRequest; | |
36 | + | |
37 | +@RestController | |
38 | +@RequestMapping("/api") | |
39 | +public class UserController extends BaseController { | |
40 | + | |
41 | + @Autowired | |
42 | + private MailService mailService; | |
43 | + | |
44 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") | |
45 | + @RequestMapping(value = "/user/{userId}", method = RequestMethod.GET) | |
46 | + @ResponseBody | |
47 | + public User getUserById(@PathVariable("userId") String strUserId) throws ThingsboardException { | |
48 | + checkParameter("userId", strUserId); | |
49 | + try { | |
50 | + UserId userId = new UserId(toUUID(strUserId)); | |
51 | + SecurityUser authUser = getCurrentUser(); | |
52 | + if (authUser.getAuthority() == Authority.CUSTOMER_USER && !authUser.getId().equals(userId)) { | |
53 | + throw new ThingsboardException("You don't have permission to perform this operation!", | |
54 | + ThingsboardErrorCode.PERMISSION_DENIED); | |
55 | + } | |
56 | + return checkUserId(userId); | |
57 | + } catch (Exception e) { | |
58 | + throw handleException(e); | |
59 | + } | |
60 | + } | |
61 | + | |
62 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") | |
63 | + @RequestMapping(value = "/user", method = RequestMethod.POST) | |
64 | + @ResponseBody | |
65 | + public User saveUser(@RequestBody User user, | |
66 | + HttpServletRequest request) throws ThingsboardException { | |
67 | + try { | |
68 | + SecurityUser authUser = getCurrentUser(); | |
69 | + if (authUser.getAuthority() == Authority.CUSTOMER_USER && !authUser.getId().equals(user.getId())) { | |
70 | + throw new ThingsboardException("You don't have permission to perform this operation!", | |
71 | + ThingsboardErrorCode.PERMISSION_DENIED); | |
72 | + } | |
73 | + boolean sendEmail = user.getId() == null; | |
74 | + if (getCurrentUser().getAuthority() == Authority.TENANT_ADMIN) { | |
75 | + user.setTenantId(getCurrentUser().getTenantId()); | |
76 | + } | |
77 | + User savedUser = checkNotNull(userService.saveUser(user)); | |
78 | + if (sendEmail) { | |
79 | + UserCredentials userCredentials = userService.findUserCredentialsByUserId(savedUser.getId()); | |
80 | + String baseUrl = String.format("%s://%s:%d", | |
81 | + request.getScheme(), | |
82 | + request.getServerName(), | |
83 | + request.getServerPort()); | |
84 | + String activateUrl = String.format("%s/api/noauth/activate?activateToken=%s", baseUrl, | |
85 | + userCredentials.getActivateToken()); | |
86 | + String email = savedUser.getEmail(); | |
87 | + try { | |
88 | + mailService.sendActivationEmail(activateUrl, email); | |
89 | + } catch (ThingsboardException e) { | |
90 | + userService.deleteUser(savedUser.getId()); | |
91 | + throw e; | |
92 | + } | |
93 | + } | |
94 | + return savedUser; | |
95 | + } catch (Exception e) { | |
96 | + throw handleException(e); | |
97 | + } | |
98 | + } | |
99 | + | |
100 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
101 | + @RequestMapping(value = "/user/sendActivationMail", method = RequestMethod.POST) | |
102 | + @ResponseStatus(value = HttpStatus.OK) | |
103 | + public void sendActivationEmail( | |
104 | + @RequestParam(value = "email") String email, | |
105 | + HttpServletRequest request) throws ThingsboardException { | |
106 | + try { | |
107 | + User user = checkNotNull(userService.findUserByEmail(email)); | |
108 | + UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getId()); | |
109 | + if (!userCredentials.isEnabled()) { | |
110 | + String baseUrl = String.format("%s://%s:%d", | |
111 | + request.getScheme(), | |
112 | + request.getServerName(), | |
113 | + request.getServerPort()); | |
114 | + String activateUrl = String.format("%s/api/noauth/activate?activateToken=%s", baseUrl, | |
115 | + userCredentials.getActivateToken()); | |
116 | + mailService.sendActivationEmail(activateUrl, email); | |
117 | + } else { | |
118 | + throw new ThingsboardException("User is already active!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); | |
119 | + } | |
120 | + } catch (Exception e) { | |
121 | + throw handleException(e); | |
122 | + } | |
123 | + } | |
124 | + | |
125 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
126 | + @RequestMapping(value = "/user/{userId}", method = RequestMethod.DELETE) | |
127 | + @ResponseStatus(value = HttpStatus.OK) | |
128 | + public void deleteUser(@PathVariable("userId") String strUserId) throws ThingsboardException { | |
129 | + checkParameter("userId", strUserId); | |
130 | + try { | |
131 | + UserId userId = new UserId(toUUID(strUserId)); | |
132 | + checkUserId(userId); | |
133 | + userService.deleteUser(userId); | |
134 | + } catch (Exception e) { | |
135 | + throw handleException(e); | |
136 | + } | |
137 | + } | |
138 | + | |
139 | + @PreAuthorize("hasAuthority('SYS_ADMIN')") | |
140 | + @RequestMapping(value = "/tenant/{tenantId}/users", params = { "limit" }, method = RequestMethod.GET) | |
141 | + @ResponseBody | |
142 | + public TextPageData<User> getTenantAdmins( | |
143 | + @PathVariable("tenantId") String strTenantId, | |
144 | + @RequestParam int limit, | |
145 | + @RequestParam(required = false) String textSearch, | |
146 | + @RequestParam(required = false) String idOffset, | |
147 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
148 | + checkParameter("tenantId", strTenantId); | |
149 | + try { | |
150 | + TenantId tenantId = new TenantId(toUUID(strTenantId)); | |
151 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
152 | + return checkNotNull(userService.findTenantAdmins(tenantId, pageLink)); | |
153 | + } catch (Exception e) { | |
154 | + throw handleException(e); | |
155 | + } | |
156 | + } | |
157 | + | |
158 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
159 | + @RequestMapping(value = "/customer/{customerId}/users", params = { "limit" }, method = RequestMethod.GET) | |
160 | + @ResponseBody | |
161 | + public TextPageData<User> getCustomerUsers( | |
162 | + @PathVariable("customerId") String strCustomerId, | |
163 | + @RequestParam int limit, | |
164 | + @RequestParam(required = false) String textSearch, | |
165 | + @RequestParam(required = false) String idOffset, | |
166 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
167 | + checkParameter("customerId", strCustomerId); | |
168 | + try { | |
169 | + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | |
170 | + checkCustomerId(customerId); | |
171 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
172 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
173 | + return checkNotNull(userService.findCustomerUsers(tenantId, customerId, pageLink)); | |
174 | + } catch (Exception e) { | |
175 | + throw handleException(e); | |
176 | + } | |
177 | + } | |
178 | + | |
179 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller; | |
17 | + | |
18 | +import org.springframework.http.HttpStatus; | |
19 | +import org.springframework.security.access.prepost.PreAuthorize; | |
20 | +import org.springframework.web.bind.annotation.*; | |
21 | +import org.thingsboard.server.common.data.id.TenantId; | |
22 | +import org.thingsboard.server.common.data.id.WidgetTypeId; | |
23 | +import org.thingsboard.server.common.data.security.Authority; | |
24 | +import org.thingsboard.server.common.data.widget.WidgetType; | |
25 | +import org.thingsboard.server.dao.model.ModelConstants; | |
26 | +import org.thingsboard.server.exception.ThingsboardException; | |
27 | + | |
28 | +import java.util.List; | |
29 | + | |
30 | +@RestController | |
31 | +@RequestMapping("/api") | |
32 | +public class WidgetTypeController extends BaseController { | |
33 | + | |
34 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
35 | + @RequestMapping(value = "/widgetType/{widgetTypeId}", method = RequestMethod.GET) | |
36 | + @ResponseBody | |
37 | + public WidgetType getWidgetTypeById(@PathVariable("widgetTypeId") String strWidgetTypeId) throws ThingsboardException { | |
38 | + checkParameter("widgetTypeId", strWidgetTypeId); | |
39 | + try { | |
40 | + WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId)); | |
41 | + return checkWidgetTypeId(widgetTypeId, false); | |
42 | + } catch (Exception e) { | |
43 | + throw handleException(e); | |
44 | + } | |
45 | + } | |
46 | + | |
47 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
48 | + @RequestMapping(value = "/widgetType", method = RequestMethod.POST) | |
49 | + @ResponseBody | |
50 | + public WidgetType saveWidgetType(@RequestBody WidgetType widgetType) throws ThingsboardException { | |
51 | + try { | |
52 | + if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) { | |
53 | + widgetType.setTenantId(new TenantId(ModelConstants.NULL_UUID)); | |
54 | + } else { | |
55 | + widgetType.setTenantId(getCurrentUser().getTenantId()); | |
56 | + } | |
57 | + return checkNotNull(widgetTypeService.saveWidgetType(widgetType)); | |
58 | + } catch (Exception e) { | |
59 | + throw handleException(e); | |
60 | + } | |
61 | + } | |
62 | + | |
63 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
64 | + @RequestMapping(value = "/widgetType/{widgetTypeId}", method = RequestMethod.DELETE) | |
65 | + @ResponseStatus(value = HttpStatus.OK) | |
66 | + public void deleteWidgetType(@PathVariable("widgetTypeId") String strWidgetTypeId) throws ThingsboardException { | |
67 | + checkParameter("widgetTypeId", strWidgetTypeId); | |
68 | + try { | |
69 | + WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId)); | |
70 | + checkWidgetTypeId(widgetTypeId, true); | |
71 | + widgetTypeService.deleteWidgetType(widgetTypeId); | |
72 | + } catch (Exception e) { | |
73 | + throw handleException(e); | |
74 | + } | |
75 | + } | |
76 | + | |
77 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
78 | + @RequestMapping(value = "/widgetTypes", params = { "isSystem", "bundleAlias"}, method = RequestMethod.GET) | |
79 | + @ResponseBody | |
80 | + public List<WidgetType> getBundleWidgetTypes( | |
81 | + @RequestParam boolean isSystem, | |
82 | + @RequestParam String bundleAlias) throws ThingsboardException { | |
83 | + try { | |
84 | + TenantId tenantId; | |
85 | + if (isSystem) { | |
86 | + tenantId = new TenantId(ModelConstants.NULL_UUID); | |
87 | + } else { | |
88 | + tenantId = getCurrentUser().getTenantId(); | |
89 | + } | |
90 | + return checkNotNull(widgetTypeService.findWidgetTypesByTenantIdAndBundleAlias(tenantId, bundleAlias)); | |
91 | + } catch (Exception e) { | |
92 | + throw handleException(e); | |
93 | + } | |
94 | + } | |
95 | + | |
96 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") | |
97 | + @RequestMapping(value = "/widgetType", params = { "isSystem", "bundleAlias", "alias" }, method = RequestMethod.GET) | |
98 | + @ResponseBody | |
99 | + public WidgetType getWidgetType( | |
100 | + @RequestParam boolean isSystem, | |
101 | + @RequestParam String bundleAlias, | |
102 | + @RequestParam String alias) throws ThingsboardException { | |
103 | + try { | |
104 | + TenantId tenantId; | |
105 | + if (isSystem) { | |
106 | + tenantId = new TenantId(ModelConstants.NULL_UUID); | |
107 | + } else { | |
108 | + tenantId = getCurrentUser().getTenantId(); | |
109 | + } | |
110 | + WidgetType widgetType = widgetTypeService.findWidgetTypeByTenantIdBundleAliasAndAlias(tenantId, bundleAlias, alias); | |
111 | + checkWidgetType(widgetType, false); | |
112 | + return widgetType; | |
113 | + } catch (Exception e) { | |
114 | + throw handleException(e); | |
115 | + } | |
116 | + } | |
117 | + | |
118 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller; | |
17 | + | |
18 | +import org.springframework.http.HttpStatus; | |
19 | +import org.springframework.security.access.prepost.PreAuthorize; | |
20 | +import org.springframework.web.bind.annotation.*; | |
21 | +import org.thingsboard.server.common.data.id.TenantId; | |
22 | +import org.thingsboard.server.common.data.id.WidgetsBundleId; | |
23 | +import org.thingsboard.server.common.data.page.TextPageData; | |
24 | +import org.thingsboard.server.common.data.page.TextPageLink; | |
25 | +import org.thingsboard.server.common.data.security.Authority; | |
26 | +import org.thingsboard.server.common.data.widget.WidgetsBundle; | |
27 | +import org.thingsboard.server.dao.model.ModelConstants; | |
28 | +import org.thingsboard.server.exception.ThingsboardException; | |
29 | + | |
30 | +import java.util.List; | |
31 | + | |
32 | +@RestController | |
33 | +@RequestMapping("/api") | |
34 | +public class WidgetsBundleController extends BaseController { | |
35 | + | |
36 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
37 | + @RequestMapping(value = "/widgetsBundle/{widgetsBundleId}", method = RequestMethod.GET) | |
38 | + @ResponseBody | |
39 | + public WidgetsBundle getWidgetsBundleById(@PathVariable("widgetsBundleId") String strWidgetsBundleId) throws ThingsboardException { | |
40 | + checkParameter("widgetsBundleId", strWidgetsBundleId); | |
41 | + try { | |
42 | + WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId)); | |
43 | + return checkWidgetsBundleId(widgetsBundleId, false); | |
44 | + } catch (Exception e) { | |
45 | + throw handleException(e); | |
46 | + } | |
47 | + } | |
48 | + | |
49 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
50 | + @RequestMapping(value = "/widgetsBundle", method = RequestMethod.POST) | |
51 | + @ResponseBody | |
52 | + public WidgetsBundle saveWidgetsBundle(@RequestBody WidgetsBundle widgetsBundle) throws ThingsboardException { | |
53 | + try { | |
54 | + if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) { | |
55 | + widgetsBundle.setTenantId(new TenantId(ModelConstants.NULL_UUID)); | |
56 | + } else { | |
57 | + widgetsBundle.setTenantId(getCurrentUser().getTenantId()); | |
58 | + } | |
59 | + return checkNotNull(widgetsBundleService.saveWidgetsBundle(widgetsBundle)); | |
60 | + } catch (Exception e) { | |
61 | + throw handleException(e); | |
62 | + } | |
63 | + } | |
64 | + | |
65 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
66 | + @RequestMapping(value = "/widgetsBundle/{widgetsBundleId}", method = RequestMethod.DELETE) | |
67 | + @ResponseStatus(value = HttpStatus.OK) | |
68 | + public void deleteWidgetsBundle(@PathVariable("widgetsBundleId") String strWidgetsBundleId) throws ThingsboardException { | |
69 | + checkParameter("widgetsBundleId", strWidgetsBundleId); | |
70 | + try { | |
71 | + WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId)); | |
72 | + checkWidgetsBundleId(widgetsBundleId, true); | |
73 | + widgetsBundleService.deleteWidgetsBundle(widgetsBundleId); | |
74 | + } catch (Exception e) { | |
75 | + throw handleException(e); | |
76 | + } | |
77 | + } | |
78 | + | |
79 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
80 | + @RequestMapping(value = "/widgetsBundles", params = { "limit" }, method = RequestMethod.GET) | |
81 | + @ResponseBody | |
82 | + public TextPageData<WidgetsBundle> getWidgetsBundles( | |
83 | + @RequestParam int limit, | |
84 | + @RequestParam(required = false) String textSearch, | |
85 | + @RequestParam(required = false) String idOffset, | |
86 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
87 | + try { | |
88 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
89 | + if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) { | |
90 | + return checkNotNull(widgetsBundleService.findSystemWidgetsBundlesByPageLink(pageLink)); | |
91 | + } else { | |
92 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
93 | + return checkNotNull(widgetsBundleService.findAllTenantWidgetsBundlesByTenantIdAndPageLink(tenantId, pageLink)); | |
94 | + } | |
95 | + } catch (Exception e) { | |
96 | + throw handleException(e); | |
97 | + } | |
98 | + } | |
99 | + | |
100 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
101 | + @RequestMapping(value = "/widgetsBundles", method = RequestMethod.GET) | |
102 | + @ResponseBody | |
103 | + public List<WidgetsBundle> getWidgetsBundles() throws ThingsboardException { | |
104 | + try { | |
105 | + if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) { | |
106 | + return checkNotNull(widgetsBundleService.findSystemWidgetsBundles()); | |
107 | + } else { | |
108 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
109 | + return checkNotNull(widgetsBundleService.findAllTenantWidgetsBundlesByTenantId(tenantId)); | |
110 | + } | |
111 | + } catch (Exception e) { | |
112 | + throw handleException(e); | |
113 | + } | |
114 | + } | |
115 | + | |
116 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/controller/plugin/PluginApiController.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller.plugin; | |
17 | + | |
18 | + | |
19 | +import lombok.extern.slf4j.Slf4j; | |
20 | +import org.springframework.beans.factory.annotation.Autowired; | |
21 | +import org.springframework.http.HttpStatus; | |
22 | +import org.springframework.http.RequestEntity; | |
23 | +import org.springframework.http.ResponseEntity; | |
24 | +import org.springframework.security.access.prepost.PreAuthorize; | |
25 | +import org.springframework.web.bind.annotation.PathVariable; | |
26 | +import org.springframework.web.bind.annotation.RequestMapping; | |
27 | +import org.springframework.web.bind.annotation.ResponseStatus; | |
28 | +import org.springframework.web.bind.annotation.RestController; | |
29 | +import org.springframework.web.context.request.async.DeferredResult; | |
30 | +import org.thingsboard.server.actors.service.ActorService; | |
31 | +import org.thingsboard.server.common.data.id.CustomerId; | |
32 | +import org.thingsboard.server.common.data.id.TenantId; | |
33 | +import org.thingsboard.server.common.data.plugin.PluginMetaData; | |
34 | +import org.thingsboard.server.controller.BaseController; | |
35 | +import org.thingsboard.server.dao.model.ModelConstants; | |
36 | +import org.thingsboard.server.dao.plugin.PluginService; | |
37 | +import org.thingsboard.server.exception.ThingsboardException; | |
38 | +import org.thingsboard.server.extensions.api.plugins.PluginApiCallSecurityContext; | |
39 | +import org.thingsboard.server.extensions.api.plugins.PluginConstants; | |
40 | +import org.thingsboard.server.extensions.api.plugins.rest.BasicPluginRestMsg; | |
41 | +import org.thingsboard.server.extensions.api.plugins.rest.RestRequest; | |
42 | + | |
43 | +import javax.servlet.http.HttpServletRequest; | |
44 | + | |
45 | +@RestController | |
46 | +@RequestMapping(PluginConstants.PLUGIN_URL_PREFIX) | |
47 | +@Slf4j | |
48 | +public class PluginApiController extends BaseController { | |
49 | + | |
50 | + @Autowired | |
51 | + private ActorService actorService; | |
52 | + | |
53 | + @Autowired | |
54 | + private PluginService pluginService; | |
55 | + | |
56 | + @SuppressWarnings("rawtypes") | |
57 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") | |
58 | + @RequestMapping(value = "/{pluginToken}/**") | |
59 | + @ResponseStatus(value = HttpStatus.OK) | |
60 | + public DeferredResult<ResponseEntity> processRequest( | |
61 | + @PathVariable("pluginToken") String pluginToken, | |
62 | + RequestEntity<byte[]> requestEntity, | |
63 | + HttpServletRequest request) | |
64 | + throws ThingsboardException { | |
65 | + log.debug("[{}] Going to process requst uri: {}", pluginToken, requestEntity.getUrl()); | |
66 | + DeferredResult<ResponseEntity> result = new DeferredResult<ResponseEntity>(); | |
67 | + PluginMetaData pluginMd = pluginService.findPluginByApiToken(pluginToken); | |
68 | + if (pluginMd == null) { | |
69 | + result.setErrorResult(new PluginNotFoundException("Plugin with token: " + pluginToken + " not found!")); | |
70 | + } else { | |
71 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
72 | + CustomerId customerId = getCurrentUser().getCustomerId(); | |
73 | + if (validatePluginAccess(pluginMd, tenantId, customerId)) { | |
74 | + if(ModelConstants.NULL_UUID.equals(tenantId.getId())){ | |
75 | + tenantId = null; | |
76 | + } | |
77 | + PluginApiCallSecurityContext securityCtx = new PluginApiCallSecurityContext(pluginMd.getTenantId(), pluginMd.getId(), tenantId, customerId); | |
78 | + actorService.process(new BasicPluginRestMsg(securityCtx, new RestRequest(requestEntity, request), result)); | |
79 | + } else { | |
80 | + result.setResult(new ResponseEntity<>(HttpStatus.FORBIDDEN)); | |
81 | + } | |
82 | + | |
83 | + } | |
84 | + return result; | |
85 | + } | |
86 | + | |
87 | + public static boolean validatePluginAccess(PluginMetaData pluginMd, TenantId tenantId, CustomerId customerId) { | |
88 | + boolean systemAdministrator = tenantId == null || ModelConstants.NULL_UUID.equals(tenantId.getId()); | |
89 | + boolean tenantAdministrator = !systemAdministrator && (customerId == null || ModelConstants.NULL_UUID.equals(customerId.getId())); | |
90 | + boolean systemPlugin = ModelConstants.NULL_UUID.equals(pluginMd.getTenantId().getId()); | |
91 | + | |
92 | + boolean validUser = false; | |
93 | + if (systemPlugin) { | |
94 | + if (pluginMd.isPublicAccess() || systemAdministrator) { | |
95 | + // All users can access public system plugins. Only system | |
96 | + // users can access private system plugins | |
97 | + validUser = true; | |
98 | + } | |
99 | + } else { | |
100 | + if ((pluginMd.isPublicAccess() || tenantAdministrator) && tenantId.equals(pluginMd.getTenantId())) { | |
101 | + // All tenant users can access public tenant plugins. Only tenant | |
102 | + // administrator can access private tenant plugins | |
103 | + validUser = true; | |
104 | + } | |
105 | + } | |
106 | + return validUser; | |
107 | + } | |
108 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/controller/plugin/PluginNotFoundException.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller.plugin; | |
17 | + | |
18 | +import org.springframework.http.HttpStatus; | |
19 | +import org.springframework.web.bind.annotation.ResponseStatus; | |
20 | + | |
21 | +@ResponseStatus(HttpStatus.NOT_FOUND) | |
22 | +public class PluginNotFoundException extends RuntimeException { | |
23 | + | |
24 | + private static final long serialVersionUID = 1L; | |
25 | + | |
26 | + public PluginNotFoundException(String message){ | |
27 | + super(message); | |
28 | + } | |
29 | + | |
30 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/controller/plugin/PluginWebSocketHandler.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller.plugin; | |
17 | + | |
18 | +import java.io.IOException; | |
19 | +import java.net.URI; | |
20 | +import java.security.InvalidParameterException; | |
21 | +import java.util.UUID; | |
22 | +import java.util.concurrent.ConcurrentHashMap; | |
23 | +import java.util.concurrent.ConcurrentMap; | |
24 | + | |
25 | +import lombok.extern.slf4j.Slf4j; | |
26 | +import org.springframework.context.annotation.Lazy; | |
27 | +import org.springframework.web.bind.annotation.RequestMapping; | |
28 | +import org.springframework.web.bind.annotation.RestController; | |
29 | +import org.thingsboard.server.actors.service.ActorService; | |
30 | +import org.thingsboard.server.config.WebSocketConfiguration; | |
31 | +import org.thingsboard.server.extensions.api.plugins.PluginConstants; | |
32 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
33 | +import org.thingsboard.server.common.data.id.CustomerId; | |
34 | +import org.thingsboard.server.common.data.id.TenantId; | |
35 | +import org.thingsboard.server.common.data.plugin.PluginMetaData; | |
36 | +import org.thingsboard.server.dao.plugin.PluginService; | |
37 | +import org.thingsboard.server.extensions.api.plugins.PluginApiCallSecurityContext; | |
38 | +import org.thingsboard.server.extensions.api.plugins.ws.BasicPluginWebsocketSessionRef; | |
39 | +import org.thingsboard.server.extensions.api.plugins.ws.PluginWebsocketSessionRef; | |
40 | +import org.thingsboard.server.extensions.api.plugins.ws.SessionEvent; | |
41 | +import org.thingsboard.server.extensions.api.plugins.ws.msg.PluginWebsocketMsg; | |
42 | +import org.thingsboard.server.extensions.api.plugins.ws.msg.SessionEventPluginWebSocketMsg; | |
43 | +import org.thingsboard.server.extensions.api.plugins.ws.msg.TextPluginWebSocketMsg; | |
44 | +import org.slf4j.Logger; | |
45 | +import org.slf4j.LoggerFactory; | |
46 | +import org.springframework.beans.factory.annotation.Autowired; | |
47 | +import org.springframework.stereotype.Service; | |
48 | +import org.springframework.web.socket.CloseStatus; | |
49 | +import org.springframework.web.socket.TextMessage; | |
50 | +import org.springframework.web.socket.WebSocketSession; | |
51 | +import org.springframework.web.socket.handler.TextWebSocketHandler; | |
52 | + | |
53 | +@Service | |
54 | +@Slf4j | |
55 | +public class PluginWebSocketHandler extends TextWebSocketHandler implements PluginWebSocketMsgEndpoint { | |
56 | + | |
57 | + private static final ConcurrentMap<String, SessionMetaData> internalSessionMap = new ConcurrentHashMap<>(); | |
58 | + private static final ConcurrentMap<String, String> externalSessionMap = new ConcurrentHashMap<>(); | |
59 | + | |
60 | + @Autowired @Lazy | |
61 | + private ActorService actorService; | |
62 | + | |
63 | + @Autowired @Lazy | |
64 | + private PluginService pluginService; | |
65 | + | |
66 | + @Override | |
67 | + public void handleTextMessage(WebSocketSession session, TextMessage message) { | |
68 | + try { | |
69 | + log.info("[{}] Processing {}", session.getId(), message); | |
70 | + SessionMetaData sessionMd = internalSessionMap.get(session.getId()); | |
71 | + if (sessionMd != null) { | |
72 | + actorService.process(new TextPluginWebSocketMsg(sessionMd.sessionRef, message.getPayload())); | |
73 | + } else { | |
74 | + log.warn("[{}] Failed to find session", session.getId()); | |
75 | + session.close(CloseStatus.SERVER_ERROR.withReason("Session not found!")); | |
76 | + } | |
77 | + session.sendMessage(message); | |
78 | + } catch (IOException e) { | |
79 | + log.warn("IO error", e); | |
80 | + } | |
81 | + } | |
82 | + | |
83 | + @Override | |
84 | + public void afterConnectionEstablished(WebSocketSession session) throws Exception { | |
85 | + super.afterConnectionEstablished(session); | |
86 | + try { | |
87 | + String internalSessionId = session.getId(); | |
88 | + PluginWebsocketSessionRef sessionRef = toRef(session); | |
89 | + String externalSessionId = sessionRef.getSessionId(); | |
90 | + internalSessionMap.put(internalSessionId, new SessionMetaData(session, sessionRef)); | |
91 | + externalSessionMap.put(externalSessionId, internalSessionId); | |
92 | + actorService.process(new SessionEventPluginWebSocketMsg(sessionRef, SessionEvent.onEstablished())); | |
93 | + log.info("[{}][{}] Session is started", externalSessionId, session.getId()); | |
94 | + } catch (InvalidParameterException e) { | |
95 | + log.warn("[[{}] Failed to start session", session.getId(), e); | |
96 | + session.close(CloseStatus.BAD_DATA.withReason(e.getMessage())); | |
97 | + } catch (Exception e) { | |
98 | + log.warn("[{}] Failed to start session", session.getId(), e); | |
99 | + session.close(CloseStatus.SERVER_ERROR.withReason(e.getMessage())); | |
100 | + } | |
101 | + } | |
102 | + | |
103 | + @Override | |
104 | + public void handleTransportError(WebSocketSession session, Throwable tError) throws Exception { | |
105 | + super.handleTransportError(session, tError); | |
106 | + SessionMetaData sessionMd = internalSessionMap.get(session.getId()); | |
107 | + if (sessionMd != null) { | |
108 | + actorService.process(new SessionEventPluginWebSocketMsg(sessionMd.sessionRef, SessionEvent.onError(tError))); | |
109 | + } else { | |
110 | + log.warn("[{}] Failed to find session", session.getId()); | |
111 | + } | |
112 | + log.trace("[{}] Session transport error", session.getId(), tError); | |
113 | + } | |
114 | + | |
115 | + @Override | |
116 | + public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { | |
117 | + super.afterConnectionClosed(session, closeStatus); | |
118 | + SessionMetaData sessionMd = internalSessionMap.remove(session.getId()); | |
119 | + if (sessionMd != null) { | |
120 | + externalSessionMap.remove(sessionMd.sessionRef.getSessionId()); | |
121 | + actorService.process(new SessionEventPluginWebSocketMsg(sessionMd.sessionRef, SessionEvent.onClosed())); | |
122 | + } | |
123 | + log.info("[{}] Session is closed", session.getId()); | |
124 | + } | |
125 | + | |
126 | + private PluginWebsocketSessionRef toRef(WebSocketSession session) throws IOException { | |
127 | + URI sessionUri = session.getUri(); | |
128 | + String path = sessionUri.getPath(); | |
129 | + path = path.substring(WebSocketConfiguration.WS_PLUGIN_PREFIX.length()); | |
130 | + if (path.length() == 0) { | |
131 | + throw new IllegalArgumentException("URL should contain plugin token!"); | |
132 | + } | |
133 | + String[] pathElements = path.split("/"); | |
134 | + String pluginToken = pathElements[0]; | |
135 | + // TODO: cache | |
136 | + PluginMetaData pluginMd = pluginService.findPluginByApiToken(pluginToken); | |
137 | + if (pluginMd == null) { | |
138 | + throw new InvalidParameterException("Can't find plugin with specified token!"); | |
139 | + } else { | |
140 | + SecurityUser currentUser = (SecurityUser) session.getAttributes().get(WebSocketConfiguration.WS_SECURITY_USER_ATTRIBUTE); | |
141 | + TenantId tenantId = currentUser.getTenantId(); | |
142 | + CustomerId customerId = currentUser.getCustomerId(); | |
143 | + if (PluginApiController.validatePluginAccess(pluginMd, tenantId, customerId)) { | |
144 | + PluginApiCallSecurityContext securityCtx = new PluginApiCallSecurityContext(pluginMd.getTenantId(), pluginMd.getId(), tenantId, | |
145 | + currentUser.getCustomerId()); | |
146 | + return new BasicPluginWebsocketSessionRef(UUID.randomUUID().toString(), securityCtx, session.getUri(), session.getAttributes(), | |
147 | + session.getLocalAddress(), session.getRemoteAddress()); | |
148 | + } else { | |
149 | + throw new SecurityException("Current user is not allowed to use this plugin!"); | |
150 | + } | |
151 | + } | |
152 | + } | |
153 | + | |
154 | + private static class SessionMetaData { | |
155 | + private final WebSocketSession session; | |
156 | + private final PluginWebsocketSessionRef sessionRef; | |
157 | + | |
158 | + public SessionMetaData(WebSocketSession session, PluginWebsocketSessionRef sessionRef) { | |
159 | + super(); | |
160 | + this.session = session; | |
161 | + this.sessionRef = sessionRef; | |
162 | + } | |
163 | + } | |
164 | + | |
165 | + @Override | |
166 | + public void send(PluginWebsocketMsg<?> wsMsg) throws IOException { | |
167 | + PluginWebsocketSessionRef sessionRef = wsMsg.getSessionRef(); | |
168 | + String externalId = sessionRef.getSessionId(); | |
169 | + log.debug("[{}] Processing {}", externalId, wsMsg); | |
170 | + String internalId = externalSessionMap.get(externalId); | |
171 | + if (internalId != null) { | |
172 | + SessionMetaData sessionMd = internalSessionMap.get(internalId); | |
173 | + if (sessionMd != null) { | |
174 | + if (wsMsg instanceof TextPluginWebSocketMsg) { | |
175 | + String payload = ((TextPluginWebSocketMsg) wsMsg).getPayload(); | |
176 | + sessionMd.session.sendMessage(new TextMessage(payload)); | |
177 | + } | |
178 | + } else { | |
179 | + log.warn("[{}][{}] Failed to find session by internal id", externalId, internalId); | |
180 | + } | |
181 | + } else { | |
182 | + log.warn("[{}] Failed to find session by external id", externalId); | |
183 | + } | |
184 | + } | |
185 | + | |
186 | + @Override | |
187 | + public void close(PluginWebsocketSessionRef sessionRef) throws IOException { | |
188 | + String externalId = sessionRef.getSessionId(); | |
189 | + log.debug("[{}] Processing close request", externalId); | |
190 | + String internalId = externalSessionMap.get(externalId); | |
191 | + if (internalId != null) { | |
192 | + SessionMetaData sessionMd = internalSessionMap.get(internalId); | |
193 | + if (sessionMd != null) { | |
194 | + sessionMd.session.close(CloseStatus.NORMAL); | |
195 | + } else { | |
196 | + log.warn("[{}][{}] Failed to find session by internal id", externalId, internalId); | |
197 | + } | |
198 | + } else { | |
199 | + log.warn("[{}] Failed to find session by external id", externalId); | |
200 | + } | |
201 | + } | |
202 | + | |
203 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/controller/plugin/PluginWebSocketMsgEndpoint.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller.plugin; | |
17 | + | |
18 | +import java.io.IOException; | |
19 | + | |
20 | +import org.thingsboard.server.extensions.api.plugins.ws.PluginWebsocketSessionRef; | |
21 | +import org.thingsboard.server.extensions.api.plugins.ws.msg.PluginWebsocketMsg; | |
22 | + | |
23 | +public interface PluginWebSocketMsgEndpoint { | |
24 | + | |
25 | + void send(PluginWebsocketMsg<?> wsMsg) throws IOException; | |
26 | + | |
27 | + void close(PluginWebsocketSessionRef sessionRef) throws IOException; | |
28 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.exception; | |
17 | + | |
18 | +import com.fasterxml.jackson.annotation.JsonValue; | |
19 | + | |
20 | +public enum ThingsboardErrorCode { | |
21 | + | |
22 | + GENERAL(2), | |
23 | + AUTHENTICATION(10), | |
24 | + JWT_TOKEN_EXPIRED(11), | |
25 | + PERMISSION_DENIED(20), | |
26 | + INVALID_ARGUMENTS(30), | |
27 | + BAD_REQUEST_PARAMS(31), | |
28 | + ITEM_NOT_FOUND(32); | |
29 | + | |
30 | + private int errorCode; | |
31 | + | |
32 | + ThingsboardErrorCode(int errorCode) { | |
33 | + this.errorCode = errorCode; | |
34 | + } | |
35 | + | |
36 | + @JsonValue | |
37 | + public int getErrorCode() { | |
38 | + return errorCode; | |
39 | + } | |
40 | + | |
41 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.exception; | |
17 | + | |
18 | +import org.springframework.http.HttpStatus; | |
19 | + | |
20 | +import java.util.Date; | |
21 | + | |
22 | +public class ThingsboardErrorResponse { | |
23 | + // HTTP Response Status Code | |
24 | + private final HttpStatus status; | |
25 | + | |
26 | + // General Error message | |
27 | + private final String message; | |
28 | + | |
29 | + // Error code | |
30 | + private final ThingsboardErrorCode errorCode; | |
31 | + | |
32 | + private final Date timestamp; | |
33 | + | |
34 | + protected ThingsboardErrorResponse(final String message, final ThingsboardErrorCode errorCode, HttpStatus status) { | |
35 | + this.message = message; | |
36 | + this.errorCode = errorCode; | |
37 | + this.status = status; | |
38 | + this.timestamp = new java.util.Date(); | |
39 | + } | |
40 | + | |
41 | + public static ThingsboardErrorResponse of(final String message, final ThingsboardErrorCode errorCode, HttpStatus status) { | |
42 | + return new ThingsboardErrorResponse(message, errorCode, status); | |
43 | + } | |
44 | + | |
45 | + public Integer getStatus() { | |
46 | + return status.value(); | |
47 | + } | |
48 | + | |
49 | + public String getMessage() { | |
50 | + return message; | |
51 | + } | |
52 | + | |
53 | + public ThingsboardErrorCode getErrorCode() { | |
54 | + return errorCode; | |
55 | + } | |
56 | + | |
57 | + public Date getTimestamp() { | |
58 | + return timestamp; | |
59 | + } | |
60 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.exception; | |
17 | + | |
18 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
19 | +import lombok.extern.slf4j.Slf4j; | |
20 | +import org.slf4j.Logger; | |
21 | +import org.slf4j.LoggerFactory; | |
22 | +import org.springframework.beans.factory.annotation.Autowired; | |
23 | +import org.springframework.http.HttpStatus; | |
24 | +import org.springframework.http.MediaType; | |
25 | +import org.springframework.security.access.AccessDeniedException; | |
26 | +import org.springframework.security.authentication.BadCredentialsException; | |
27 | +import org.springframework.security.core.AuthenticationException; | |
28 | +import org.springframework.security.web.access.AccessDeniedHandler; | |
29 | +import org.springframework.stereotype.Component; | |
30 | +import org.thingsboard.server.service.security.exception.AuthMethodNotSupportedException; | |
31 | +import org.thingsboard.server.service.security.exception.JwtExpiredTokenException; | |
32 | + | |
33 | +import javax.servlet.ServletException; | |
34 | +import javax.servlet.http.HttpServletRequest; | |
35 | +import javax.servlet.http.HttpServletResponse; | |
36 | +import java.io.IOException; | |
37 | +@Component | |
38 | +@Slf4j | |
39 | +public class ThingsboardErrorResponseHandler implements AccessDeniedHandler { | |
40 | + | |
41 | + @Autowired | |
42 | + private ObjectMapper mapper; | |
43 | + | |
44 | + @Override | |
45 | + public void handle(HttpServletRequest request, HttpServletResponse response, | |
46 | + AccessDeniedException accessDeniedException) throws IOException, | |
47 | + ServletException { | |
48 | + if (!response.isCommitted()) { | |
49 | + response.setContentType(MediaType.APPLICATION_JSON_VALUE); | |
50 | + response.setStatus(HttpStatus.FORBIDDEN.value()); | |
51 | + mapper.writeValue(response.getWriter(), | |
52 | + ThingsboardErrorResponse.of("You don't have permission to perform this operation!", | |
53 | + ThingsboardErrorCode.PERMISSION_DENIED, HttpStatus.FORBIDDEN)); | |
54 | + } | |
55 | + } | |
56 | + | |
57 | + public void handle(Exception exception, HttpServletResponse response) { | |
58 | + log.debug("Processing exception {}", exception.getMessage(), exception); | |
59 | + if (!response.isCommitted()) { | |
60 | + try { | |
61 | + response.setContentType(MediaType.APPLICATION_JSON_VALUE); | |
62 | + | |
63 | + if (exception instanceof ThingsboardException) { | |
64 | + handleThingsboardException((ThingsboardException) exception, response); | |
65 | + } else if (exception instanceof AccessDeniedException) { | |
66 | + handleAccessDeniedException(response); | |
67 | + } else if (exception instanceof AuthenticationException) { | |
68 | + handleAuthenticationException((AuthenticationException) exception, response); | |
69 | + } else { | |
70 | + response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); | |
71 | + mapper.writeValue(response.getWriter(), ThingsboardErrorResponse.of(exception.getMessage(), | |
72 | + ThingsboardErrorCode.GENERAL, HttpStatus.INTERNAL_SERVER_ERROR)); | |
73 | + } | |
74 | + } catch (IOException e) { | |
75 | + log.error("Can't handle exception", e); | |
76 | + } | |
77 | + } | |
78 | + } | |
79 | + | |
80 | + private void handleThingsboardException(ThingsboardException thingsboardException, HttpServletResponse response) throws IOException { | |
81 | + | |
82 | + ThingsboardErrorCode errorCode = thingsboardException.getErrorCode(); | |
83 | + HttpStatus status; | |
84 | + | |
85 | + switch (errorCode) { | |
86 | + case AUTHENTICATION: | |
87 | + status = HttpStatus.UNAUTHORIZED; | |
88 | + break; | |
89 | + case PERMISSION_DENIED: | |
90 | + status = HttpStatus.FORBIDDEN; | |
91 | + break; | |
92 | + case INVALID_ARGUMENTS: | |
93 | + status = HttpStatus.BAD_REQUEST; | |
94 | + break; | |
95 | + case ITEM_NOT_FOUND: | |
96 | + status = HttpStatus.NOT_FOUND; | |
97 | + break; | |
98 | + case BAD_REQUEST_PARAMS: | |
99 | + status = HttpStatus.BAD_REQUEST; | |
100 | + break; | |
101 | + case GENERAL: | |
102 | + status = HttpStatus.INTERNAL_SERVER_ERROR; | |
103 | + break; | |
104 | + default: | |
105 | + status = HttpStatus.INTERNAL_SERVER_ERROR; | |
106 | + break; | |
107 | + } | |
108 | + | |
109 | + response.setStatus(status.value()); | |
110 | + mapper.writeValue(response.getWriter(), ThingsboardErrorResponse.of(thingsboardException.getMessage(), errorCode, status)); | |
111 | + } | |
112 | + | |
113 | + private void handleAccessDeniedException(HttpServletResponse response) throws IOException { | |
114 | + response.setStatus(HttpStatus.FORBIDDEN.value()); | |
115 | + mapper.writeValue(response.getWriter(), | |
116 | + ThingsboardErrorResponse.of("You don't have permission to perform this operation!", | |
117 | + ThingsboardErrorCode.PERMISSION_DENIED, HttpStatus.FORBIDDEN)); | |
118 | + | |
119 | + } | |
120 | + | |
121 | + private void handleAuthenticationException(AuthenticationException authenticationException, HttpServletResponse response) throws IOException { | |
122 | + response.setStatus(HttpStatus.UNAUTHORIZED.value()); | |
123 | + if (authenticationException instanceof BadCredentialsException) { | |
124 | + mapper.writeValue(response.getWriter(), ThingsboardErrorResponse.of("Invalid username or password", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)); | |
125 | + } else if (authenticationException instanceof JwtExpiredTokenException) { | |
126 | + mapper.writeValue(response.getWriter(), ThingsboardErrorResponse.of("Token has expired", ThingsboardErrorCode.JWT_TOKEN_EXPIRED, HttpStatus.UNAUTHORIZED)); | |
127 | + } else if (authenticationException instanceof AuthMethodNotSupportedException) { | |
128 | + mapper.writeValue(response.getWriter(), ThingsboardErrorResponse.of(authenticationException.getMessage(), ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)); | |
129 | + } | |
130 | + mapper.writeValue(response.getWriter(), ThingsboardErrorResponse.of("Authentication failed", ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED)); | |
131 | + } | |
132 | + | |
133 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.exception; | |
17 | + | |
18 | +public class ThingsboardException extends Exception { | |
19 | + | |
20 | + private static final long serialVersionUID = 1L; | |
21 | + | |
22 | + private ThingsboardErrorCode errorCode; | |
23 | + | |
24 | + public ThingsboardException() { | |
25 | + super(); | |
26 | + } | |
27 | + | |
28 | + public ThingsboardException(ThingsboardErrorCode errorCode) { | |
29 | + this.errorCode = errorCode; | |
30 | + } | |
31 | + | |
32 | + public ThingsboardException(String message, ThingsboardErrorCode errorCode) { | |
33 | + super(message); | |
34 | + this.errorCode = errorCode; | |
35 | + } | |
36 | + | |
37 | + public ThingsboardException(String message, Throwable cause, ThingsboardErrorCode errorCode) { | |
38 | + super(message, cause); | |
39 | + this.errorCode = errorCode; | |
40 | + } | |
41 | + | |
42 | + public ThingsboardException(Throwable cause, ThingsboardErrorCode errorCode) { | |
43 | + super(cause); | |
44 | + this.errorCode = errorCode; | |
45 | + } | |
46 | + | |
47 | + public ThingsboardErrorCode getErrorCode() { | |
48 | + return errorCode; | |
49 | + } | |
50 | + | |
51 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/service/environment/EnvironmentLogService.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.environment; | |
17 | + | |
18 | +import lombok.extern.slf4j.Slf4j; | |
19 | +import org.apache.zookeeper.Environment; | |
20 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | |
21 | +import org.springframework.stereotype.Service; | |
22 | + | |
23 | +import javax.annotation.PostConstruct; | |
24 | + | |
25 | +/** | |
26 | + * Created by igor on 11/24/16. | |
27 | + */ | |
28 | + | |
29 | +@Service("environmentLogService") | |
30 | +@ConditionalOnProperty(prefix = "zk", value = "enabled", havingValue = "false", matchIfMissing = true) | |
31 | +@Slf4j | |
32 | +public class EnvironmentLogService { | |
33 | + | |
34 | + @PostConstruct | |
35 | + public void init() { | |
36 | + Environment.logEnv("Thingsboard server environment: ", log); | |
37 | + } | |
38 | + | |
39 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.mail; | |
17 | + | |
18 | +import java.util.HashMap; | |
19 | +import java.util.Locale; | |
20 | +import java.util.Map; | |
21 | +import java.util.Properties; | |
22 | + | |
23 | +import javax.annotation.PostConstruct; | |
24 | +import javax.mail.internet.MimeMessage; | |
25 | + | |
26 | +import lombok.extern.slf4j.Slf4j; | |
27 | +import org.apache.commons.lang3.StringUtils; | |
28 | +import org.apache.velocity.app.VelocityEngine; | |
29 | +import org.thingsboard.server.exception.ThingsboardErrorCode; | |
30 | +import org.thingsboard.server.exception.ThingsboardException; | |
31 | +import org.thingsboard.server.common.data.AdminSettings; | |
32 | +import org.thingsboard.server.dao.settings.AdminSettingsService; | |
33 | +import org.thingsboard.server.dao.exception.IncorrectParameterException; | |
34 | +import org.slf4j.Logger; | |
35 | +import org.slf4j.LoggerFactory; | |
36 | +import org.springframework.beans.factory.annotation.Autowired; | |
37 | +import org.springframework.context.MessageSource; | |
38 | +import org.springframework.core.NestedRuntimeException; | |
39 | +import org.springframework.mail.javamail.JavaMailSenderImpl; | |
40 | +import org.springframework.mail.javamail.MimeMessageHelper; | |
41 | +import org.springframework.stereotype.Service; | |
42 | +import org.springframework.ui.velocity.VelocityEngineUtils; | |
43 | + | |
44 | +import com.fasterxml.jackson.databind.JsonNode; | |
45 | +@Service | |
46 | +@Slf4j | |
47 | +public class DefaultMailService implements MailService { | |
48 | + | |
49 | + @Autowired | |
50 | + private MessageSource messages; | |
51 | + | |
52 | + @Autowired | |
53 | + private VelocityEngine engine; | |
54 | + | |
55 | + private JavaMailSenderImpl mailSender; | |
56 | + | |
57 | + private String mailFrom; | |
58 | + | |
59 | + @Autowired | |
60 | + private AdminSettingsService adminSettingsService; | |
61 | + | |
62 | + @PostConstruct | |
63 | + private void init() { | |
64 | + updateMailConfiguration(); | |
65 | + } | |
66 | + | |
67 | + @Override | |
68 | + public void updateMailConfiguration() { | |
69 | + AdminSettings settings = adminSettingsService.findAdminSettingsByKey("mail"); | |
70 | + JsonNode jsonConfig = settings.getJsonValue(); | |
71 | + mailSender = createMailSender(jsonConfig); | |
72 | + mailFrom = jsonConfig.get("mailFrom").asText(); | |
73 | + } | |
74 | + | |
75 | + private JavaMailSenderImpl createMailSender(JsonNode jsonConfig) { | |
76 | + JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); | |
77 | + mailSender.setHost(jsonConfig.get("smtpHost").asText()); | |
78 | + mailSender.setPort(parsePort(jsonConfig.get("smtpPort").asText())); | |
79 | + mailSender.setUsername(jsonConfig.get("username").asText()); | |
80 | + mailSender.setPassword(jsonConfig.get("password").asText()); | |
81 | + mailSender.setJavaMailProperties(createJavaMailProperties(jsonConfig)); | |
82 | + return mailSender; | |
83 | + } | |
84 | + | |
85 | + private Properties createJavaMailProperties(JsonNode jsonConfig) { | |
86 | + Properties javaMailProperties = new Properties(); | |
87 | + String protocol = jsonConfig.get("smtpProtocol").asText(); | |
88 | + javaMailProperties.put("mail.transport.protocol", protocol); | |
89 | + javaMailProperties.put("mail." + protocol + ".host", jsonConfig.get("smtpHost").asText()); | |
90 | + javaMailProperties.put("mail." + protocol + ".port", jsonConfig.get("smtpPort").asText()); | |
91 | + javaMailProperties.put("mail." + protocol + ".timeout", jsonConfig.get("timeout").asText()); | |
92 | + javaMailProperties.put("mail." + protocol + ".auth", String.valueOf(StringUtils.isNotEmpty(jsonConfig.get("username").asText()))); | |
93 | + javaMailProperties.put("mail." + protocol + ".starttls.enable", jsonConfig.get("enableTls")); | |
94 | + return javaMailProperties; | |
95 | + } | |
96 | + | |
97 | + private int parsePort(String strPort) { | |
98 | + try { | |
99 | + return Integer.valueOf(strPort); | |
100 | + } catch (NumberFormatException e) { | |
101 | + throw new IncorrectParameterException(String.format("Invalid smtp port value: %s", strPort)); | |
102 | + } | |
103 | + } | |
104 | + | |
105 | + @Override | |
106 | + public void sendTestMail(JsonNode jsonConfig, String email) throws ThingsboardException { | |
107 | + JavaMailSenderImpl testMailSender = createMailSender(jsonConfig); | |
108 | + String mailFrom = jsonConfig.get("mailFrom").asText(); | |
109 | + String subject = messages.getMessage("test.message.subject", null, Locale.US); | |
110 | + | |
111 | + Map<String, Object> model = new HashMap<String, Object>(); | |
112 | + model.put("targetEmail", email); | |
113 | + | |
114 | + String message = VelocityEngineUtils.mergeTemplateIntoString(this.engine, | |
115 | + "test.vm", "UTF-8", model); | |
116 | + | |
117 | + sendMail(testMailSender, mailFrom, email, subject, message); | |
118 | + } | |
119 | + | |
120 | + @Override | |
121 | + public void sendActivationEmail(String activationLink, String email) throws ThingsboardException { | |
122 | + | |
123 | + String subject = messages.getMessage("activation.subject", null, Locale.US); | |
124 | + | |
125 | + Map<String, Object> model = new HashMap<String, Object>(); | |
126 | + model.put("activationLink", activationLink); | |
127 | + model.put("targetEmail", email); | |
128 | + | |
129 | + String message = VelocityEngineUtils.mergeTemplateIntoString(this.engine, | |
130 | + "activation.vm", "UTF-8", model); | |
131 | + | |
132 | + sendMail(mailSender, mailFrom, email, subject, message); | |
133 | + } | |
134 | + | |
135 | + @Override | |
136 | + public void sendAccountActivatedEmail(String loginLink, String email) throws ThingsboardException { | |
137 | + | |
138 | + String subject = messages.getMessage("account.activated.subject", null, Locale.US); | |
139 | + | |
140 | + Map<String, Object> model = new HashMap<String, Object>(); | |
141 | + model.put("loginLink", loginLink); | |
142 | + model.put("targetEmail", email); | |
143 | + | |
144 | + String message = VelocityEngineUtils.mergeTemplateIntoString(this.engine, | |
145 | + "account.activated.vm", "UTF-8", model); | |
146 | + | |
147 | + sendMail(mailSender, mailFrom, email, subject, message); | |
148 | + } | |
149 | + | |
150 | + @Override | |
151 | + public void sendResetPasswordEmail(String passwordResetLink, String email) throws ThingsboardException { | |
152 | + | |
153 | + String subject = messages.getMessage("reset.password.subject", null, Locale.US); | |
154 | + | |
155 | + Map<String, Object> model = new HashMap<String, Object>(); | |
156 | + model.put("passwordResetLink", passwordResetLink); | |
157 | + model.put("targetEmail", email); | |
158 | + | |
159 | + String message = VelocityEngineUtils.mergeTemplateIntoString(this.engine, | |
160 | + "reset.password.vm", "UTF-8", model); | |
161 | + | |
162 | + sendMail(mailSender, mailFrom, email, subject, message); | |
163 | + } | |
164 | + | |
165 | + @Override | |
166 | + public void sendPasswordWasResetEmail(String loginLink, String email) throws ThingsboardException { | |
167 | + | |
168 | + String subject = messages.getMessage("password.was.reset.subject", null, Locale.US); | |
169 | + | |
170 | + Map<String, Object> model = new HashMap<String, Object>(); | |
171 | + model.put("loginLink", loginLink); | |
172 | + model.put("targetEmail", email); | |
173 | + | |
174 | + String message = VelocityEngineUtils.mergeTemplateIntoString(this.engine, | |
175 | + "password.was.reset.vm", "UTF-8", model); | |
176 | + | |
177 | + sendMail(mailSender, mailFrom, email, subject, message); | |
178 | + } | |
179 | + | |
180 | + | |
181 | + private void sendMail(JavaMailSenderImpl mailSender, | |
182 | + String mailFrom, String email, | |
183 | + String subject, String message) throws ThingsboardException { | |
184 | + try { | |
185 | + MimeMessage mimeMsg = mailSender.createMimeMessage(); | |
186 | + MimeMessageHelper helper = new MimeMessageHelper(mimeMsg, "UTF-8"); | |
187 | + helper.setFrom(mailFrom); | |
188 | + helper.setTo(email); | |
189 | + helper.setSubject(subject); | |
190 | + helper.setText(message, true); | |
191 | + mailSender.send(helper.getMimeMessage()); | |
192 | + } catch (Exception e) { | |
193 | + throw handleException(e); | |
194 | + } | |
195 | + } | |
196 | + | |
197 | + protected ThingsboardException handleException(Exception exception) { | |
198 | + String message; | |
199 | + if (exception instanceof NestedRuntimeException) { | |
200 | + message = ((NestedRuntimeException)exception).getMostSpecificCause().getMessage(); | |
201 | + } else { | |
202 | + message = exception.getMessage(); | |
203 | + } | |
204 | + return new ThingsboardException(String.format("Unable to send mail: %s", message), | |
205 | + ThingsboardErrorCode.GENERAL); | |
206 | + } | |
207 | + | |
208 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.mail; | |
17 | + | |
18 | +import org.thingsboard.server.exception.ThingsboardException; | |
19 | + | |
20 | +import com.fasterxml.jackson.databind.JsonNode; | |
21 | + | |
22 | +public interface MailService { | |
23 | + | |
24 | + void updateMailConfiguration(); | |
25 | + | |
26 | + void sendTestMail(JsonNode config, String email) throws ThingsboardException; | |
27 | + | |
28 | + void sendActivationEmail(String activationLink, String email) throws ThingsboardException; | |
29 | + | |
30 | + void sendAccountActivatedEmail(String loginLink, String email) throws ThingsboardException; | |
31 | + | |
32 | + void sendResetPasswordEmail(String passwordResetLink, String email) throws ThingsboardException; | |
33 | + | |
34 | + void sendPasswordWasResetEmail(String loginLink, String email) throws ThingsboardException; | |
35 | + | |
36 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.auth; | |
17 | + | |
18 | +import org.springframework.security.authentication.AbstractAuthenticationToken; | |
19 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
20 | +import org.thingsboard.server.service.security.model.token.RawAccessJwtToken; | |
21 | + | |
22 | +public abstract class AbstractJwtAuthenticationToken extends AbstractAuthenticationToken { | |
23 | + | |
24 | + private static final long serialVersionUID = -6212297506742428406L; | |
25 | + | |
26 | + private RawAccessJwtToken rawAccessToken; | |
27 | + private SecurityUser securityUser; | |
28 | + | |
29 | + public AbstractJwtAuthenticationToken(RawAccessJwtToken unsafeToken) { | |
30 | + super(null); | |
31 | + this.rawAccessToken = unsafeToken; | |
32 | + this.setAuthenticated(false); | |
33 | + } | |
34 | + | |
35 | + public AbstractJwtAuthenticationToken(SecurityUser securityUser) { | |
36 | + super(securityUser.getAuthorities()); | |
37 | + this.eraseCredentials(); | |
38 | + this.securityUser = securityUser; | |
39 | + super.setAuthenticated(true); | |
40 | + } | |
41 | + | |
42 | + @Override | |
43 | + public void setAuthenticated(boolean authenticated) { | |
44 | + if (authenticated) { | |
45 | + throw new IllegalArgumentException( | |
46 | + "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); | |
47 | + } | |
48 | + super.setAuthenticated(false); | |
49 | + } | |
50 | + | |
51 | + @Override | |
52 | + public Object getCredentials() { | |
53 | + return rawAccessToken; | |
54 | + } | |
55 | + | |
56 | + @Override | |
57 | + public Object getPrincipal() { | |
58 | + return this.securityUser; | |
59 | + } | |
60 | + | |
61 | + @Override | |
62 | + public void eraseCredentials() { | |
63 | + super.eraseCredentials(); | |
64 | + this.rawAccessToken = null; | |
65 | + } | |
66 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/service/security/auth/JwtAuthenticationToken.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.auth; | |
17 | + | |
18 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
19 | +import org.thingsboard.server.service.security.model.token.RawAccessJwtToken; | |
20 | + | |
21 | +public class JwtAuthenticationToken extends AbstractJwtAuthenticationToken { | |
22 | + | |
23 | + private static final long serialVersionUID = -8487219769037942225L; | |
24 | + | |
25 | + public JwtAuthenticationToken(RawAccessJwtToken unsafeToken) { | |
26 | + super(unsafeToken); | |
27 | + } | |
28 | + | |
29 | + public JwtAuthenticationToken(SecurityUser securityUser) { | |
30 | + super(securityUser); | |
31 | + } | |
32 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.auth; | |
17 | + | |
18 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
19 | +import org.thingsboard.server.service.security.model.token.RawAccessJwtToken; | |
20 | + | |
21 | +public class RefreshAuthenticationToken extends AbstractJwtAuthenticationToken { | |
22 | + | |
23 | + private static final long serialVersionUID = -1311042791508924523L; | |
24 | + | |
25 | + public RefreshAuthenticationToken(RawAccessJwtToken unsafeToken) { | |
26 | + super(unsafeToken); | |
27 | + } | |
28 | + | |
29 | + public RefreshAuthenticationToken(SecurityUser securityUser) { | |
30 | + super(securityUser); | |
31 | + } | |
32 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.auth.jwt; | |
17 | + | |
18 | +import io.jsonwebtoken.Claims; | |
19 | +import io.jsonwebtoken.Jws; | |
20 | +import org.springframework.beans.factory.annotation.Autowired; | |
21 | +import org.springframework.security.authentication.AuthenticationProvider; | |
22 | +import org.springframework.security.core.Authentication; | |
23 | +import org.springframework.security.core.AuthenticationException; | |
24 | +import org.springframework.security.core.GrantedAuthority; | |
25 | +import org.springframework.security.core.authority.SimpleGrantedAuthority; | |
26 | +import org.springframework.stereotype.Component; | |
27 | +import org.thingsboard.server.config.JwtSettings; | |
28 | +import org.thingsboard.server.service.security.auth.JwtAuthenticationToken; | |
29 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
30 | +import org.thingsboard.server.service.security.model.token.JwtTokenFactory; | |
31 | +import org.thingsboard.server.service.security.model.token.RawAccessJwtToken; | |
32 | + | |
33 | +import java.util.List; | |
34 | +import java.util.stream.Collectors; | |
35 | + | |
36 | +@Component | |
37 | +@SuppressWarnings("unchecked") | |
38 | +public class JwtAuthenticationProvider implements AuthenticationProvider { | |
39 | + | |
40 | + private final JwtTokenFactory tokenFactory; | |
41 | + | |
42 | + @Autowired | |
43 | + public JwtAuthenticationProvider(JwtTokenFactory tokenFactory) { | |
44 | + this.tokenFactory = tokenFactory; | |
45 | + } | |
46 | + | |
47 | + @Override | |
48 | + public Authentication authenticate(Authentication authentication) throws AuthenticationException { | |
49 | + RawAccessJwtToken rawAccessToken = (RawAccessJwtToken) authentication.getCredentials(); | |
50 | + SecurityUser securityUser = tokenFactory.parseAccessJwtToken(rawAccessToken); | |
51 | + return new JwtAuthenticationToken(securityUser); | |
52 | + } | |
53 | + | |
54 | + @Override | |
55 | + public boolean supports(Class<?> authentication) { | |
56 | + return (JwtAuthenticationToken.class.isAssignableFrom(authentication)); | |
57 | + } | |
58 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.auth.jwt; | |
17 | + | |
18 | +import org.springframework.beans.factory.annotation.Autowired; | |
19 | +import org.springframework.security.core.Authentication; | |
20 | +import org.springframework.security.core.AuthenticationException; | |
21 | +import org.springframework.security.core.context.SecurityContext; | |
22 | +import org.springframework.security.core.context.SecurityContextHolder; | |
23 | +import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; | |
24 | +import org.springframework.security.web.authentication.AuthenticationFailureHandler; | |
25 | +import org.springframework.security.web.util.matcher.RequestMatcher; | |
26 | +import org.thingsboard.server.config.ThingsboardSecurityConfiguration; | |
27 | +import org.thingsboard.server.service.security.auth.JwtAuthenticationToken; | |
28 | +import org.thingsboard.server.service.security.auth.jwt.extractor.TokenExtractor; | |
29 | +import org.thingsboard.server.service.security.model.token.RawAccessJwtToken; | |
30 | + | |
31 | +import javax.servlet.FilterChain; | |
32 | +import javax.servlet.ServletException; | |
33 | +import javax.servlet.http.HttpServletRequest; | |
34 | +import javax.servlet.http.HttpServletResponse; | |
35 | +import java.io.IOException; | |
36 | + | |
37 | +public class JwtTokenAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter { | |
38 | + private final AuthenticationFailureHandler failureHandler; | |
39 | + private final TokenExtractor tokenExtractor; | |
40 | + | |
41 | + @Autowired | |
42 | + public JwtTokenAuthenticationProcessingFilter(AuthenticationFailureHandler failureHandler, | |
43 | + TokenExtractor tokenExtractor, RequestMatcher matcher) { | |
44 | + super(matcher); | |
45 | + this.failureHandler = failureHandler; | |
46 | + this.tokenExtractor = tokenExtractor; | |
47 | + } | |
48 | + | |
49 | + @Override | |
50 | + public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) | |
51 | + throws AuthenticationException, IOException, ServletException { | |
52 | + RawAccessJwtToken token = new RawAccessJwtToken(tokenExtractor.extract(request)); | |
53 | + return getAuthenticationManager().authenticate(new JwtAuthenticationToken(token)); | |
54 | + } | |
55 | + | |
56 | + @Override | |
57 | + protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, | |
58 | + Authentication authResult) throws IOException, ServletException { | |
59 | + SecurityContext context = SecurityContextHolder.createEmptyContext(); | |
60 | + context.setAuthentication(authResult); | |
61 | + SecurityContextHolder.setContext(context); | |
62 | + chain.doFilter(request, response); | |
63 | + } | |
64 | + | |
65 | + @Override | |
66 | + protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, | |
67 | + AuthenticationException failed) throws IOException, ServletException { | |
68 | + SecurityContextHolder.clearContext(); | |
69 | + failureHandler.onAuthenticationFailure(request, response, failed); | |
70 | + } | |
71 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.auth.jwt; | |
17 | + | |
18 | +import org.springframework.beans.factory.annotation.Autowired; | |
19 | +import org.springframework.security.authentication.AuthenticationProvider; | |
20 | +import org.springframework.security.authentication.DisabledException; | |
21 | +import org.springframework.security.authentication.InsufficientAuthenticationException; | |
22 | +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | |
23 | +import org.springframework.security.core.Authentication; | |
24 | +import org.springframework.security.core.AuthenticationException; | |
25 | +import org.springframework.security.core.userdetails.UsernameNotFoundException; | |
26 | +import org.springframework.stereotype.Component; | |
27 | +import org.springframework.util.Assert; | |
28 | +import org.thingsboard.server.common.data.User; | |
29 | +import org.thingsboard.server.common.data.security.UserCredentials; | |
30 | +import org.thingsboard.server.dao.user.UserService; | |
31 | +import org.thingsboard.server.service.security.auth.RefreshAuthenticationToken; | |
32 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
33 | +import org.thingsboard.server.service.security.model.token.JwtTokenFactory; | |
34 | +import org.thingsboard.server.service.security.model.token.RawAccessJwtToken; | |
35 | + | |
36 | +@Component | |
37 | +public class RefreshTokenAuthenticationProvider implements AuthenticationProvider { | |
38 | + | |
39 | + private final JwtTokenFactory tokenFactory; | |
40 | + private final UserService userService; | |
41 | + | |
42 | + @Autowired | |
43 | + public RefreshTokenAuthenticationProvider(final UserService userService, final JwtTokenFactory tokenFactory) { | |
44 | + this.userService = userService; | |
45 | + this.tokenFactory = tokenFactory; | |
46 | + } | |
47 | + | |
48 | + @Override | |
49 | + public Authentication authenticate(Authentication authentication) throws AuthenticationException { | |
50 | + Assert.notNull(authentication, "No authentication data provided"); | |
51 | + RawAccessJwtToken rawAccessToken = (RawAccessJwtToken) authentication.getCredentials(); | |
52 | + SecurityUser unsafeUser = tokenFactory.parseRefreshToken(rawAccessToken); | |
53 | + | |
54 | + User user = userService.findUserById(unsafeUser.getId()); | |
55 | + if (user == null) { | |
56 | + throw new UsernameNotFoundException("User not found by refresh token"); | |
57 | + } | |
58 | + | |
59 | + UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getId()); | |
60 | + if (userCredentials == null) { | |
61 | + throw new UsernameNotFoundException("User credentials not found"); | |
62 | + } | |
63 | + | |
64 | + if (!userCredentials.isEnabled()) { | |
65 | + throw new DisabledException("User is not active"); | |
66 | + } | |
67 | + | |
68 | + if (user.getAuthority() == null) throw new InsufficientAuthenticationException("User has no authority assigned"); | |
69 | + | |
70 | + SecurityUser securityUser = new SecurityUser(user, userCredentials.isEnabled()); | |
71 | + | |
72 | + return new RefreshAuthenticationToken(securityUser); | |
73 | + } | |
74 | + | |
75 | + @Override | |
76 | + public boolean supports(Class<?> authentication) { | |
77 | + return (RefreshAuthenticationToken.class.isAssignableFrom(authentication)); | |
78 | + } | |
79 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.auth.jwt; | |
17 | + | |
18 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
19 | +import org.apache.commons.lang3.StringUtils; | |
20 | +import org.slf4j.Logger; | |
21 | +import org.slf4j.LoggerFactory; | |
22 | +import org.springframework.http.HttpMethod; | |
23 | +import org.springframework.security.authentication.AuthenticationServiceException; | |
24 | +import org.springframework.security.core.Authentication; | |
25 | +import org.springframework.security.core.AuthenticationException; | |
26 | +import org.springframework.security.core.context.SecurityContextHolder; | |
27 | +import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; | |
28 | +import org.springframework.security.web.authentication.AuthenticationFailureHandler; | |
29 | +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; | |
30 | +import org.thingsboard.server.service.security.auth.RefreshAuthenticationToken; | |
31 | +import org.thingsboard.server.service.security.exception.AuthMethodNotSupportedException; | |
32 | +import org.thingsboard.server.service.security.model.token.RawAccessJwtToken; | |
33 | + | |
34 | +import javax.servlet.FilterChain; | |
35 | +import javax.servlet.ServletException; | |
36 | +import javax.servlet.http.HttpServletRequest; | |
37 | +import javax.servlet.http.HttpServletResponse; | |
38 | +import java.io.IOException; | |
39 | + | |
40 | +public class RefreshTokenProcessingFilter extends AbstractAuthenticationProcessingFilter { | |
41 | + private static Logger logger = LoggerFactory.getLogger(RefreshTokenProcessingFilter.class); | |
42 | + | |
43 | + private final AuthenticationSuccessHandler successHandler; | |
44 | + private final AuthenticationFailureHandler failureHandler; | |
45 | + | |
46 | + private final ObjectMapper objectMapper; | |
47 | + | |
48 | + public RefreshTokenProcessingFilter(String defaultProcessUrl, AuthenticationSuccessHandler successHandler, | |
49 | + AuthenticationFailureHandler failureHandler, ObjectMapper mapper) { | |
50 | + super(defaultProcessUrl); | |
51 | + this.successHandler = successHandler; | |
52 | + this.failureHandler = failureHandler; | |
53 | + this.objectMapper = mapper; | |
54 | + } | |
55 | + | |
56 | + @Override | |
57 | + public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) | |
58 | + throws AuthenticationException, IOException, ServletException { | |
59 | + if (!HttpMethod.POST.name().equals(request.getMethod())) { | |
60 | + if(logger.isDebugEnabled()) { | |
61 | + logger.debug("Authentication method not supported. Request method: " + request.getMethod()); | |
62 | + } | |
63 | + throw new AuthMethodNotSupportedException("Authentication method not supported"); | |
64 | + } | |
65 | + | |
66 | + RefreshTokenRequest refreshTokenRequest; | |
67 | + try { | |
68 | + refreshTokenRequest = objectMapper.readValue(request.getReader(), RefreshTokenRequest.class); | |
69 | + } catch (Exception e) { | |
70 | + throw new AuthenticationServiceException("Invalid refresh token request payload"); | |
71 | + } | |
72 | + | |
73 | + if (StringUtils.isBlank(refreshTokenRequest.getRefreshToken())) { | |
74 | + throw new AuthenticationServiceException("Refresh token is not provided"); | |
75 | + } | |
76 | + | |
77 | + RawAccessJwtToken token = new RawAccessJwtToken(refreshTokenRequest.getRefreshToken()); | |
78 | + | |
79 | + return this.getAuthenticationManager().authenticate(new RefreshAuthenticationToken(token)); | |
80 | + } | |
81 | + | |
82 | + @Override | |
83 | + protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, | |
84 | + Authentication authResult) throws IOException, ServletException { | |
85 | + successHandler.onAuthenticationSuccess(request, response, authResult); | |
86 | + } | |
87 | + | |
88 | + @Override | |
89 | + protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, | |
90 | + AuthenticationException failed) throws IOException, ServletException { | |
91 | + SecurityContextHolder.clearContext(); | |
92 | + failureHandler.onAuthenticationFailure(request, response, failed); | |
93 | + } | |
94 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.auth.jwt; | |
17 | + | |
18 | +import org.springframework.beans.factory.annotation.Autowired; | |
19 | +import org.springframework.stereotype.Component; | |
20 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
21 | +import org.thingsboard.server.service.security.model.token.JwtToken; | |
22 | +import org.thingsboard.server.service.security.model.token.JwtTokenFactory; | |
23 | + | |
24 | +@Component | |
25 | +public class RefreshTokenRepository { | |
26 | + | |
27 | + private final JwtTokenFactory tokenFactory; | |
28 | + | |
29 | + @Autowired | |
30 | + public RefreshTokenRepository(final JwtTokenFactory tokenFactory) { | |
31 | + this.tokenFactory = tokenFactory; | |
32 | + } | |
33 | + | |
34 | + public JwtToken requestRefreshToken(SecurityUser user) { | |
35 | + return tokenFactory.createRefreshToken(user); | |
36 | + } | |
37 | + | |
38 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/service/security/auth/jwt/RefreshTokenRequest.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.auth.jwt; | |
17 | + | |
18 | +import com.fasterxml.jackson.annotation.JsonCreator; | |
19 | +import com.fasterxml.jackson.annotation.JsonProperty; | |
20 | + | |
21 | +public class RefreshTokenRequest { | |
22 | + private String refreshToken; | |
23 | + | |
24 | + @JsonCreator | |
25 | + public RefreshTokenRequest(@JsonProperty("refreshToken") String refreshToken) { | |
26 | + this.refreshToken = refreshToken; | |
27 | + } | |
28 | + | |
29 | + public String getRefreshToken() { | |
30 | + return refreshToken; | |
31 | + } | |
32 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.auth.jwt; | |
17 | + | |
18 | +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; | |
19 | +import org.springframework.security.web.util.matcher.OrRequestMatcher; | |
20 | +import org.springframework.security.web.util.matcher.RequestMatcher; | |
21 | +import org.springframework.util.Assert; | |
22 | + | |
23 | +import javax.servlet.http.HttpServletRequest; | |
24 | +import java.util.List; | |
25 | +import java.util.stream.Collectors; | |
26 | + | |
27 | +public class SkipPathRequestMatcher implements RequestMatcher { | |
28 | + private OrRequestMatcher matchers; | |
29 | + private RequestMatcher processingMatcher; | |
30 | + | |
31 | + public SkipPathRequestMatcher(List<String> pathsToSkip, String processingPath) { | |
32 | + Assert.notNull(pathsToSkip); | |
33 | + List<RequestMatcher> m = pathsToSkip.stream().map(path -> new AntPathRequestMatcher(path)).collect(Collectors.toList()); | |
34 | + matchers = new OrRequestMatcher(m); | |
35 | + processingMatcher = new AntPathRequestMatcher(processingPath); | |
36 | + } | |
37 | + | |
38 | + @Override | |
39 | + public boolean matches(HttpServletRequest request) { | |
40 | + if (matchers.matches(request)) { | |
41 | + return false; | |
42 | + } | |
43 | + return processingMatcher.matches(request) ? true : false; | |
44 | + } | |
45 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.auth.jwt.extractor; | |
17 | + | |
18 | +import org.apache.commons.lang3.StringUtils; | |
19 | +import org.springframework.security.authentication.AuthenticationServiceException; | |
20 | +import org.springframework.stereotype.Component; | |
21 | +import org.thingsboard.server.config.ThingsboardSecurityConfiguration; | |
22 | + | |
23 | +import javax.servlet.http.HttpServletRequest; | |
24 | + | |
25 | +@Component(value="jwtHeaderTokenExtractor") | |
26 | +public class JwtHeaderTokenExtractor implements TokenExtractor { | |
27 | + public static String HEADER_PREFIX = "Bearer "; | |
28 | + | |
29 | + @Override | |
30 | + public String extract(HttpServletRequest request) { | |
31 | + String header = request.getHeader(ThingsboardSecurityConfiguration.JWT_TOKEN_HEADER_PARAM); | |
32 | + if (StringUtils.isBlank(header)) { | |
33 | + throw new AuthenticationServiceException("Authorization header cannot be blank!"); | |
34 | + } | |
35 | + | |
36 | + if (header.length() < HEADER_PREFIX.length()) { | |
37 | + throw new AuthenticationServiceException("Invalid authorization header size."); | |
38 | + } | |
39 | + | |
40 | + return header.substring(HEADER_PREFIX.length(), header.length()); | |
41 | + } | |
42 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.auth.jwt.extractor; | |
17 | + | |
18 | +import org.apache.commons.lang3.StringUtils; | |
19 | +import org.springframework.security.authentication.AuthenticationServiceException; | |
20 | +import org.springframework.stereotype.Component; | |
21 | +import org.thingsboard.server.config.ThingsboardSecurityConfiguration; | |
22 | + | |
23 | +import javax.servlet.http.HttpServletRequest; | |
24 | + | |
25 | +@Component(value="jwtQueryTokenExtractor") | |
26 | +public class JwtQueryTokenExtractor implements TokenExtractor { | |
27 | + | |
28 | + @Override | |
29 | + public String extract(HttpServletRequest request) { | |
30 | + String token = null; | |
31 | + if (request.getParameterMap() != null && !request.getParameterMap().isEmpty()) { | |
32 | + String[] tokenParamValue = request.getParameterMap().get(ThingsboardSecurityConfiguration.JWT_TOKEN_QUERY_PARAM); | |
33 | + if (tokenParamValue != null && tokenParamValue.length == 1) { | |
34 | + token = tokenParamValue[0]; | |
35 | + } | |
36 | + } | |
37 | + if (StringUtils.isBlank(token)) { | |
38 | + throw new AuthenticationServiceException("Authorization query parameter cannot be blank!"); | |
39 | + } | |
40 | + | |
41 | + return token; | |
42 | + } | |
43 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.auth.jwt.extractor; | |
17 | + | |
18 | +import javax.servlet.http.HttpServletRequest; | |
19 | + | |
20 | +public interface TokenExtractor { | |
21 | + public String extract(HttpServletRequest request); | |
22 | +} | |
\ No newline at end of file | ... | ... |
application/src/main/java/org/thingsboard/server/service/security/auth/rest/LoginRequest.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.auth.rest; | |
17 | + | |
18 | +import com.fasterxml.jackson.annotation.JsonCreator; | |
19 | +import com.fasterxml.jackson.annotation.JsonProperty; | |
20 | + | |
21 | +public class LoginRequest { | |
22 | + private String username; | |
23 | + private String password; | |
24 | + | |
25 | + @JsonCreator | |
26 | + public LoginRequest(@JsonProperty("username") String username, @JsonProperty("password") String password) { | |
27 | + this.username = username; | |
28 | + this.password = password; | |
29 | + } | |
30 | + | |
31 | + public String getUsername() { | |
32 | + return username; | |
33 | + } | |
34 | + | |
35 | + public String getPassword() { | |
36 | + return password; | |
37 | + } | |
38 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.auth.rest; | |
17 | + | |
18 | +import org.springframework.beans.factory.annotation.Autowired; | |
19 | +import org.springframework.security.authentication.*; | |
20 | +import org.springframework.security.core.Authentication; | |
21 | +import org.springframework.security.core.AuthenticationException; | |
22 | +import org.springframework.security.core.userdetails.UsernameNotFoundException; | |
23 | +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; | |
24 | +import org.springframework.stereotype.Component; | |
25 | +import org.springframework.util.Assert; | |
26 | +import org.thingsboard.server.common.data.User; | |
27 | +import org.thingsboard.server.common.data.security.UserCredentials; | |
28 | +import org.thingsboard.server.dao.user.UserService; | |
29 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
30 | + | |
31 | +@Component | |
32 | +public class RestAuthenticationProvider implements AuthenticationProvider { | |
33 | + | |
34 | + private final BCryptPasswordEncoder encoder; | |
35 | + private final UserService userService; | |
36 | + | |
37 | + @Autowired | |
38 | + public RestAuthenticationProvider(final UserService userService, final BCryptPasswordEncoder encoder) { | |
39 | + this.userService = userService; | |
40 | + this.encoder = encoder; | |
41 | + } | |
42 | + | |
43 | + @Override | |
44 | + public Authentication authenticate(Authentication authentication) throws AuthenticationException { | |
45 | + Assert.notNull(authentication, "No authentication data provided"); | |
46 | + | |
47 | + String username = (String) authentication.getPrincipal(); | |
48 | + String password = (String) authentication.getCredentials(); | |
49 | + | |
50 | + User user = userService.findUserByEmail(username); | |
51 | + if (user == null) { | |
52 | + throw new UsernameNotFoundException("User not found: " + username); | |
53 | + } | |
54 | + | |
55 | + UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getId()); | |
56 | + if (userCredentials == null) { | |
57 | + throw new UsernameNotFoundException("User credentials not found"); | |
58 | + } | |
59 | + | |
60 | + if (!userCredentials.isEnabled()) { | |
61 | + throw new DisabledException("User is not active"); | |
62 | + } | |
63 | + | |
64 | + if (!encoder.matches(password, userCredentials.getPassword())) { | |
65 | + throw new BadCredentialsException("Authentication Failed. Username or Password not valid."); | |
66 | + } | |
67 | + | |
68 | + if (user.getAuthority() == null) throw new InsufficientAuthenticationException("User has no authority assigned"); | |
69 | + | |
70 | + SecurityUser securityUser = new SecurityUser(user, userCredentials.isEnabled()); | |
71 | + | |
72 | + return new UsernamePasswordAuthenticationToken(securityUser, null, securityUser.getAuthorities()); | |
73 | + } | |
74 | + | |
75 | + @Override | |
76 | + public boolean supports(Class<?> authentication) { | |
77 | + return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); | |
78 | + } | |
79 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.auth.rest; | |
17 | + | |
18 | +import org.springframework.beans.factory.annotation.Autowired; | |
19 | +import org.springframework.security.core.AuthenticationException; | |
20 | +import org.springframework.security.web.authentication.AuthenticationFailureHandler; | |
21 | +import org.springframework.stereotype.Component; | |
22 | +import org.thingsboard.server.exception.ThingsboardErrorResponseHandler; | |
23 | + | |
24 | +import javax.servlet.ServletException; | |
25 | +import javax.servlet.http.HttpServletRequest; | |
26 | +import javax.servlet.http.HttpServletResponse; | |
27 | +import java.io.IOException; | |
28 | + | |
29 | +@Component | |
30 | +public class RestAwareAuthenticationFailureHandler implements AuthenticationFailureHandler { | |
31 | + | |
32 | + private final ThingsboardErrorResponseHandler errorResponseHandler; | |
33 | + | |
34 | + @Autowired | |
35 | + public RestAwareAuthenticationFailureHandler(ThingsboardErrorResponseHandler errorResponseHandler) { | |
36 | + this.errorResponseHandler = errorResponseHandler; | |
37 | + } | |
38 | + | |
39 | + @Override | |
40 | + public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, | |
41 | + AuthenticationException e) throws IOException, ServletException { | |
42 | + errorResponseHandler.handle(e, response); | |
43 | + } | |
44 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.auth.rest; | |
17 | + | |
18 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
19 | +import org.springframework.beans.factory.annotation.Autowired; | |
20 | +import org.springframework.http.HttpStatus; | |
21 | +import org.springframework.http.MediaType; | |
22 | +import org.springframework.security.core.Authentication; | |
23 | +import org.springframework.security.web.WebAttributes; | |
24 | +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; | |
25 | +import org.springframework.stereotype.Component; | |
26 | +import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository; | |
27 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
28 | +import org.thingsboard.server.service.security.model.token.JwtToken; | |
29 | +import org.thingsboard.server.service.security.model.token.JwtTokenFactory; | |
30 | + | |
31 | +import javax.servlet.ServletException; | |
32 | +import javax.servlet.http.HttpServletRequest; | |
33 | +import javax.servlet.http.HttpServletResponse; | |
34 | +import javax.servlet.http.HttpSession; | |
35 | +import java.io.IOException; | |
36 | +import java.util.HashMap; | |
37 | +import java.util.Map; | |
38 | + | |
39 | +@Component | |
40 | +public class RestAwareAuthenticationSuccessHandler implements AuthenticationSuccessHandler { | |
41 | + private final ObjectMapper mapper; | |
42 | + private final JwtTokenFactory tokenFactory; | |
43 | + private final RefreshTokenRepository refreshTokenRepository; | |
44 | + | |
45 | + @Autowired | |
46 | + public RestAwareAuthenticationSuccessHandler(final ObjectMapper mapper, final JwtTokenFactory tokenFactory, final RefreshTokenRepository refreshTokenRepository) { | |
47 | + this.mapper = mapper; | |
48 | + this.tokenFactory = tokenFactory; | |
49 | + this.refreshTokenRepository = refreshTokenRepository; | |
50 | + } | |
51 | + | |
52 | + @Override | |
53 | + public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, | |
54 | + Authentication authentication) throws IOException, ServletException { | |
55 | + SecurityUser securityUser = (SecurityUser) authentication.getPrincipal(); | |
56 | + | |
57 | + JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser); | |
58 | + JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser); | |
59 | + | |
60 | + Map<String, String> tokenMap = new HashMap<String, String>(); | |
61 | + tokenMap.put("token", accessToken.getToken()); | |
62 | + tokenMap.put("refreshToken", refreshToken.getToken()); | |
63 | + | |
64 | + response.setStatus(HttpStatus.OK.value()); | |
65 | + response.setContentType(MediaType.APPLICATION_JSON_VALUE); | |
66 | + mapper.writeValue(response.getWriter(), tokenMap); | |
67 | + | |
68 | + clearAuthenticationAttributes(request); | |
69 | + } | |
70 | + | |
71 | + /** | |
72 | + * Removes temporary authentication-related data which may have been stored | |
73 | + * in the session during the authentication process.. | |
74 | + * | |
75 | + */ | |
76 | + protected final void clearAuthenticationAttributes(HttpServletRequest request) { | |
77 | + HttpSession session = request.getSession(false); | |
78 | + | |
79 | + if (session == null) { | |
80 | + return; | |
81 | + } | |
82 | + | |
83 | + session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION); | |
84 | + } | |
85 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.auth.rest; | |
17 | + | |
18 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
19 | +import org.apache.commons.lang3.StringUtils; | |
20 | +import org.slf4j.Logger; | |
21 | +import org.slf4j.LoggerFactory; | |
22 | +import org.springframework.http.HttpMethod; | |
23 | +import org.springframework.security.authentication.AuthenticationServiceException; | |
24 | +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | |
25 | +import org.springframework.security.core.Authentication; | |
26 | +import org.springframework.security.core.AuthenticationException; | |
27 | +import org.springframework.security.core.context.SecurityContextHolder; | |
28 | +import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; | |
29 | +import org.springframework.security.web.authentication.AuthenticationFailureHandler; | |
30 | +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; | |
31 | +import org.thingsboard.server.service.security.exception.AuthMethodNotSupportedException; | |
32 | + | |
33 | +import javax.servlet.FilterChain; | |
34 | +import javax.servlet.ServletException; | |
35 | +import javax.servlet.http.HttpServletRequest; | |
36 | +import javax.servlet.http.HttpServletResponse; | |
37 | +import java.io.IOException; | |
38 | + | |
39 | +public class RestLoginProcessingFilter extends AbstractAuthenticationProcessingFilter { | |
40 | + private static Logger logger = LoggerFactory.getLogger(RestLoginProcessingFilter.class); | |
41 | + | |
42 | + private final AuthenticationSuccessHandler successHandler; | |
43 | + private final AuthenticationFailureHandler failureHandler; | |
44 | + | |
45 | + private final ObjectMapper objectMapper; | |
46 | + | |
47 | + public RestLoginProcessingFilter(String defaultProcessUrl, AuthenticationSuccessHandler successHandler, | |
48 | + AuthenticationFailureHandler failureHandler, ObjectMapper mapper) { | |
49 | + super(defaultProcessUrl); | |
50 | + this.successHandler = successHandler; | |
51 | + this.failureHandler = failureHandler; | |
52 | + this.objectMapper = mapper; | |
53 | + } | |
54 | + | |
55 | + @Override | |
56 | + public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) | |
57 | + throws AuthenticationException, IOException, ServletException { | |
58 | + if (!HttpMethod.POST.name().equals(request.getMethod())) { | |
59 | + if(logger.isDebugEnabled()) { | |
60 | + logger.debug("Authentication method not supported. Request method: " + request.getMethod()); | |
61 | + } | |
62 | + throw new AuthMethodNotSupportedException("Authentication method not supported"); | |
63 | + } | |
64 | + | |
65 | + LoginRequest loginRequest; | |
66 | + try { | |
67 | + loginRequest = objectMapper.readValue(request.getReader(), LoginRequest.class); | |
68 | + } catch (Exception e) { | |
69 | + throw new AuthenticationServiceException("Invalid login request payload"); | |
70 | + } | |
71 | + | |
72 | + if (StringUtils.isBlank(loginRequest.getUsername()) || StringUtils.isBlank(loginRequest.getPassword())) { | |
73 | + throw new AuthenticationServiceException("Username or Password not provided"); | |
74 | + } | |
75 | + | |
76 | + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()); | |
77 | + | |
78 | + return this.getAuthenticationManager().authenticate(token); | |
79 | + } | |
80 | + | |
81 | + @Override | |
82 | + protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, | |
83 | + Authentication authResult) throws IOException, ServletException { | |
84 | + successHandler.onAuthenticationSuccess(request, response, authResult); | |
85 | + } | |
86 | + | |
87 | + @Override | |
88 | + protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, | |
89 | + AuthenticationException failed) throws IOException, ServletException { | |
90 | + SecurityContextHolder.clearContext(); | |
91 | + failureHandler.onAuthenticationFailure(request, response, failed); | |
92 | + } | |
93 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.device; | |
17 | + | |
18 | +import lombok.extern.slf4j.Slf4j; | |
19 | +import org.springframework.beans.factory.annotation.Autowired; | |
20 | +import org.springframework.stereotype.Service; | |
21 | +import org.thingsboard.server.common.data.Device; | |
22 | +import org.thingsboard.server.common.data.id.DeviceId; | |
23 | +import org.thingsboard.server.common.data.security.DeviceCredentials; | |
24 | +import org.thingsboard.server.common.data.security.DeviceCredentialsFilter; | |
25 | +import org.thingsboard.server.common.transport.auth.DeviceAuthResult; | |
26 | +import org.thingsboard.server.common.transport.auth.DeviceAuthService; | |
27 | +import org.thingsboard.server.dao.device.DeviceCredentialsService; | |
28 | +import org.thingsboard.server.dao.device.DeviceService; | |
29 | + | |
30 | +import java.util.Optional; | |
31 | + | |
32 | +@Service | |
33 | +@Slf4j | |
34 | +public class DefaultDeviceAuthService implements DeviceAuthService { | |
35 | + | |
36 | + @Autowired | |
37 | + DeviceService deviceService; | |
38 | + | |
39 | + @Autowired | |
40 | + DeviceCredentialsService deviceCredentialsService; | |
41 | + | |
42 | + @Override | |
43 | + public DeviceAuthResult process(DeviceCredentialsFilter credentialsFilter) { | |
44 | + log.trace("Lookup device credentials using filter {}", credentialsFilter); | |
45 | + DeviceCredentials credentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId(credentialsFilter.getCredentialsId()); | |
46 | + if (credentials != null) { | |
47 | + log.trace("Credentials found {}", credentials); | |
48 | + if (credentials.getCredentialsType() == credentialsFilter.getCredentialsType()) { | |
49 | + switch (credentials.getCredentialsType()) { | |
50 | + case ACCESS_TOKEN: | |
51 | + // Credentials ID matches Credentials value in this | |
52 | + // primitive case; | |
53 | + return DeviceAuthResult.of(credentials.getDeviceId()); | |
54 | + default: | |
55 | + return DeviceAuthResult.of("Credentials Type is not supported yet!"); | |
56 | + } | |
57 | + } else { | |
58 | + return DeviceAuthResult.of("Credentials Type mismatch!"); | |
59 | + } | |
60 | + } else { | |
61 | + log.trace("Credentials not found!"); | |
62 | + return DeviceAuthResult.of("Credentials Not Found!"); | |
63 | + } | |
64 | + } | |
65 | + | |
66 | + @Override | |
67 | + public Optional<Device> findDeviceById(DeviceId deviceId) { | |
68 | + return Optional.ofNullable(deviceService.findDeviceById(deviceId)); | |
69 | + } | |
70 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.exception; | |
17 | + | |
18 | +import org.springframework.security.authentication.AuthenticationServiceException; | |
19 | + | |
20 | +public class AuthMethodNotSupportedException extends AuthenticationServiceException { | |
21 | + private static final long serialVersionUID = 3705043083010304496L; | |
22 | + | |
23 | + public AuthMethodNotSupportedException(String msg) { | |
24 | + super(msg); | |
25 | + } | |
26 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.exception; | |
17 | + | |
18 | +import org.springframework.security.core.AuthenticationException; | |
19 | +import org.thingsboard.server.service.security.model.token.JwtToken; | |
20 | + | |
21 | +public class JwtExpiredTokenException extends AuthenticationException { | |
22 | + private static final long serialVersionUID = -5959543783324224864L; | |
23 | + | |
24 | + private JwtToken token; | |
25 | + | |
26 | + public JwtExpiredTokenException(String msg) { | |
27 | + super(msg); | |
28 | + } | |
29 | + | |
30 | + public JwtExpiredTokenException(JwtToken token, String msg, Throwable t) { | |
31 | + super(msg, t); | |
32 | + this.token = token; | |
33 | + } | |
34 | + | |
35 | + public String token() { | |
36 | + return this.token.getToken(); | |
37 | + } | |
38 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/service/security/model/SecurityUser.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.model; | |
17 | + | |
18 | +import org.springframework.security.core.GrantedAuthority; | |
19 | +import org.springframework.security.core.authority.SimpleGrantedAuthority; | |
20 | +import org.thingsboard.server.common.data.User; | |
21 | +import org.thingsboard.server.common.data.id.UserId; | |
22 | + | |
23 | +import java.util.Arrays; | |
24 | +import java.util.Collection; | |
25 | +import java.util.stream.Collectors; | |
26 | + | |
27 | +public class SecurityUser extends User { | |
28 | + | |
29 | + private static final long serialVersionUID = -797397440703066079L; | |
30 | + | |
31 | + private Collection<GrantedAuthority> authorities; | |
32 | + private boolean enabled; | |
33 | + | |
34 | + public SecurityUser() { | |
35 | + super(); | |
36 | + } | |
37 | + | |
38 | + public SecurityUser(UserId id) { | |
39 | + super(id); | |
40 | + } | |
41 | + | |
42 | + public SecurityUser(User user, boolean enabled) { | |
43 | + super(user); | |
44 | + this.enabled = enabled; | |
45 | + } | |
46 | + | |
47 | + public Collection<? extends GrantedAuthority> getAuthorities() { | |
48 | + if (authorities == null) { | |
49 | + authorities = Arrays.asList(SecurityUser.this.getAuthority()).stream() | |
50 | + .map(authority -> new SimpleGrantedAuthority(authority.name())) | |
51 | + .collect(Collectors.toList()); | |
52 | + } | |
53 | + return authorities; | |
54 | + } | |
55 | + | |
56 | + public boolean isEnabled() { | |
57 | + return enabled; | |
58 | + } | |
59 | + | |
60 | + public void setEnabled(boolean enabled) { | |
61 | + this.enabled = enabled; | |
62 | + } | |
63 | + | |
64 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/service/security/model/token/AccessJwtToken.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.model.token; | |
17 | + | |
18 | +import com.fasterxml.jackson.annotation.JsonIgnore; | |
19 | +import io.jsonwebtoken.Claims; | |
20 | + | |
21 | +public final class AccessJwtToken implements JwtToken { | |
22 | + private final String rawToken; | |
23 | + @JsonIgnore | |
24 | + private Claims claims; | |
25 | + | |
26 | + protected AccessJwtToken(final String token, Claims claims) { | |
27 | + this.rawToken = token; | |
28 | + this.claims = claims; | |
29 | + } | |
30 | + | |
31 | + public String getToken() { | |
32 | + return this.rawToken; | |
33 | + } | |
34 | + | |
35 | + public Claims getClaims() { | |
36 | + return claims; | |
37 | + } | |
38 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/service/security/model/token/JwtToken.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.security.model.token; | |
17 | + | |
18 | +public interface JwtToken { | |
19 | + String getToken(); | |
20 | +} | ... | ... |