Commit d6c2eefe05d6cc8427e2fda8b2c9d0b50e374442

Authored by YevhenBondarenko
Committed by Andrew Shvayka
1 parent 04727e81

base url improvements

... ... @@ -171,7 +171,8 @@ public class AuthController extends BaseController {
171 171 try {
172 172 String email = resetPasswordByEmailRequest.get("email").asText();
173 173 UserCredentials userCredentials = userService.requestPasswordReset(TenantId.SYS_TENANT_ID, email);
174   - String baseUrl = MiscUtils.constructBaseUrl(request);
  174 + User user = userService.findUserById(TenantId.SYS_TENANT_ID, userCredentials.getUserId());
  175 + String baseUrl = systemSecurityService.getBaseUrl(user.getTenantId(), user.getCustomerId(), request);
175 176 String resetUrl = String.format("%s/api/noauth/resetPassword?resetToken=%s", baseUrl,
176 177 userCredentials.getResetToken());
177 178
... ... @@ -219,7 +220,7 @@ public class AuthController extends BaseController {
219 220 User user = userService.findUserById(TenantId.SYS_TENANT_ID, credentials.getUserId());
220 221 UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail());
221 222 SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled(), principal);
222   - String baseUrl = MiscUtils.constructBaseUrl(request);
  223 + String baseUrl = systemSecurityService.getBaseUrl(user.getTenantId(), user.getCustomerId(), request);
223 224 String loginUrl = String.format("%s/login", baseUrl);
224 225 String email = user.getEmail();
225 226
... ... @@ -266,7 +267,7 @@ public class AuthController extends BaseController {
266 267 User user = userService.findUserById(TenantId.SYS_TENANT_ID, userCredentials.getUserId());
267 268 UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail());
268 269 SecurityUser securityUser = new SecurityUser(user, userCredentials.isEnabled(), principal);
269   - String baseUrl = MiscUtils.constructBaseUrl(request);
  270 + String baseUrl = systemSecurityService.getBaseUrl(user.getTenantId(), user.getCustomerId(), request);
270 271 String loginUrl = String.format("%s/login", baseUrl);
271 272 String email = user.getEmail();
272 273 mailService.sendPasswordWasResetEmail(loginUrl, email);
... ...
... ... @@ -52,6 +52,7 @@ import org.thingsboard.server.service.security.model.token.JwtToken;
52 52 import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
53 53 import org.thingsboard.server.service.security.permission.Operation;
54 54 import org.thingsboard.server.service.security.permission.Resource;
  55 +import org.thingsboard.server.service.security.system.SystemSecurityService;
55 56 import org.thingsboard.server.utils.MiscUtils;
56 57
57 58 import javax.servlet.http.HttpServletRequest;
... ... @@ -78,6 +79,9 @@ public class UserController extends BaseController {
78 79 @Autowired
79 80 private RefreshTokenRepository refreshTokenRepository;
80 81
  82 + @Autowired
  83 + private SystemSecurityService systemSecurityService;
  84 +
81 85
82 86 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
83 87 @RequestMapping(value = "/user/{userId}", method = RequestMethod.GET)
... ... @@ -145,7 +149,7 @@ public class UserController extends BaseController {
145 149 if (sendEmail) {
146 150 SecurityUser authUser = getCurrentUser();
147 151 UserCredentials userCredentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), savedUser.getId());
148   - String baseUrl = MiscUtils.constructBaseUrl(request);
  152 + String baseUrl = systemSecurityService.getBaseUrl(getTenantId(), getCurrentUser().getCustomerId(), request);
149 153 String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
150 154 userCredentials.getActivateToken());
151 155 String email = savedUser.getEmail();
... ... @@ -185,7 +189,7 @@ public class UserController extends BaseController {
185 189
186 190 UserCredentials userCredentials = userService.findUserCredentialsByUserId(getCurrentUser().getTenantId(), user.getId());
187 191 if (!userCredentials.isEnabled()) {
188   - String baseUrl = MiscUtils.constructBaseUrl(request);
  192 + String baseUrl = systemSecurityService.getBaseUrl(getTenantId(), getCurrentUser().getCustomerId(), request);
189 193 String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
190 194 userCredentials.getActivateToken());
191 195 mailService.sendActivationEmail(activateUrl, email);
... ... @@ -210,7 +214,7 @@ public class UserController extends BaseController {
210 214 SecurityUser authUser = getCurrentUser();
211 215 UserCredentials userCredentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), user.getId());
212 216 if (!userCredentials.isEnabled()) {
213   - String baseUrl = MiscUtils.constructBaseUrl(request);
  217 + String baseUrl = systemSecurityService.getBaseUrl(getTenantId(), getCurrentUser().getCustomerId(), request);
214 218 String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
215 219 userCredentials.getActivateToken());
216 220 return activateUrl;
... ...
... ... @@ -19,6 +19,10 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
19 19 import org.springframework.security.core.AuthenticationException;
20 20 import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
21 21 import org.springframework.stereotype.Component;
  22 +import org.thingsboard.server.common.data.id.CustomerId;
  23 +import org.thingsboard.server.common.data.id.EntityId;
  24 +import org.thingsboard.server.common.data.id.TenantId;
  25 +import org.thingsboard.server.service.security.system.SystemSecurityService;
22 26 import org.thingsboard.server.utils.MiscUtils;
23 27
24 28 import javax.servlet.ServletException;
... ... @@ -32,11 +36,13 @@ import java.nio.charset.StandardCharsets;
32 36 @ConditionalOnProperty(prefix = "security.oauth2", value = "enabled", havingValue = "true")
33 37 public class Oauth2AuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
34 38
  39 + private SystemSecurityService systemSecurityService;
  40 +
35 41 @Override
36 42 public void onAuthenticationFailure(HttpServletRequest request,
37 43 HttpServletResponse response, AuthenticationException exception)
38 44 throws IOException, ServletException {
39   - String baseUrl = MiscUtils.constructBaseUrl(request);
  45 + String baseUrl = systemSecurityService.getBaseUrl(TenantId.SYS_TENANT_ID, new CustomerId(EntityId.NULL_UUID), request);
40 46 getRedirectStrategy().sendRedirect(request, response, baseUrl + "/login?loginError=" +
41 47 URLEncoder.encode(exception.getMessage(), StandardCharsets.UTF_8.toString()));
42 48 }
... ...
... ... @@ -21,13 +21,16 @@ import org.springframework.security.core.Authentication;
21 21 import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
22 22 import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
23 23 import org.springframework.stereotype.Component;
  24 +import org.thingsboard.server.common.data.id.CustomerId;
  25 +import org.thingsboard.server.common.data.id.EntityId;
  26 +import org.thingsboard.server.common.data.id.TenantId;
24 27 import org.thingsboard.server.dao.oauth2.OAuth2Client;
25 28 import org.thingsboard.server.dao.oauth2.OAuth2Configuration;
26 29 import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository;
27 30 import org.thingsboard.server.service.security.model.SecurityUser;
28 31 import org.thingsboard.server.service.security.model.token.JwtToken;
29 32 import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
30   -import org.thingsboard.server.utils.MiscUtils;
  33 +import org.thingsboard.server.service.security.system.SystemSecurityService;
31 34
32 35 import javax.servlet.http.HttpServletRequest;
33 36 import javax.servlet.http.HttpServletResponse;
... ... @@ -43,16 +46,18 @@ public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationS
43 46 private final RefreshTokenRepository refreshTokenRepository;
44 47 private final OAuth2ClientMapperProvider oauth2ClientMapperProvider;
45 48 private final OAuth2Configuration oauth2Configuration;
  49 + private final SystemSecurityService systemSecurityService;
46 50
47 51 @Autowired
48 52 public Oauth2AuthenticationSuccessHandler(final JwtTokenFactory tokenFactory,
49 53 final RefreshTokenRepository refreshTokenRepository,
50 54 final OAuth2ClientMapperProvider oauth2ClientMapperProvider,
51   - final OAuth2Configuration oauth2Configuration) {
  55 + final OAuth2Configuration oauth2Configuration, SystemSecurityService systemSecurityService) {
52 56 this.tokenFactory = tokenFactory;
53 57 this.refreshTokenRepository = refreshTokenRepository;
54 58 this.oauth2ClientMapperProvider = oauth2ClientMapperProvider;
55 59 this.oauth2Configuration = oauth2Configuration;
  60 + this.systemSecurityService = systemSecurityService;
56 61 }
57 62
58 63 @Override
... ... @@ -60,7 +65,7 @@ public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationS
60 65 HttpServletResponse response,
61 66 Authentication authentication) throws IOException {
62 67
63   - String baseUrl = MiscUtils.constructBaseUrl(request);
  68 + String baseUrl = systemSecurityService.getBaseUrl(TenantId.SYS_TENANT_ID, new CustomerId(EntityId.NULL_UUID), request);
64 69 try {
65 70 OAuth2AuthenticationToken token = (OAuth2AuthenticationToken) authentication;
66 71
... ...
... ... @@ -40,17 +40,20 @@ import org.thingsboard.rule.engine.api.MailService;
40 40 import org.thingsboard.server.common.data.AdminSettings;
41 41 import org.thingsboard.server.common.data.User;
42 42 import org.thingsboard.server.common.data.exception.ThingsboardException;
  43 +import org.thingsboard.server.common.data.id.CustomerId;
43 44 import org.thingsboard.server.common.data.id.TenantId;
44 45 import org.thingsboard.server.common.data.security.UserCredentials;
  46 +import org.thingsboard.server.common.data.security.model.SecuritySettings;
  47 +import org.thingsboard.server.common.data.security.model.UserPasswordPolicy;
45 48 import org.thingsboard.server.dao.exception.DataValidationException;
46 49 import org.thingsboard.server.dao.settings.AdminSettingsService;
47 50 import org.thingsboard.server.dao.user.UserService;
48 51 import org.thingsboard.server.dao.user.UserServiceImpl;
49 52 import org.thingsboard.server.service.security.exception.UserPasswordExpiredException;
50   -import org.thingsboard.server.common.data.security.model.SecuritySettings;
51   -import org.thingsboard.server.common.data.security.model.UserPasswordPolicy;
  53 +import org.thingsboard.server.utils.MiscUtils;
52 54
53 55 import javax.annotation.Resource;
  56 +import javax.servlet.http.HttpServletRequest;
54 57 import java.util.ArrayList;
55 58 import java.util.List;
56 59 import java.util.Map;
... ... @@ -146,7 +149,7 @@ public class DefaultSystemSecurityService implements SystemSecurityService {
146 149 if (isPositiveInteger(securitySettings.getPasswordPolicy().getPasswordExpirationPeriodDays())) {
147 150 if ((userCredentials.getCreatedTime()
148 151 + TimeUnit.DAYS.toMillis(securitySettings.getPasswordPolicy().getPasswordExpirationPeriodDays()))
149   - < System.currentTimeMillis()) {
  152 + < System.currentTimeMillis()) {
150 153 userCredentials = userService.requestExpiredPasswordReset(tenantId, userCredentials.getId());
151 154 throw new UserPasswordExpiredException("User password expired!", userCredentials.getResetToken());
152 155 }
... ... @@ -197,6 +200,21 @@ public class DefaultSystemSecurityService implements SystemSecurityService {
197 200 }
198 201 }
199 202
  203 + @Override
  204 + public String getBaseUrl(TenantId tenantId, CustomerId customerId, HttpServletRequest httpServletRequest) {
  205 + String baseUrl;
  206 + AdminSettings generalSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "general");
  207 +
  208 + JsonNode prohibitDifferentUrl = generalSettings.getJsonValue().get("prohibitDifferentUrl");
  209 +
  210 + if (prohibitDifferentUrl != null && prohibitDifferentUrl.asBoolean()) {
  211 + baseUrl = generalSettings.getJsonValue().get("baseUrl").asText();
  212 + } else {
  213 + baseUrl = MiscUtils.constructBaseUrl(httpServletRequest);
  214 + }
  215 + return baseUrl;
  216 + }
  217 +
200 218 private static boolean isPositiveInteger(Integer val) {
201 219 return val != null && val.intValue() > 0;
202 220 }
... ...
... ... @@ -16,11 +16,14 @@
16 16 package org.thingsboard.server.service.security.system;
17 17
18 18 import org.springframework.security.core.AuthenticationException;
  19 +import org.thingsboard.server.common.data.id.CustomerId;
19 20 import org.thingsboard.server.common.data.id.TenantId;
20 21 import org.thingsboard.server.common.data.security.UserCredentials;
21 22 import org.thingsboard.server.dao.exception.DataValidationException;
22 23 import org.thingsboard.server.common.data.security.model.SecuritySettings;
23 24
  25 +import javax.servlet.http.HttpServletRequest;
  26 +
24 27 public interface SystemSecurityService {
25 28
26 29 SecuritySettings getSecuritySettings(TenantId tenantId);
... ... @@ -31,4 +34,6 @@ public interface SystemSecurityService {
31 34
32 35 void validatePassword(TenantId tenantId, String password, UserCredentials userCredentials) throws DataValidationException;
33 36
  37 + String getBaseUrl(TenantId tenantId, CustomerId customerId, HttpServletRequest httpServletRequest);
  38 +
34 39 }
... ...
... ... @@ -18,6 +18,7 @@ package org.thingsboard.server.controller;
18 18 import com.fasterxml.jackson.core.type.TypeReference;
19 19 import com.fasterxml.jackson.databind.JsonNode;
20 20 import com.fasterxml.jackson.databind.ObjectMapper;
  21 +import com.fasterxml.jackson.databind.node.ObjectNode;
21 22 import io.jsonwebtoken.Claims;
22 23 import io.jsonwebtoken.Header;
23 24 import io.jsonwebtoken.Jwt;
... ... @@ -58,6 +59,7 @@ import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilde
58 59 import org.springframework.util.LinkedMultiValueMap;
59 60 import org.springframework.util.MultiValueMap;
60 61 import org.springframework.web.context.WebApplicationContext;
  62 +import org.thingsboard.server.common.data.AdminSettings;
61 63 import org.thingsboard.server.common.data.BaseData;
62 64 import org.thingsboard.server.common.data.Customer;
63 65 import org.thingsboard.server.common.data.Tenant;
... ... @@ -68,6 +70,7 @@ import org.thingsboard.server.common.data.page.TextPageLink;
68 70 import org.thingsboard.server.common.data.page.TimePageLink;
69 71 import org.thingsboard.server.common.data.security.Authority;
70 72 import org.thingsboard.server.config.ThingsboardSecurityConfiguration;
  73 +import org.thingsboard.server.dao.util.mapping.JacksonUtil;
71 74 import org.thingsboard.server.service.mail.TestMailService;
72 75 import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRequest;
73 76 import org.thingsboard.server.service.security.auth.rest.LoginRequest;
... ... @@ -174,6 +177,11 @@ public abstract class AbstractControllerTest {
174 177 }
175 178 loginSysAdmin();
176 179
  180 + ObjectNode generalSettings = JacksonUtil.OBJECT_MAPPER.createObjectNode();
  181 + AdminSettings adminSettings = new AdminSettings();
  182 + adminSettings.setKey("general");
  183 + adminSettings.setJsonValue(generalSettings);
  184 +
177 185 Tenant tenant = new Tenant();
178 186 tenant.setTitle(TEST_TENANT_NAME);
179 187 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
... ...
... ... @@ -34,6 +34,11 @@
34 34 <div translate ng-message="required">admin.base-url-required</div>
35 35 </div>
36 36 </md-input-container>
  37 + <md-checkbox class="md-block"
  38 + aria-label="{{ 'admin.prohibit-different-url' | translate }}"
  39 + ng-model="vm.settings.jsonValue.prohibitDifferentUrl">
  40 + {{ 'admin.prohibit-different-url' | translate }}
  41 + </md-checkbox>
37 42 <div layout="row" layout-align="end center" width="100%" layout-wrap>
38 43 <md-button ng-disabled="$root.loading || vm.settingsForm.$invalid || !vm.settingsForm.$dirty" type="submit" class="md-raised md-primary">{{'action.save' | translate}}</md-button>
39 44 </div>
... ...
... ... @@ -74,6 +74,7 @@
74 74 "test-mail-sent": "Test mail was successfully sent!",
75 75 "base-url": "Base URL",
76 76 "base-url-required": "Base URL is required.",
  77 + "prohibit-different-url": "Prohibit different URL",
77 78 "mail-from": "Mail From",
78 79 "mail-from-required": "Mail From is required.",
79 80 "smtp-protocol": "SMTP protocol",
... ...