Commit 0ce522207263c1b6f81909e77dac6ead80cba9a5

Authored by Igor Kulikov
2 parents aabbe773 d9bfd829

Merge branch 'master' into develop/3.0

@@ -79,11 +79,18 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt @@ -79,11 +79,18 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
79 @Qualifier("oauth2AuthenticationSuccessHandler") 79 @Qualifier("oauth2AuthenticationSuccessHandler")
80 private AuthenticationSuccessHandler oauth2AuthenticationSuccessHandler; 80 private AuthenticationSuccessHandler oauth2AuthenticationSuccessHandler;
81 81
  82 + @Autowired(required = false)
  83 + @Qualifier("oauth2AuthenticationFailureHandler")
  84 + private AuthenticationFailureHandler oauth2AuthenticationFailureHandler;
  85 +
82 @Autowired 86 @Autowired
83 @Qualifier("defaultAuthenticationSuccessHandler") 87 @Qualifier("defaultAuthenticationSuccessHandler")
84 private AuthenticationSuccessHandler successHandler; 88 private AuthenticationSuccessHandler successHandler;
85 89
86 - @Autowired private AuthenticationFailureHandler failureHandler; 90 + @Autowired
  91 + @Qualifier("defaultAuthenticationFailureHandler")
  92 + private AuthenticationFailureHandler failureHandler;
  93 +
87 @Autowired private RestAuthenticationProvider restAuthenticationProvider; 94 @Autowired private RestAuthenticationProvider restAuthenticationProvider;
88 @Autowired private JwtAuthenticationProvider jwtAuthenticationProvider; 95 @Autowired private JwtAuthenticationProvider jwtAuthenticationProvider;
89 @Autowired private RefreshTokenAuthenticationProvider refreshTokenAuthenticationProvider; 96 @Autowired private RefreshTokenAuthenticationProvider refreshTokenAuthenticationProvider;
@@ -204,11 +211,11 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt @@ -204,11 +211,11 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
204 http.oauth2Login() 211 http.oauth2Login()
205 .loginPage("/oauth2Login") 212 .loginPage("/oauth2Login")
206 .loginProcessingUrl(oauth2Configuration.getLoginProcessingUrl()) 213 .loginProcessingUrl(oauth2Configuration.getLoginProcessingUrl())
207 - .successHandler(oauth2AuthenticationSuccessHandler); 214 + .successHandler(oauth2AuthenticationSuccessHandler)
  215 + .failureHandler(oauth2AuthenticationFailureHandler);
