Skip to content

Commit 93001e5

Browse files
committed
switch token to base62 format
1 parent 200a3da commit 93001e5

File tree

19 files changed

+197
-74
lines changed

19 files changed

+197
-74
lines changed

.jhipster/Token.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"fields": [
1414
{
1515
"fieldName": "token",
16-
"fieldType": "UUID"
16+
"fieldType": "String"
1717
},
1818
{
1919
"fieldName": "creation",

src/main/java/org/mskcc/cbio/oncokb/domain/Token.java

+5-8
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
package org.mskcc.cbio.oncokb.domain;
22

33
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4-
import org.hibernate.annotations.Type;
54

65
import javax.persistence.*;
76
import javax.validation.constraints.*;
87

98
import java.io.Serializable;
109
import java.time.Instant;
11-
import java.util.UUID;
1210

1311
/**
1412
* A Token.
@@ -23,9 +21,8 @@ public class Token implements Serializable {
2321
@GeneratedValue(strategy = GenerationType.IDENTITY)
2422
private Long id;
2523

26-
@Type(type = "uuid-char")
27-
@Column(name = "token", length = 36)
28-
private UUID token;
24+
@Column(name = "token", length = 40)
25+
private String token;
2926

3027
@Column(name = "creation")
3128
private Instant creation;
@@ -60,16 +57,16 @@ public void setId(Long id) {
6057
this.id = id;
6158
}
6259

63-
public UUID getToken() {
60+
public String getToken() {
6461
return token;
6562
}
6663

67-
public Token token(UUID token) {
64+
public Token token(String token) {
6865
this.token = token;
6966
return this;
7067
}
7168

72-
public void setToken(UUID token) {
69+
public void setToken(String token) {
7370
this.token = token;
7471
}
7572

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package org.mskcc.cbio.oncokb.domain;
2+
3+
import java.io.Serializable;
4+
import java.security.SecureRandom;
5+
import java.util.zip.CRC32;
6+
7+
import org.apache.commons.lang3.StringUtils;
8+
import org.mskcc.cbio.oncokb.domain.enumeration.TokenType;
9+
10+
public class TokenKey implements Serializable {
11+
public static int TOKEN_CHAR_LENGTH = 30;
12+
13+
public static int CHECKSUM_CHAR_LENGTH = 6;
14+
15+
private static String BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
16+
17+
private TokenType tokenType;
18+
19+
private String token;
20+
21+
private String checksum;
22+
23+
public static TokenKey generate(TokenType type) {
24+
TokenKey tokenKey = new TokenKey();
25+
tokenKey.setTokenType(type);
26+
27+
String token = generateToken();
28+
tokenKey.setToken(token);
29+
tokenKey.setChecksum(generateChecksum(token));
30+
31+
return tokenKey;
32+
}
33+
34+
public boolean validate() {
35+
return generateChecksum(token).equals(this.checksum);
36+
}
37+
38+
private static String generateToken() {
39+
SecureRandom secureRandom = new SecureRandom();
40+
StringBuilder token = new StringBuilder();
41+
for (int i = 0; i < TOKEN_CHAR_LENGTH; i++) {
42+
token.append(BASE62_CHARS.charAt(secureRandom.nextInt(BASE62_CHARS.length())));
43+
}
44+
return token.toString();
45+
}
46+
47+
public static String generateChecksum(String token) {
48+
CRC32 crc32 = new CRC32();
49+
crc32.update(token.getBytes());
50+
String base62Checksum = toBase62(crc32.getValue());
51+
if (base62Checksum.length() < CHECKSUM_CHAR_LENGTH) {
52+
base62Checksum = StringUtils.repeat('0', CHECKSUM_CHAR_LENGTH - base62Checksum.length()) + base62Checksum;
53+
}
54+
return base62Checksum;
55+
}
56+
57+
private static String toBase62(long val) {
58+
StringBuffer sb = new StringBuffer();
59+
while(val > 0) {
60+
int remainder = (int) (val % 62);
61+
val = val / 62;
62+
sb.insert(0, BASE62_CHARS.charAt((int) remainder));
63+
}
64+
return sb.toString();
65+
}
66+
67+
public TokenType getTokenType() {
68+
return tokenType;
69+
}
70+
71+
public void setTokenType(TokenType tokenType) {
72+
this.tokenType = tokenType;
73+
}
74+
75+
public String getToken() {
76+
return token;
77+
}
78+
79+
public void setToken(String token) {
80+
this.token = token;
81+
}
82+
83+
public String getChecksum() {
84+
return checksum;
85+
}
86+
87+
public void setChecksum(String checksum) {
88+
this.checksum = checksum;
89+
}
90+
91+
public String getFullToken() {
92+
return this.tokenType.getType() + "_" + this.token + this.checksum;
93+
}
94+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.mskcc.cbio.oncokb.domain.enumeration;
2+
3+
public enum TokenType {
4+
USER("okbu"),
5+
SERVICE("okbs");
6+
7+
String type;
8+
9+
TokenType(String type) {
10+
this.type = type;
11+
}
12+
13+
public String getType() {
14+
return this.type;
15+
}
16+
}

src/main/java/org/mskcc/cbio/oncokb/repository/TokenRepository.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public interface TokenRepository extends JpaRepository<Token, Long> {
3333
Optional<Token> findPublicWebsiteToken();
3434

3535
@Cacheable(cacheResolver = "tokenCacheResolver")
36-
Optional<Token> findByToken(UUID token);
36+
Optional<Token> findByToken(String token);
3737

3838
@Cacheable(cacheResolver = "tokenCacheResolver")
3939
@Query("select token from Token token where token.user.login = ?1")

src/main/java/org/mskcc/cbio/oncokb/security/uuid/TokenProvider.java

+16-14
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import org.mskcc.cbio.oncokb.domain.Authority;
44
import org.mskcc.cbio.oncokb.domain.Token;
5+
import org.mskcc.cbio.oncokb.domain.TokenKey;
56
import org.mskcc.cbio.oncokb.domain.User;
7+
import org.mskcc.cbio.oncokb.domain.enumeration.TokenType;
68
import org.mskcc.cbio.oncokb.repository.UserRepository;
79
import org.mskcc.cbio.oncokb.security.AuthoritiesConstants;
810
import org.mskcc.cbio.oncokb.security.SecurityUtils;
@@ -50,11 +52,11 @@ public List<Token> getUserTokens(User userLogin) {
5052
return tokenService.findByUser(userLogin);
5153
}
5254

53-
private Token getNewToken(Set<Authority> authorities, Optional<Instant> definedExpirationTime) {
54-
return getNewToken(authorities, definedExpirationTime, Optional.of(true));
55+
private Token getNewToken(Set<Authority> authorities, TokenType tokenType, Optional<Instant> definedExpirationTime) {
56+
return getNewToken(authorities, tokenType, definedExpirationTime, Optional.of(true));
5557
}
5658

57-
private Token getNewToken(Set<Authority> authorities, Optional<Instant> definedExpirationTime, Optional<Boolean> isRenewable) {
59+
private Token getNewToken(Set<Authority> authorities, TokenType tokenType, Optional<Instant> definedExpirationTime, Optional<Boolean> isRenewable) {
5860
Token token = new Token();
5961
Instant currentTime = Instant.now();
6062
token.setCreation(currentTime);
@@ -73,20 +75,20 @@ private Token getNewToken(Set<Authority> authorities, Optional<Instant> definedE
7375
Instant.now().plusSeconds(EXPIRATION_TIME_PUBLIC_WEBSITE_IN_SECONDS) : currentTime.plusSeconds(EXPIRATION_TIME_IN_SECONDS);
7476
token.setExpiration(expirationTime);
7577
}
76-
token.setToken(UUID.randomUUID());
78+
token.setToken(TokenKey.generate(tokenType).getFullToken());
7779
return token;
7880
}
7981

8082
public Token createTokenForCurrentUserLogin(Optional<Instant> definedExpirationTime, Optional<Boolean> isRenewable) {
8183
Optional<User> userOptional = userRepository.findOneWithAuthoritiesByLogin(SecurityUtils.getCurrentUserLogin().get());
8284
if(userOptional.isPresent()) {
83-
return createToken(userOptional.get(), definedExpirationTime, isRenewable, Optional.empty());
85+
return createToken(userOptional.get(), TokenType.USER ,definedExpirationTime, isRenewable, Optional.empty());
8486
}
8587
return null;
8688
}
8789

88-
public Token createToken(User user, Optional<Instant> definedExpirationTime, Optional<Boolean> isRenewable, Optional<String> name) {
89-
Token token = getNewToken(user.getAuthorities(), definedExpirationTime, isRenewable);
90+
public Token createToken(User user, TokenType tokenType, Optional<Instant> definedExpirationTime, Optional<Boolean> isRenewable, Optional<String> name) {
91+
Token token = getNewToken(user.getAuthorities(), tokenType, definedExpirationTime, isRenewable);
9092
token.setUser(user);
9193
if (name.isPresent()) {
9294
token.setName(name.get());
@@ -95,29 +97,29 @@ public Token createToken(User user, Optional<Instant> definedExpirationTime, Opt
9597
return token;
9698
}
9799

98-
public void createToken(Token token, Optional<String> name){
99-
Token newToken = createToken(token.getUser(), Optional.of(token.getExpiration()), Optional.of(token.isRenewable()), name);
100+
public void createToken(Token token, TokenType tokenType, Optional<String> name){
101+
Token newToken = createToken(token.getUser(), tokenType, Optional.of(token.getExpiration()), Optional.of(token.isRenewable()), name);
100102
newToken.setCreation(token.getCreation());
101103
newToken.setCurrentUsage(token.getCurrentUsage());
102104
newToken.setUsageLimit(token.getUsageLimit());
103105
tokenService.save(newToken);
104106
}
105107

106108
// This method is used in the frontend thymeleaf parsing
107-
public UUID getPubWebToken() {
109+
public String getPubWebToken() {
108110
Optional<User> user = userRepository.findOneWithAuthoritiesByLogin(PUBLIC_WEBSITE_LOGIN);
109111
if (user.isPresent()) {
110112
Token userToken = new Token();
111113
Optional<Token> tokenOptional = tokenService.findPublicWebsiteToken();
112114
if (!tokenOptional.isPresent()) {
113-
Token newToken = getNewToken(user.get().getAuthorities(), Optional.empty());
115+
Token newToken = getNewToken(user.get().getAuthorities(), TokenType.USER, Optional.empty());
114116
newToken.setUser(user.get());
115117
userToken = tokenService.save(newToken);
116118
} else {
117119
userToken = tokenOptional.get();
118120
if (userToken.getExpiration().isBefore(Instant.now())) {
119121
// I want to update the token associated with public website once it's expired
120-
Token newToken = getNewToken(user.get().getAuthorities(), Optional.empty(), Optional.empty());
122+
Token newToken = getNewToken(user.get().getAuthorities(), TokenType.USER, Optional.empty(), Optional.empty());
121123
userToken.setToken(newToken.getToken());
122124
userToken.setCreation(newToken.getCreation());
123125
userToken.setExpiration(newToken.getExpiration());
@@ -131,7 +133,7 @@ public UUID getPubWebToken() {
131133
return null;
132134
}
133135

134-
public Authentication getAuthentication(UUID token) {
136+
public Authentication getAuthentication(String token) {
135137
Optional<Token> tokenOptional = tokenService.findByToken(token);
136138

137139
Optional<User> user = userRepository.findOneWithAuthoritiesByLogin(tokenOptional.get().getUser().getLogin());
@@ -143,7 +145,7 @@ public Authentication getAuthentication(UUID token) {
143145
return new UsernamePasswordAuthenticationToken(user.get().getLogin(), token, authorities);
144146
}
145147

146-
public boolean validateToken(UUID tokenValue) {
148+
public boolean validateToken(String tokenValue) {
147149
try {
148150
Optional<Token> token = tokenService.findByToken(tokenValue);
149151
if (token.isPresent() && token.get().getExpiration().isAfter(Instant.now())) {

src/main/java/org/mskcc/cbio/oncokb/security/uuid/UUIDFilter.java

+5-6
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import javax.servlet.ServletResponse;
1212
import javax.servlet.http.HttpServletRequest;
1313
import java.io.IOException;
14-
import java.util.UUID;
1514

1615
/**
1716
* Filters incoming requests and installs a Spring Security principal if a header corresponding to a valid user is
@@ -31,20 +30,20 @@ public UUIDFilter(TokenProvider tokenProvider) {
3130
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
3231
throws IOException, ServletException {
3332
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
34-
UUID uuid = resolveToken(httpServletRequest);
35-
if (uuid != null && this.tokenProvider.validateToken(uuid)) {
36-
Authentication authentication = this.tokenProvider.getAuthentication(uuid);
33+
String token = resolveToken(httpServletRequest);
34+
if (token != null && this.tokenProvider.validateToken(token)) {
35+
Authentication authentication = this.tokenProvider.getAuthentication(token);
3736
SecurityContextHolder.getContext().setAuthentication(authentication);
3837
// this.tokenProvider.addAccessRecord(uuid, servletRequest.getRemoteAddr());
3938
}
4039
filterChain.doFilter(servletRequest, servletResponse);
4140
}
4241

43-
private UUID resolveToken(HttpServletRequest request) {
42+
private String resolveToken(HttpServletRequest request) {
4443
String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
4544
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
4645
try {
47-
return UUID.fromString(bearerToken.substring(7));
46+
return bearerToken.substring(7);
4847
} catch (Exception e) {
4948
logger.info("Invalid token.");
5049
return null;

src/main/java/org/mskcc/cbio/oncokb/service/TokenService.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public interface TokenService {
3939

4040
Optional<Token> findPublicWebsiteToken();
4141

42-
Optional<Token> findByToken(UUID token);
42+
Optional<Token> findByToken(String token);
4343

4444
List<Token> findByUserIsCurrentUser();
4545

src/main/java/org/mskcc/cbio/oncokb/service/UserService.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.mskcc.cbio.oncokb.domain.enumeration.LicenseModel;
1111
import org.mskcc.cbio.oncokb.domain.enumeration.LicenseStatus;
1212
import org.mskcc.cbio.oncokb.domain.enumeration.LicenseType;
13+
import org.mskcc.cbio.oncokb.domain.enumeration.TokenType;
1314
import org.mskcc.cbio.oncokb.repository.AuthorityRepository;
1415
import org.mskcc.cbio.oncokb.repository.CompanyDomainRepository;
1516
import org.mskcc.cbio.oncokb.repository.CompanyRepository;
@@ -42,7 +43,6 @@
4243
import org.springframework.transaction.annotation.Transactional;
4344
import org.springframework.cache.annotation.Cacheable;
4445

45-
import javax.mail.MessagingException;
4646
import javax.validation.constraints.NotNull;
4747
import java.time.Instant;
4848
import java.time.temporal.ChronoUnit;
@@ -645,6 +645,7 @@ private List<Token> generateTokenForUserIfNotExist(UserDTO userDTO, Optional<Int
645645
if (tokens.isEmpty()) {
646646
Token token = tokenProvider.createToken(
647647
userMapper.userDTOToUser(userDTO),
648+
TokenType.USER,
648649
tokenValidDays.isPresent() ? Optional.of(Instant.now().plusSeconds(DAY_IN_SECONDS * (long) tokenValidDays.get())) : Optional.empty(),
649650
tokenIsRenewable,
650651
Optional.empty()

src/main/java/org/mskcc/cbio/oncokb/service/impl/CompanyServiceImpl.java

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.mskcc.cbio.oncokb.domain.UserDetails;
2525
import org.mskcc.cbio.oncokb.domain.enumeration.LicenseStatus;
2626
import org.mskcc.cbio.oncokb.domain.enumeration.LicenseType;
27+
import org.mskcc.cbio.oncokb.domain.enumeration.TokenType;
2728
import org.mskcc.cbio.oncokb.repository.CompanyRepository;
2829
import org.mskcc.cbio.oncokb.repository.UserDetailsRepository;
2930
import org.mskcc.cbio.oncokb.repository.UserRepository;
@@ -319,6 +320,7 @@ public Optional<Token> createServiceAccountToken(Long id, String name) throws To
319320

320321
return Optional.of(tokenProvider.createToken(
321322
serviceUser,
323+
TokenType.SERVICE,
322324
Optional.of(
323325
LocalDateTime.of(9999, 1, 1, 0, 0).atZone(ZoneId.systemDefault()).toInstant()
324326
),

src/main/java/org/mskcc/cbio/oncokb/service/impl/TokenServiceImpl.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.util.List;
2020
import java.util.Objects;
2121
import java.util.Optional;
22-
import java.util.UUID;
2322
import java.util.stream.Collectors;
2423

2524
import static org.mskcc.cbio.oncokb.config.cache.TokenCacheResolver.TOKENS_BY_USER_LOGIN_CACHE;
@@ -85,7 +84,7 @@ public Optional<Token> findPublicWebsiteToken() {
8584
}
8685

8786
@Override
88-
public Optional<Token> findByToken(UUID token) {
87+
public Optional<Token> findByToken(String token) {
8988
return tokenRepository.findByToken(token);
9089
}
9190

0 commit comments

Comments
 (0)