Commit 5fdbb51cd7acfff633b62446c85be4ae6d36d771

Authored by Igor Kulikov
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
... ...
  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 +}
... ...
  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 +}
... ...
  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 +}
... ...
  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 +}
... ...
  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 +}
... ...
  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 +}
... ...
  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 +}
... ...
  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 +}
... ...
  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 +}
... ...
  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 +}
... ...
  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
... ...
  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 +}
... ...
  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 +}
... ...
  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 +}
... ...
  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 +}
... ...