208 } 216 }
209 } 217 }
210 218
211 -  
212 @Bean 219 @Bean
213 @ConditionalOnMissingBean(CorsFilter.class) 220 @ConditionalOnMissingBean(CorsFilter.class)
214 public CorsFilter corsFilter(@Autowired MvcCorsProperties mvcCorsProperties) { 221 public CorsFilter corsFilter(@Autowired MvcCorsProperties mvcCorsProperties) {
@@ -52,6 +52,7 @@ import org.thingsboard.server.service.security.model.UserPrincipal; @@ -52,6 +52,7 @@ import org.thingsboard.server.service.security.model.UserPrincipal;
52 import org.thingsboard.server.service.security.model.token.JwtToken; 52 import org.thingsboard.server.service.security.model.token.JwtToken;
53 import org.thingsboard.server.service.security.model.token.JwtTokenFactory; 53 import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
54 import org.thingsboard.server.service.security.system.SystemSecurityService; 54 import org.thingsboard.server.service.security.system.SystemSecurityService;
  55 +import org.thingsboard.server.utils.MiscUtils;
55 import ua_parser.Client; 56 import ua_parser.Client;
56 57
57 import javax.servlet.http.HttpServletRequest; 58 import javax.servlet.http.HttpServletRequest;
@@ -170,7 +171,7 @@ public class AuthController extends BaseController { @@ -170,7 +171,7 @@ public class AuthController extends BaseController {
170 try { 171 try {
171 String email = resetPasswordByEmailRequest.get("email").asText(); 172 String email = resetPasswordByEmailRequest.get("email").asText();
172 UserCredentials userCredentials = userService.requestPasswordReset(TenantId.SYS_TENANT_ID, email); 173 UserCredentials userCredentials = userService.requestPasswordReset(TenantId.SYS_TENANT_ID, email);
173 - String baseUrl = constructBaseUrl(request); 174 + String baseUrl = MiscUtils.constructBaseUrl(request);
174 String resetUrl = String.format("%s/api/noauth/resetPassword?resetToken=%s", baseUrl, 175 String resetUrl = String.format("%s/api/noauth/resetPassword?resetToken=%s", baseUrl,
175 userCredentials.getResetToken()); 176 userCredentials.getResetToken());
176 177
@@ -218,7 +219,7 @@ public class AuthController extends BaseController { @@ -218,7 +219,7 @@ public class AuthController extends BaseController {
218 User user = userService.findUserById(TenantId.SYS_TENANT_ID, credentials.getUserId()); 219 User user = userService.findUserById(TenantId.SYS_TENANT_ID, credentials.getUserId());
219 UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail()); 220 UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail());
220 SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled(), principal); 221 SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled(), principal);
221 - String baseUrl = constructBaseUrl(request); 222 + String baseUrl = MiscUtils.constructBaseUrl(request);
222 String loginUrl = String.format("%s/login", baseUrl); 223 String loginUrl = String.format("%s/login", baseUrl);
223 String email = user.getEmail(); 224 String email = user.getEmail();
224 225
@@ -265,7 +266,7 @@ public class AuthController extends BaseController { @@ -265,7 +266,7 @@ public class AuthController extends BaseController {
265 User user = userService.findUserById(TenantId.SYS_TENANT_ID, userCredentials.getUserId()); 266 User user = userService.findUserById(TenantId.SYS_TENANT_ID, userCredentials.getUserId());
266 UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail()); 267 UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail());
267 SecurityUser securityUser = new SecurityUser(user, userCredentials.isEnabled(), principal); 268 SecurityUser securityUser = new SecurityUser(user, userCredentials.isEnabled(), principal);
268 - String baseUrl = constructBaseUrl(request); 269 + String baseUrl = MiscUtils.constructBaseUrl(request);
269 String loginUrl = String.format("%s/login", baseUrl); 270 String loginUrl = String.format("%s/login", baseUrl);
270 String email = user.getEmail(); 271 String email = user.getEmail();
271 mailService.sendPasswordWasResetEmail(loginUrl, email); 272 mailService.sendPasswordWasResetEmail(loginUrl, email);
@@ -567,39 +567,6 @@ public abstract class BaseController { @@ -567,39 +567,6 @@ public abstract class BaseController {
567 return ruleNode; 567 return ruleNode;
568 } 568 }
569 569
570 -  
571 - protected String constructBaseUrl(HttpServletRequest request) {  
572 - String scheme = request.getScheme();  
573 -  
574 - String forwardedProto = request.getHeader("x-forwarded-proto");  
575 - if (forwardedProto != null) {  
576 - scheme = forwardedProto;  
577 - }  
578 -  
579 - int serverPort = request.getServerPort();  
580 - if (request.getHeader("x-forwarded-port") != null) {  
581 - try {  
582 - serverPort = request.getIntHeader("x-forwarded-port");  
583 - } catch (NumberFormatException e) {  
584 - }  
585 - } else if (forwardedProto != null) {  
586 - switch (forwardedProto) {  
587 - case "http":  
588 - serverPort = 80;  
589 - break;  
590 - case "https":  
591 - serverPort = 443;  
592 - break;  
593 - }  
594 - }  
595 -  
596 - String baseUrl = String.format("%s://%s:%d",  
597 - scheme,  
598 - request.getServerName(),  
599 - serverPort);  
600 - return baseUrl;  
601 - }  
602 -  
603 protected <I extends EntityId> I emptyId(EntityType entityType) { 570 protected <I extends EntityId> I emptyId(EntityType entityType) {
604 return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID); 571 return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID);
605 } 572 }
@@ -52,6 +52,7 @@ import org.thingsboard.server.service.security.model.token.JwtToken; @@ -52,6 +52,7 @@ import org.thingsboard.server.service.security.model.token.JwtToken;
52 import org.thingsboard.server.service.security.model.token.JwtTokenFactory; 52 import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
53 import org.thingsboard.server.service.security.permission.Operation; 53 import org.thingsboard.server.service.security.permission.Operation;
54 import org.thingsboard.server.service.security.permission.Resource; 54 import org.thingsboard.server.service.security.permission.Resource;
  55 +import org.thingsboard.server.utils.MiscUtils;
55 56
56 import javax.servlet.http.HttpServletRequest; 57 import javax.servlet.http.HttpServletRequest;
57 58
@@ -148,7 +149,7 @@ public class UserController extends BaseController { @@ -148,7 +149,7 @@ public class UserController extends BaseController {
148 if (sendEmail) { 149 if (sendEmail) {
149 SecurityUser authUser = getCurrentUser(); 150 SecurityUser authUser = getCurrentUser();
150 UserCredentials userCredentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), savedUser.getId()); 151 UserCredentials userCredentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), savedUser.getId());
151 - String baseUrl = constructBaseUrl(request); 152 + String baseUrl = MiscUtils.constructBaseUrl(request);
152 String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl, 153 String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
153 userCredentials.getActivateToken()); 154 userCredentials.getActivateToken());
154 String email = savedUser.getEmail(); 155 String email = savedUser.getEmail();
@@ -188,7 +189,7 @@ public class UserController extends BaseController { @@ -188,7 +189,7 @@ public class UserController extends BaseController {
188 189
189 UserCredentials userCredentials = userService.findUserCredentialsByUserId(getCurrentUser().getTenantId(), user.getId()); 190 UserCredentials userCredentials = userService.findUserCredentialsByUserId(getCurrentUser().getTenantId(), user.getId());
190 if (!userCredentials.isEnabled()) { 191 if (!userCredentials.isEnabled()) {
191 - String baseUrl = constructBaseUrl(request); 192 + String baseUrl = MiscUtils.constructBaseUrl(request);
192 String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl, 193 String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
193 userCredentials.getActivateToken()); 194 userCredentials.getActivateToken());
194 mailService.sendActivationEmail(activateUrl, email); 195 mailService.sendActivationEmail(activateUrl, email);
@@ -213,7 +214,7 @@ public class UserController extends BaseController { @@ -213,7 +214,7 @@ public class UserController extends BaseController {
213 SecurityUser authUser = getCurrentUser(); 214 SecurityUser authUser = getCurrentUser();
214 UserCredentials userCredentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), user.getId()); 215 UserCredentials userCredentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), user.getId());
215 if (!userCredentials.isEnabled()) { 216 if (!userCredentials.isEnabled()) {
216 - String baseUrl = constructBaseUrl(request); 217 + String baseUrl = MiscUtils.constructBaseUrl(request);
217 String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl, 218 String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
218 userCredentials.getActivateToken()); 219 userCredentials.getActivateToken());
219 return activateUrl; 220 return activateUrl;
@@ -63,7 +63,7 @@ public abstract class AbstractOAuth2ClientMapper { @@ -63,7 +63,7 @@ public abstract class AbstractOAuth2ClientMapper {
63 63
64 private final Lock userCreationLock = new ReentrantLock(); 64 private final Lock userCreationLock = new ReentrantLock();
65 65
66 - protected SecurityUser getOrCreateSecurityUserFromOAuth2User(OAuth2User oauth2User, boolean allowUserCreation) { 66 + protected SecurityUser getOrCreateSecurityUserFromOAuth2User(OAuth2User oauth2User, boolean allowUserCreation, boolean activateUser) {
67 UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, oauth2User.getEmail()); 67 UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, oauth2User.getEmail());
68 68
69 User user = userService.findUserByEmail(TenantId.SYS_TENANT_ID, oauth2User.getEmail()); 69 User user = userService.findUserByEmail(TenantId.SYS_TENANT_ID, oauth2User.getEmail());
@@ -93,8 +93,10 @@ public abstract class AbstractOAuth2ClientMapper { @@ -93,8 +93,10 @@ public abstract class AbstractOAuth2ClientMapper {
93 user.setFirstName(oauth2User.getFirstName()); 93 user.setFirstName(oauth2User.getFirstName());
94 user.setLastName(oauth2User.getLastName()); 94 user.setLastName(oauth2User.getLastName());
95 user = userService.saveUser(user); 95 user = userService.saveUser(user);
96 - UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId());  
97 - userService.activateUserCredentials(user.getTenantId(), userCredentials.getActivateToken(), passwordEncoder.encode("")); 96 + if (activateUser) {
  97 + UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId());
  98 + userService.activateUserCredentials(user.getTenantId(), userCredentials.getActivateToken(), passwordEncoder.encode(""));
  99 + }
98 } 100 }
99 } catch (Exception e) { 101 } catch (Exception e) {
100 log.error("Can't get or create security user from oauth2 user", e); 102 log.error("Can't get or create security user from oauth2 user", e);
@@ -56,7 +56,8 @@ public class BasicOAuth2ClientMapper extends AbstractOAuth2ClientMapper implemen @@ -56,7 +56,8 @@ public class BasicOAuth2ClientMapper extends AbstractOAuth2ClientMapper implemen
56 String customerName = sub.replace(config.getBasic().getCustomerNamePattern()); 56 String customerName = sub.replace(config.getBasic().getCustomerNamePattern());
57 oauth2User.setCustomerName(customerName); 57 oauth2User.setCustomerName(customerName);
58 } 58 }
59 - return getOrCreateSecurityUserFromOAuth2User(oauth2User, config.getBasic().isAllowUserCreation()); 59 +
  60 + return getOrCreateSecurityUserFromOAuth2User(oauth2User, config.isAllowUserCreation(), config.isActivateUser());
