Fix token sessionId calculation

This commit is contained in:
ViacheslavKlimov 2024-05-28 15:43:50 +03:00
parent bf5d99fab1
commit 5e2a4a73b7
6 changed files with 64 additions and 64 deletions

View File

@ -15,7 +15,6 @@
*/
package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
@ -34,8 +33,8 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.server.cache.limits.RateLimitService;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
@ -49,7 +48,6 @@ import org.thingsboard.server.common.data.security.model.JwtPair;
import org.thingsboard.server.common.data.security.model.SecuritySettings;
import org.thingsboard.server.common.data.security.model.UserPasswordPolicy;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.cache.limits.RateLimitService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.auth.rest.RestAuthenticationDetails;
import org.thingsboard.server.service.security.model.ActivateUserRequest;
@ -105,9 +103,8 @@ public class AuthController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/auth/changePassword", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public ObjectNode changePassword(
@Parameter(description = "Change Password Request")
@RequestBody ChangePasswordRequest changePasswordRequest) throws ThingsboardException {
public JwtPair changePassword(@Parameter(description = "Change Password Request")
@RequestBody ChangePasswordRequest changePasswordRequest) throws ThingsboardException {
String currentPassword = changePasswordRequest.getCurrentPassword();
String newPassword = changePasswordRequest.getNewPassword();
SecurityUser securityUser = getCurrentUser();
@ -123,10 +120,7 @@ public class AuthController extends BaseController {
userService.replaceUserCredentials(securityUser.getTenantId(), userCredentials);
eventPublisher.publishEvent(new UserCredentialsInvalidationEvent(securityUser.getId()));
ObjectNode response = JacksonUtil.newObjectNode();
response.put("token", tokenFactory.createAccessJwtToken(securityUser).getToken());
response.put("refreshToken", tokenFactory.createRefreshToken(securityUser).getToken());
return response;
return tokenFactory.createTokenPair(securityUser);
}
@ApiOperation(value = "Get the current User password policy (getUserPasswordPolicy)",

View File

@ -15,6 +15,8 @@
*/
package org.thingsboard.server.service.security.model;
import lombok.Getter;
import lombok.Setter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.thingsboard.server.common.data.User;
@ -30,9 +32,12 @@ public class SecurityUser extends User {
private static final long serialVersionUID = -797397440703066079L;
private Collection<GrantedAuthority> authorities;
@Getter @Setter
private boolean enabled;
@Getter @Setter
private UserPrincipal userPrincipal;
private String sessionId;
@Getter @Setter
private String sessionId = UUID.randomUUID().toString();
public SecurityUser() {
super();
@ -46,7 +51,6 @@ public class SecurityUser extends User {
super(user);
this.enabled = enabled;
this.userPrincipal = userPrincipal;
this.sessionId = UUID.randomUUID().toString();
}
public Collection<GrantedAuthority> getAuthorities() {
@ -58,27 +62,4 @@ public class SecurityUser extends User {
return authorities;
}
public boolean isEnabled() {
return enabled;
}
public UserPrincipal getUserPrincipal() {
return userPrincipal;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public void setUserPrincipal(UserPrincipal userPrincipal) {
this.userPrincipal = userPrincipal;
}
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
}

View File

@ -232,6 +232,7 @@ public class JwtTokenFactory {
}
public JwtPair createTokenPair(SecurityUser securityUser) {
securityUser.setSessionId(UUID.randomUUID().toString());
JwtToken accessToken = createAccessJwtToken(securityUser);
JwtToken refreshToken = createRefreshToken(securityUser);
return new JwtPair(accessToken.getToken(), refreshToken.getToken());

View File

@ -73,16 +73,7 @@ public class JwtTokenFactoryTest {
@Test
public void testCreateAndParseAccessJwtToken() {
SecurityUser securityUser = new SecurityUser();
securityUser.setId(new UserId(UUID.randomUUID()));
securityUser.setEmail("tenant@thingsboard.org");
securityUser.setAuthority(Authority.TENANT_ADMIN);
securityUser.setTenantId(new TenantId(UUID.randomUUID()));
securityUser.setEnabled(true);
securityUser.setFirstName("A");
securityUser.setLastName("B");
securityUser.setUserPrincipal(new UserPrincipal(UserPrincipal.Type.USER_NAME, securityUser.getEmail()));
securityUser.setCustomerId(new CustomerId(UUID.randomUUID()));
SecurityUser securityUser = createSecurityUser();
testCreateAndParseAccessJwtToken(securityUser);
@ -111,18 +102,12 @@ public class JwtTokenFactoryTest {
assertThat(parsedSecurityUser.getCustomerId()).isEqualTo(securityUser.getCustomerId());
assertThat(parsedSecurityUser.getFirstName()).isEqualTo(securityUser.getFirstName());
assertThat(parsedSecurityUser.getLastName()).isEqualTo(securityUser.getLastName());
assertThat(parsedSecurityUser.getSessionId()).isNotNull().isEqualTo(securityUser.getSessionId());
}
@Test
public void testCreateAndParseRefreshJwtToken() {
SecurityUser securityUser = new SecurityUser();
securityUser.setId(new UserId(UUID.randomUUID()));
securityUser.setEmail("tenant@thingsboard.org");
securityUser.setAuthority(Authority.TENANT_ADMIN);
securityUser.setUserPrincipal(new UserPrincipal(UserPrincipal.Type.USER_NAME, securityUser.getEmail()));
securityUser.setEnabled(true);
securityUser.setTenantId(new TenantId(UUID.randomUUID()));
securityUser.setCustomerId(new CustomerId(UUID.randomUUID()));
SecurityUser securityUser = createSecurityUser();
JwtToken refreshToken = tokenFactory.createRefreshToken(securityUser);
checkExpirationTime(refreshToken, jwtSettings.getRefreshTokenExpTime());
@ -138,15 +123,7 @@ public class JwtTokenFactoryTest {
@Test
public void testCreateAndParsePreVerificationJwtToken() {
SecurityUser securityUser = new SecurityUser();
securityUser.setId(new UserId(UUID.randomUUID()));
securityUser.setEmail("tenant@thingsboard.org");
securityUser.setAuthority(Authority.TENANT_ADMIN);
securityUser.setUserPrincipal(new UserPrincipal(UserPrincipal.Type.USER_NAME, securityUser.getEmail()));
securityUser.setEnabled(true);
securityUser.setTenantId(new TenantId(UUID.randomUUID()));
securityUser.setCustomerId(new CustomerId(UUID.randomUUID()));
SecurityUser securityUser = createSecurityUser();
int tokenLifetime = (int) TimeUnit.MINUTES.toSeconds(30);
JwtToken preVerificationToken = tokenFactory.createPreVerificationToken(securityUser, tokenLifetime);
checkExpirationTime(preVerificationToken, tokenLifetime);
@ -162,6 +139,34 @@ public class JwtTokenFactoryTest {
});
}
@Test
public void testSessionId() {
SecurityUser securityUser = createSecurityUser();
String sessionId = securityUser.getSessionId();
String accessToken = tokenFactory.createAccessJwtToken(securityUser).getToken();
securityUser = tokenFactory.parseAccessJwtToken(accessToken);
assertThat(securityUser.getSessionId()).isNotNull().isEqualTo(sessionId);
String newAccessToken = tokenFactory.createTokenPair(securityUser).getToken();
securityUser = tokenFactory.parseAccessJwtToken(newAccessToken);
assertThat(securityUser.getSessionId()).isNotNull().isNotEqualTo(sessionId);
}
private SecurityUser createSecurityUser() {
SecurityUser securityUser = new SecurityUser();
securityUser.setId(new UserId(UUID.randomUUID()));
securityUser.setEmail("tenant@thingsboard.org");
securityUser.setAuthority(Authority.TENANT_ADMIN);
securityUser.setTenantId(new TenantId(UUID.randomUUID()));
securityUser.setEnabled(true);
securityUser.setFirstName("A");
securityUser.setLastName("B");
securityUser.setUserPrincipal(new UserPrincipal(UserPrincipal.Type.USER_NAME, securityUser.getEmail()));
securityUser.setCustomerId(new CustomerId(UUID.randomUUID()));
return securityUser;
}
private void mockJwtSettings(JwtSettings settings) {
AdminSettings adminJwtSettings = new AdminSettings();
adminJwtSettings.setJsonValue(JacksonUtil.valueToTree(settings));

View File

@ -18,17 +18,17 @@ package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.id.UUIDBased;
import org.thingsboard.server.common.data.validation.NoXss;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
@ -64,6 +64,23 @@ public abstract class BaseDataWithAdditionalInfo<I extends UUIDBased> extends Ba
setJson(addInfo, json -> this.additionalInfo = json, bytes -> this.additionalInfoBytes = bytes);
}
public void setAdditionalInfoField(String field, JsonNode value) {
JsonNode additionalInfo = getAdditionalInfo();
if (!(additionalInfo instanceof ObjectNode)) {
additionalInfo = mapper.createObjectNode();
}
((ObjectNode) additionalInfo).set(field, value);
setAdditionalInfo(additionalInfo);
}
public <T> T getAdditionalInfoField(String field, Function<JsonNode, T> mapper, T defaultValue) {
JsonNode additionalInfo = getAdditionalInfo();
if (additionalInfo != null && additionalInfo.has(field)) {
return mapper.apply(additionalInfo.get(field));
}
return defaultValue;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;

View File

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.common.data.security.model;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.NoArgsConstructor;
@ -25,6 +26,7 @@ import java.io.Serializable;
@Schema(description = "JWT Pair")
@Data
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class JwtPair implements Serializable {
@Schema(description = "The JWT Access Token. Used to perform API calls.", example = "AAB254FF67D..")