Commit d6c2eefe05d6cc8427e2fda8b2c9d0b50e374442
Committed by
Andrew Shvayka
1 parent
04727e81
base url improvements
Showing
9 changed files
with
66 additions
and
13 deletions
... | ... | @@ -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", | ... | ... |