|
|
|
@ -18,6 +18,7 @@ package org.thingsboard.server.service.security.model.token; |
|
|
|
import io.jsonwebtoken.Claims; |
|
|
|
import io.jsonwebtoken.ExpiredJwtException; |
|
|
|
import io.jsonwebtoken.Jws; |
|
|
|
import io.jsonwebtoken.JwtBuilder; |
|
|
|
import io.jsonwebtoken.Jwts; |
|
|
|
import io.jsonwebtoken.MalformedJwtException; |
|
|
|
import io.jsonwebtoken.SignatureAlgorithm; |
|
|
|
@ -36,6 +37,7 @@ import org.thingsboard.server.common.data.security.Authority; |
|
|
|
import org.thingsboard.server.common.data.security.model.JwtToken; |
|
|
|
import org.thingsboard.server.config.JwtSettings; |
|
|
|
import org.thingsboard.server.service.security.exception.JwtExpiredTokenException; |
|
|
|
import org.thingsboard.server.service.security.model.JwtTokenPair; |
|
|
|
import org.thingsboard.server.service.security.model.SecurityUser; |
|
|
|
import org.thingsboard.server.service.security.model.UserPrincipal; |
|
|
|
|
|
|
|
@ -58,6 +60,7 @@ public class JwtTokenFactory { |
|
|
|
private static final String IS_PUBLIC = "isPublic"; |
|
|
|
private static final String TENANT_ID = "tenantId"; |
|
|
|
private static final String CUSTOMER_ID = "customerId"; |
|
|
|
private static final String SESSION_ID = "sessionId"; |
|
|
|
|
|
|
|
private final JwtSettings settings; |
|
|
|
|
|
|
|
@ -70,39 +73,28 @@ public class JwtTokenFactory { |
|
|
|
* Factory method for issuing new JWT Tokens. |
|
|
|
*/ |
|
|
|
public AccessJwtToken createAccessJwtToken(SecurityUser securityUser) { |
|
|
|
if (StringUtils.isBlank(securityUser.getEmail())) |
|
|
|
throw new IllegalArgumentException("Cannot create JWT Token without username/email"); |
|
|
|
|
|
|
|
if (securityUser.getAuthority() == null) |
|
|
|
if (securityUser.getAuthority() == null) { |
|
|
|
throw new IllegalArgumentException("User doesn't have any privileges"); |
|
|
|
} |
|
|
|
|
|
|
|
UserPrincipal principal = securityUser.getUserPrincipal(); |
|
|
|
String subject = principal.getValue(); |
|
|
|
Claims claims = Jwts.claims().setSubject(subject); |
|
|
|
claims.put(SCOPES, securityUser.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList())); |
|
|
|
claims.put(USER_ID, securityUser.getId().getId().toString()); |
|
|
|
claims.put(FIRST_NAME, securityUser.getFirstName()); |
|
|
|
claims.put(LAST_NAME, securityUser.getLastName()); |
|
|
|
claims.put(ENABLED, securityUser.isEnabled()); |
|
|
|
claims.put(IS_PUBLIC, principal.getType() == UserPrincipal.Type.PUBLIC_ID); |
|
|
|
|
|
|
|
JwtBuilder jwtBuilder = setUpToken(securityUser, securityUser.getAuthorities().stream() |
|
|
|
.map(GrantedAuthority::getAuthority).collect(Collectors.toList()), settings.getTokenExpirationTime()); |
|
|
|
jwtBuilder.claim(FIRST_NAME, securityUser.getFirstName()) |
|
|
|
.claim(LAST_NAME, securityUser.getLastName()) |
|
|
|
.claim(ENABLED, securityUser.isEnabled()) |
|
|
|
.claim(IS_PUBLIC, principal.getType() == UserPrincipal.Type.PUBLIC_ID); |
|
|
|
if (securityUser.getTenantId() != null) { |
|
|
|
claims.put(TENANT_ID, securityUser.getTenantId().getId().toString()); |
|
|
|
jwtBuilder.claim(TENANT_ID, securityUser.getTenantId().getId().toString()); |
|
|
|
} |
|
|
|
if (securityUser.getCustomerId() != null) { |
|
|
|
claims.put(CUSTOMER_ID, securityUser.getCustomerId().getId().toString()); |
|
|
|
jwtBuilder.claim(CUSTOMER_ID, securityUser.getCustomerId().getId().toString()); |
|
|
|
} |
|
|
|
|
|
|
|
ZonedDateTime currentTime = ZonedDateTime.now(); |
|
|
|
String token = jwtBuilder.compact(); |
|
|
|
|
|
|
|
String token = Jwts.builder() |
|
|
|
.setClaims(claims) |
|
|
|
.setIssuer(settings.getTokenIssuer()) |
|
|
|
.setIssuedAt(Date.from(currentTime.toInstant())) |
|
|
|
.setExpiration(Date.from(currentTime.plusSeconds(settings.getTokenExpirationTime()).toInstant())) |
|
|
|
.signWith(SignatureAlgorithm.HS512, settings.getTokenSigningKey()) |
|
|
|
.compact(); |
|
|
|
|
|
|
|
return new AccessJwtToken(token, claims); |
|
|
|
return new AccessJwtToken(token); |
|
|
|
} |
|
|
|
|
|
|
|
public SecurityUser parseAccessJwtToken(RawAccessJwtToken rawAccessToken) { |
|
|
|
@ -118,47 +110,40 @@ public class JwtTokenFactory { |
|
|
|
SecurityUser securityUser = new SecurityUser(new UserId(UUID.fromString(claims.get(USER_ID, String.class)))); |
|
|
|
securityUser.setEmail(subject); |
|
|
|
securityUser.setAuthority(Authority.parse(scopes.get(0))); |
|
|
|
securityUser.setFirstName(claims.get(FIRST_NAME, String.class)); |
|
|
|
securityUser.setLastName(claims.get(LAST_NAME, String.class)); |
|
|
|
securityUser.setEnabled(claims.get(ENABLED, Boolean.class)); |
|
|
|
boolean isPublic = claims.get(IS_PUBLIC, Boolean.class); |
|
|
|
UserPrincipal principal = new UserPrincipal(isPublic ? UserPrincipal.Type.PUBLIC_ID : UserPrincipal.Type.USER_NAME, subject); |
|
|
|
securityUser.setUserPrincipal(principal); |
|
|
|
String tenantId = claims.get(TENANT_ID, String.class); |
|
|
|
if (tenantId != null) { |
|
|
|
securityUser.setTenantId(TenantId.fromUUID(UUID.fromString(tenantId))); |
|
|
|
} else if (securityUser.getAuthority() == Authority.SYS_ADMIN) { |
|
|
|
securityUser.setTenantId(TenantId.SYS_TENANT_ID); |
|
|
|
} |
|
|
|
String customerId = claims.get(CUSTOMER_ID, String.class); |
|
|
|
if (customerId != null) { |
|
|
|
securityUser.setCustomerId(new CustomerId(UUID.fromString(customerId))); |
|
|
|
securityUser.setSessionId(claims.get(SESSION_ID, String.class)); |
|
|
|
|
|
|
|
if (securityUser.getAuthority() != Authority.PRE_VERIFICATION_TOKEN) { |
|
|
|
securityUser.setFirstName(claims.get(FIRST_NAME, String.class)); |
|
|
|
securityUser.setLastName(claims.get(LAST_NAME, String.class)); |
|
|
|
securityUser.setEnabled(claims.get(ENABLED, Boolean.class)); |
|
|
|
boolean isPublic = claims.get(IS_PUBLIC, Boolean.class); |
|
|
|
UserPrincipal principal = new UserPrincipal(isPublic ? UserPrincipal.Type.PUBLIC_ID : UserPrincipal.Type.USER_NAME, subject); |
|
|
|
securityUser.setUserPrincipal(principal); |
|
|
|
String customerId = claims.get(CUSTOMER_ID, String.class); |
|
|
|
if (customerId != null) { |
|
|
|
securityUser.setCustomerId(new CustomerId(UUID.fromString(customerId))); |
|
|
|
} |
|
|
|
} else { |
|
|
|
securityUser.setUserPrincipal(new UserPrincipal(UserPrincipal.Type.USER_NAME, subject)); |
|
|
|
} |
|
|
|
|
|
|
|
return securityUser; |
|
|
|
} |
|
|
|
|
|
|
|
public JwtToken createRefreshToken(SecurityUser securityUser) { |
|
|
|
if (StringUtils.isBlank(securityUser.getEmail())) { |
|
|
|
throw new IllegalArgumentException("Cannot create JWT Token without username/email"); |
|
|
|
} |
|
|
|
|
|
|
|
ZonedDateTime currentTime = ZonedDateTime.now(); |
|
|
|
|
|
|
|
UserPrincipal principal = securityUser.getUserPrincipal(); |
|
|
|
Claims claims = Jwts.claims().setSubject(principal.getValue()); |
|
|
|
claims.put(SCOPES, Collections.singletonList(Authority.REFRESH_TOKEN.name())); |
|
|
|
claims.put(USER_ID, securityUser.getId().getId().toString()); |
|
|
|
claims.put(IS_PUBLIC, principal.getType() == UserPrincipal.Type.PUBLIC_ID); |
|
|
|
|
|
|
|
String token = Jwts.builder() |
|
|
|
.setClaims(claims) |
|
|
|
.setIssuer(settings.getTokenIssuer()) |
|
|
|
.setId(UUID.randomUUID().toString()) |
|
|
|
.setIssuedAt(Date.from(currentTime.toInstant())) |
|
|
|
.setExpiration(Date.from(currentTime.plusSeconds(settings.getRefreshTokenExpTime()).toInstant())) |
|
|
|
.signWith(SignatureAlgorithm.HS512, settings.getTokenSigningKey()) |
|
|
|
.compact(); |
|
|
|
String token = setUpToken(securityUser, Collections.singletonList(Authority.REFRESH_TOKEN.name()), settings.getRefreshTokenExpTime()) |
|
|
|
.claim(IS_PUBLIC, principal.getType() == UserPrincipal.Type.PUBLIC_ID) |
|
|
|
.setId(UUID.randomUUID().toString()).compact(); |
|
|
|
|
|
|
|
return new AccessJwtToken(token, claims); |
|
|
|
return new AccessJwtToken(token); |
|
|
|
} |
|
|
|
|
|
|
|
public SecurityUser parseRefreshToken(RawAccessJwtToken rawAccessToken) { |
|
|
|
@ -177,9 +162,41 @@ public class JwtTokenFactory { |
|
|
|
UserPrincipal principal = new UserPrincipal(isPublic ? UserPrincipal.Type.PUBLIC_ID : UserPrincipal.Type.USER_NAME, subject); |
|
|
|
SecurityUser securityUser = new SecurityUser(new UserId(UUID.fromString(claims.get(USER_ID, String.class)))); |
|
|
|
securityUser.setUserPrincipal(principal); |
|
|
|
securityUser.setSessionId(claims.get(SESSION_ID, String.class)); |
|
|
|
return securityUser; |
|
|
|
} |
|
|
|
|
|
|
|
public JwtToken createPreVerificationToken(SecurityUser user) { |
|
|
|
String token = setUpToken(user, Collections.singletonList(Authority.PRE_VERIFICATION_TOKEN.name()), settings.getPreVerificationTokenExpirationTime()) |
|
|
|
.claim(TENANT_ID, user.getTenantId().toString()) |
|
|
|
.compact(); |
|
|
|
return new AccessJwtToken(token); |
|
|
|
} |
|
|
|
|
|
|
|
private JwtBuilder setUpToken(SecurityUser securityUser, List<String> scopes, long expirationTime) { |
|
|
|
if (StringUtils.isBlank(securityUser.getEmail())) { |
|
|
|
throw new IllegalArgumentException("Cannot create JWT Token without username/email"); |
|
|
|
} |
|
|
|
|
|
|
|
UserPrincipal principal = securityUser.getUserPrincipal(); |
|
|
|
|
|
|
|
Claims claims = Jwts.claims().setSubject(principal.getValue()); |
|
|
|
claims.put(USER_ID, securityUser.getId().getId().toString()); |
|
|
|
claims.put(SCOPES, scopes); |
|
|
|
if (securityUser.getSessionId() != null) { |
|
|
|
claims.put(SESSION_ID, securityUser.getSessionId()); |
|
|
|
} |
|
|
|
|
|
|
|
ZonedDateTime currentTime = ZonedDateTime.now(); |
|
|
|
|
|
|
|
return Jwts.builder() |
|
|
|
.setClaims(claims) |
|
|
|
.setIssuer(settings.getTokenIssuer()) |
|
|
|
.setIssuedAt(Date.from(currentTime.toInstant())) |
|
|
|
.setExpiration(Date.from(currentTime.plusSeconds(expirationTime).toInstant())) |
|
|
|
.signWith(SignatureAlgorithm.HS512, settings.getTokenSigningKey()); |
|
|
|
} |
|
|
|
|
|
|
|
public Jws<Claims> parseTokenClaims(JwtToken token) { |
|
|
|
try { |
|
|
|
return Jwts.parser() |
|
|
|
@ -193,4 +210,11 @@ public class JwtTokenFactory { |
|
|
|
throw new JwtExpiredTokenException(token, "JWT Token expired", expiredEx); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public JwtTokenPair createTokenPair(SecurityUser securityUser) { |
|
|
|
JwtToken accessToken = createAccessJwtToken(securityUser); |
|
|
|
JwtToken refreshToken = createRefreshToken(securityUser); |
|
|
|
return new JwtTokenPair(accessToken.getToken(), refreshToken.getToken()); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|