60 } 61 }
61 62
62 private String getTenantName(Map<String, Object> attributes, OAuth2ClientMapperConfig config) { 63 private String getTenantName(Map<String, Object> attributes, OAuth2ClientMapperConfig config) {
@@ -38,7 +38,7 @@ public class CustomOAuth2ClientMapper extends AbstractOAuth2ClientMapper impleme @@ -38,7 +38,7 @@ public class CustomOAuth2ClientMapper extends AbstractOAuth2ClientMapper impleme
38 @Override 38 @Override
39 public SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, OAuth2ClientMapperConfig config) { 39 public SecurityUser getOrCreateUserByClientPrincipal(OAuth2AuthenticationToken token, OAuth2ClientMapperConfig config) {
40 OAuth2User oauth2User = getOAuth2User(token, config.getCustom()); 40 OAuth2User oauth2User = getOAuth2User(token, config.getCustom());
41 - return getOrCreateSecurityUserFromOAuth2User(oauth2User, config.getBasic().isAllowUserCreation()); 41 + return getOrCreateSecurityUserFromOAuth2User(oauth2User, config.isAllowUserCreation(), config.isActivateUser());
42 } 42 }
43 43
44 private synchronized OAuth2User getOAuth2User(OAuth2AuthenticationToken token, OAuth2ClientMapperConfig.CustomOAuth2ClientMapperConfig custom) { 44 private synchronized OAuth2User getOAuth2User(OAuth2AuthenticationToken token, OAuth2ClientMapperConfig.CustomOAuth2ClientMapperConfig custom) {
  1 +/**
  2 + * Copyright © 2016-2020 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.oauth2;
  17 +
  18 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  19 +import org.springframework.security.core.AuthenticationException;
  20 +import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
  21 +import org.springframework.stereotype.Component;
  22 +import org.thingsboard.server.utils.MiscUtils;
  23 +
  24 +import javax.servlet.ServletException;
  25 +import javax.servlet.http.HttpServletRequest;
  26 +import javax.servlet.http.HttpServletResponse;
  27 +import java.io.IOException;
  28 +import java.net.URLEncoder;
  29 +import java.nio.charset.StandardCharsets;
  30 +
  31 +@Component(value = "oauth2AuthenticationFailureHandler")
  32 +@ConditionalOnProperty(prefix = "security.oauth2", value = "enabled", havingValue = "true")
  33 +public class Oauth2AuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
  34 +
  35 + @Override
  36 + public void onAuthenticationFailure(HttpServletRequest request,
  37 + HttpServletResponse response, AuthenticationException exception)
  38 + throws IOException, ServletException {
  39 + String baseUrl = MiscUtils.constructBaseUrl(request);
  40 + getRedirectStrategy().sendRedirect(request, response, baseUrl + "/login?loginError=" +
  41 + URLEncoder.encode(exception.getMessage(), StandardCharsets.UTF_8.toString()));
  42 + }
  43 +}
@@ -27,6 +27,7 @@ import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository; @@ -27,6 +27,7 @@ import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository;
27 import org.thingsboard.server.service.security.model.SecurityUser; 27 import org.thingsboard.server.service.security.model.SecurityUser;
28 import org.thingsboard.server.service.security.model.token.JwtToken; 28 import org.thingsboard.server.service.security.model.token.JwtToken;
29 import org.thingsboard.server.service.security.model.token.JwtTokenFactory; 29 import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
  30 +import org.thingsboard.server.utils.MiscUtils;
30 31
31 import javax.servlet.http.HttpServletRequest; 32 import javax.servlet.http.HttpServletRequest;
32 import javax.servlet.http.HttpServletResponse; 33 import javax.servlet.http.HttpServletResponse;
@@ -65,6 +66,7 @@ public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationS @@ -65,6 +66,7 @@ public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationS
65 JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser); 66 JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser);
66 JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser); 67 JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser);
67 68
68 - getRedirectStrategy().sendRedirect(request, response, "/?accessToken=" + accessToken.getToken() + "&refreshToken=" + refreshToken.getToken()); 69 + String baseUrl = MiscUtils.constructBaseUrl(request);
  70 + getRedirectStrategy().sendRedirect(request, response, baseUrl + "/?accessToken=" + accessToken.getToken() + "&refreshToken=" + refreshToken.getToken());
69 } 71 }
70 } 72 }
@@ -26,7 +26,7 @@ import javax.servlet.http.HttpServletRequest; @@ -26,7 +26,7 @@ import javax.servlet.http.HttpServletRequest;
26 import javax.servlet.http.HttpServletResponse; 26 import javax.servlet.http.HttpServletResponse;
27 import java.io.IOException; 27 import java.io.IOException;
28 28
29 -@Component 29 +@Component(value = "defaultAuthenticationFailureHandler")
30 public class RestAwareAuthenticationFailureHandler implements AuthenticationFailureHandler { 30 public class RestAwareAuthenticationFailureHandler implements AuthenticationFailureHandler {
31 31
32 private final ThingsboardErrorResponseHandler errorResponseHandler; 32 private final ThingsboardErrorResponseHandler errorResponseHandler;
@@ -18,8 +18,8 @@ package org.thingsboard.server.utils; @@ -18,8 +18,8 @@ package org.thingsboard.server.utils;
18 import com.google.common.hash.HashFunction; 18 import com.google.common.hash.HashFunction;
19 import com.google.common.hash.Hashing; 19 import com.google.common.hash.Hashing;
20 20
  21 +import javax.servlet.http.HttpServletRequest;
21 import java.nio.charset.Charset; 22 import java.nio.charset.Charset;
22 -import java.util.Random;  
23 23
24 24
25 /** 25 /**
@@ -47,4 +47,36 @@ public class MiscUtils { @@ -47,4 +47,36 @@ public class MiscUtils {
47 throw new IllegalArgumentException("Can't find hash function with name " + name); 47 throw new IllegalArgumentException("Can't find hash function with name " + name);
48 } 48 }
49 } 49 }
  50 +
  51 + public static String constructBaseUrl(HttpServletRequest request) {
  52 + String scheme = request.getScheme();
  53 +
  54 + String forwardedProto = request.getHeader("x-forwarded-proto");
  55 + if (forwardedProto != null) {
  56 + scheme = forwardedProto;
  57 + }
  58 +
  59 + int serverPort = request.getServerPort();
  60 + if (request.getHeader("x-forwarded-port") != null) {
  61 + try {
  62 + serverPort = request.getIntHeader("x-forwarded-port");
  63 + } catch (NumberFormatException e) {
  64 + }
  65 + } else if (forwardedProto != null) {
  66 + switch (forwardedProto) {
  67 + case "http":
  68 + serverPort = 80;
  69 + break;
  70 + case "https":
  71 + serverPort = 443;
  72 + break;
  73 + }
  74 + }
  75 +
  76 + String baseUrl = String.format("%s://%s:%d",
  77 + scheme,
  78 + request.getServerName(),
  79 + serverPort);
  80 + return baseUrl;
  81 + }
50 } 82 }
@@ -127,11 +127,13 @@ security: @@ -127,11 +127,13 @@ security:
127 userInfoUri: "${SECURITY_OAUTH2_DEFAULT_USER_INFO_URI:}" 127 userInfoUri: "${SECURITY_OAUTH2_DEFAULT_USER_INFO_URI:}"
128 userNameAttributeName: "${SECURITY_OAUTH2_DEFAULT_USER_NAME_ATTRIBUTE_NAME:email}" 128 userNameAttributeName: "${SECURITY_OAUTH2_DEFAULT_USER_NAME_ATTRIBUTE_NAME:email}"
129 mapperConfig: 129 mapperConfig:
  130 + # Allows to create user if it not exists
  131 + allowUserCreation: "${SECURITY_OAUTH2_DEFAULT_MAPPER_ALLOW_USER_CREATION:true}"
  132 + # Allows user to setup ThingsBoard internal password and login over default Login window
  133 + activateUser: "${SECURITY_OAUTH2_DEFAULT_MAPPER_ACTIVATE_USER:false}"
130 # Mapper type of converter from external user into internal - 'basic' or 'custom' 134 # Mapper type of converter from external user into internal - 'basic' or 'custom'
131 type: "${SECURITY_OAUTH2_DEFAULT_MAPPER_TYPE:basic}" 135 type: "${SECURITY_OAUTH2_DEFAULT_MAPPER_TYPE:basic}"
132 basic: 136 basic:
133 - # Allows to create user if it not exists  
134 - allowUserCreation: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_ALLOW_USER_CREATION:true}"  
135 # Key from attributes of external user object to use as email 137 # Key from attributes of external user object to use as email
136 emailAttributeKey: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_EMAIL_ATTRIBUTE_KEY:email}" 138 emailAttributeKey: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_EMAIL_ATTRIBUTE_KEY:email}"
137 firstNameAttributeKey: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_FIRST_NAME_ATTRIBUTE_KEY:}" 139 firstNameAttributeKey: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_FIRST_NAME_ATTRIBUTE_KEY:}"
@@ -20,13 +20,14 @@ import lombok.Data; @@ -20,13 +20,14 @@ import lombok.Data;
20 @Data 20 @Data
21 public class OAuth2ClientMapperConfig { 21 public class OAuth2ClientMapperConfig {
22 22
  23 + private boolean allowUserCreation;
  24 + private boolean activateUser;
23 private String type; 25 private String type;
24 private BasicOAuth2ClientMapperConfig basic; 26 private BasicOAuth2ClientMapperConfig basic;
25 private CustomOAuth2ClientMapperConfig custom; 27 private CustomOAuth2ClientMapperConfig custom;
26 28
27 @Data 29 @Data
28 public static class BasicOAuth2ClientMapperConfig { 30 public static class BasicOAuth2ClientMapperConfig {
29 - private boolean allowUserCreation;  
30 private String emailAttributeKey; 31 private String emailAttributeKey;
31 private String firstNameAttributeKey; 32 private String firstNameAttributeKey;
32 private String lastNameAttributeKey; 33 private String lastNameAttributeKey;
@@ -22,7 +22,7 @@ export default angular.module('thingsboard.api.user', [thingsboardApiLogin, @@ -22,7 +22,7 @@ export default angular.module('thingsboard.api.user', [thingsboardApiLogin,
22 .name; 22 .name;
23 23
24 /*@ngInject*/ 24 /*@ngInject*/
25 -function UserService($http, $q, $rootScope, adminService, dashboardService, timeService, loginService, toast, store, jwtHelper, $translate, $state, $location) { 25 +function UserService($http, $q, $rootScope, adminService, dashboardService, timeService, loginService, toast, store, jwtHelper, $translate, $state, $location, $mdDialog) {
26 var currentUser = null, 26 var currentUser = null,
27 currentUserDetails = null, 27 currentUserDetails = null,
28 lastPublicDashboardId = null, 28 lastPublicDashboardId = null,
@@ -406,6 +406,10 @@ function UserService($http, $q, $rootScope, adminService, dashboardService, time @@ -406,6 +406,10 @@ function UserService($http, $q, $rootScope, adminService, dashboardService, time
406 }, function fail() { 406 }, function fail() {
407 deferred.reject(); 407 deferred.reject();
408 }); 408 });
  409 + } else if (locationSearch.loginError) {
  410 + showLoginErrorDialog(locationSearch.loginError);
  411 + $location.search('loginError', null);
  412 + deferred.reject();
409 } else { 413 } else {
410 procceedJwtTokenValidate(); 414 procceedJwtTokenValidate();
411 } 415 }
@@ -415,6 +419,17 @@ function UserService($http, $q, $rootScope, adminService, dashboardService, time @@ -415,6 +419,17 @@ function UserService($http, $q, $rootScope, adminService, dashboardService, time
415 return deferred.promise; 419 return deferred.promise;
416 } 420 }
417 421
  422 + function showLoginErrorDialog(loginError) {
  423 + $translate(['login.error',
  424 + 'action.close']).then(function (translations) {
  425 + var alert = $mdDialog.alert()
  426 + .title(translations['login.error'])
  427 + .htmlContent(loginError)
  428 + .ok(translations['action.close']);
  429 + $mdDialog.show(alert);
  430 + });
  431 + }
  432 +
418 function loadIsUserTokenAccessEnabled() { 433 function loadIsUserTokenAccessEnabled() {
419 var deferred = $q.defer(); 434 var deferred = $q.defer();
420 if (currentUser.authority === 'SYS_ADMIN' || currentUser.authority === 'TENANT_ADMIN') { 435 if (currentUser.authority === 'SYS_ADMIN' || currentUser.authority === 'TENANT_ADMIN') {
@@ -1334,7 +1334,8 @@ @@ -1334,7 +1334,8 @@
1334 "password-link-sent-message": "Password reset link was successfully sent!", 1334 "password-link-sent-message": "Password reset link was successfully sent!",
1335 "email": "Email", 1335 "email": "Email",
1336 "login-with": "Login with {{name}}", 1336 "login-with": "Login with {{name}}",
1337 - "or": "or" 1337 + "or": "or",
  1338 + "error": "Login error"
1338 }, 1339 },
1339 "position": { 1340 "position": {
1340 "top": "Top", 1341 "top": "Top",
@@ -51,7 +51,7 @@ @@ -51,7 +51,7 @@
51 <div class="text mat-typography">{{ "login.or" | translate | uppercase }}</div> 51 <div class="text mat-typography">{{ "login.or" | translate | uppercase }}</div>
52 <div class="line"><md-divider></md-divider></div> 52 <div class="line"><md-divider></md-divider></div>
53 </div> 53 </div>
54 - <md-button ng-repeat="oauth2Client in oauth2Clients" class="md-raised" 54 + <md-button ng-repeat="oauth2Client in oauth2Clients" class="md-raised md-accent md-hue-2"
55 layout="row" layout-align="center center" ng-href="{{ oauth2Client.url }}" target="_self"> 55 layout="row" layout-align="center center" ng-href="{{ oauth2Client.url }}" target="_self">
56 <md-icon class="material-icons md-18" md-svg-icon="{{ oauth2Client.icon }}"></md-icon> 56 <md-icon class="material-icons md-18" md-svg-icon="{{ oauth2Client.icon }}"></md-icon>
57 {{ 'login.login-with' | translate: {name: oauth2Client.name} }} 57 {{ 'login.login-with' | translate: {name: oauth2Client.name} }}