Skip to content

Commit

Permalink
Merge pull request thingsboard#10884 from thingsboard/fix/token-factory
Browse files Browse the repository at this point in the history
Fix token sessionId calculation
  • Loading branch information
ViacheslavKlimov authored May 29, 2024
2 parents bf5d99f + 5e2a4a7 commit bbc6b9a
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -34,8 +33,8 @@
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;
Expand All @@ -49,7 +48,6 @@
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;
Expand Down Expand Up @@ -105,9 +103,8 @@ public void logout(HttpServletRequest request) throws ThingsboardException {
@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();
Expand All @@ -123,10 +120,7 @@ public ObjectNode changePassword(
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)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
Expand All @@ -46,7 +51,6 @@ public SecurityUser(User user, boolean enabled, UserPrincipal userPrincipal) {
super(user);
this.enabled = enabled;
this.userPrincipal = userPrincipal;
this.sessionId = UUID.randomUUID().toString();
}

public Collection<GrantedAuthority> getAuthorities() {
Expand All @@ -58,27 +62,4 @@ public Collection<GrantedAuthority> getAuthorities() {
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ public Jws<Claims> parseTokenClaims(String token) {
}

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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,7 @@ public void beforeEach() {

@Test
public void testCreateAndParseAccessJwtToken() {
SecurityUser securityUser = new SecurityUser();
securityUser.setId(new UserId(UUID.randomUUID()));
securityUser.setEmail("[email protected]");
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);

Expand Down Expand Up @@ -111,18 +102,12 @@ public void testCreateAndParseAccessJwtToken(SecurityUser securityUser) {
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("[email protected]");
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());
Expand All @@ -138,15 +123,7 @@ public void testCreateAndParseRefreshJwtToken() {

@Test
public void testCreateAndParsePreVerificationJwtToken() {
SecurityUser securityUser = new SecurityUser();
securityUser.setId(new UserId(UUID.randomUUID()));
securityUser.setEmail("[email protected]");
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);
Expand All @@ -162,6 +139,34 @@ public void testCreateAndParsePreVerificationJwtToken() {
});
}

@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("[email protected]");
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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@
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;

/**
Expand Down Expand Up @@ -64,6 +64,23 @@ public void setAdditionalInfo(JsonNode addInfo) {
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -25,6 +26,7 @@
@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..")
Expand Down

0 comments on commit bbc6b9a

Please sign in to comment.