1 |
|
package io.sunshower.service.security.crypto; |
2 |
|
|
3 |
|
import io.sunshower.common.Identifier; |
4 |
|
import io.sunshower.common.crypto.Hashes; |
5 |
|
import io.sunshower.common.crypto.Multihash; |
6 |
|
import io.sunshower.core.security.InvalidCredentialException; |
7 |
|
import io.sunshower.core.security.InvalidTokenException; |
8 |
|
import io.sunshower.core.security.crypto.EncryptionService; |
9 |
|
import io.sunshower.model.core.auth.User; |
10 |
|
import java.util.logging.Level; |
11 |
|
import java.util.logging.Logger; |
12 |
|
import javax.annotation.PostConstruct; |
13 |
|
import javax.inject.Inject; |
14 |
|
import javax.inject.Named; |
15 |
|
import javax.persistence.EntityManager; |
16 |
|
import javax.persistence.PersistenceContext; |
17 |
|
import org.jasypt.util.text.TextEncryptor; |
18 |
|
import org.springframework.cache.Cache; |
19 |
|
import org.springframework.security.crypto.password.PasswordEncoder; |
20 |
|
import org.springframework.stereotype.Service; |
21 |
|
|
22 |
|
@Service |
|
|
| 77.8% |
Uncovered Elements: 12 (54) |
Complexity: 16 |
Complexity Density: 0.47 |
|
23 |
|
public class StrongEncryptionService implements EncryptionService { |
24 |
|
|
25 |
|
static final Logger log = Logger.getLogger(StrongEncryptionService.class.getName()); |
26 |
|
|
27 |
|
static final Hashes.HashFunction hashFunction = Hashes.create(Multihash.Type.SHA_2_256); |
28 |
|
|
29 |
|
@Inject |
30 |
|
@Named("caches:authentication") |
31 |
|
private Cache cache; |
32 |
|
|
33 |
|
@Inject private PasswordEncoder encoder; |
34 |
|
|
35 |
|
@Inject private TextEncryptor encrypter; |
36 |
|
|
37 |
|
@PersistenceContext private EntityManager entityManager; |
38 |
|
|
39 |
|
@Inject private MessageAuthenticationCode messageAuthenticationCode; |
40 |
|
|
|
|
| 100% |
Uncovered Elements: 0 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
41 |
1 |
@PostConstruct... |
42 |
|
public void postConstruct() { |
43 |
1 |
log.log(Level.INFO, "Encryption Service using: " + hashFunction); |
44 |
|
} |
45 |
|
|
|
|
| 0% |
Uncovered Elements: 1 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
46 |
0 |
@Override... |
47 |
|
public String sign(String value) { |
48 |
0 |
return encrypter.encrypt(value); |
49 |
|
} |
50 |
|
|
|
|
| 0% |
Uncovered Elements: 1 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
51 |
0 |
@Override... |
52 |
|
public String unsign(String value) { |
53 |
0 |
return encrypter.decrypt(value); |
54 |
|
} |
55 |
|
|
|
|
| 60% |
Uncovered Elements: 2 (5) |
Complexity: 2 |
Complexity Density: 0.67 |
|
56 |
18 |
@Override... |
57 |
|
public String encrypt(String password) { |
58 |
18 |
if (password == null) { |
59 |
0 |
throw new IllegalArgumentException("Expected password to encrypt to not be null"); |
60 |
|
} |
61 |
18 |
return encoder.encode(password); |
62 |
|
} |
63 |
|
|
|
|
| 100% |
Uncovered Elements: 0 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
64 |
3 |
@Override... |
65 |
|
public boolean matches(String raw, String password) { |
66 |
3 |
return encoder.matches(raw, password); |
67 |
|
} |
68 |
|
|
|
|
| 100% |
Uncovered Elements: 0 (4) |
Complexity: 1 |
Complexity Density: 0.25 |
|
69 |
6 |
@Override... |
70 |
|
public String createToken(User user) { |
71 |
6 |
final String password = encrypter.encrypt(user.getPassword()); |
72 |
6 |
final String id = encrypter.encrypt(user.getId().toString()); |
73 |
6 |
final String combined = id + "#" + password; |
74 |
6 |
return messageAuthenticationCode.token(combined); |
75 |
|
} |
76 |
|
|
|
|
| 100% |
Uncovered Elements: 0 (9) |
Complexity: 2 |
Complexity Density: 0.29 |
|
77 |
7 |
@Override... |
78 |
|
public User findByToken(String token) { |
79 |
7 |
if (isLogoutRequest(token)) { |
80 |
1 |
final String[] parts = token.split("\\$\\$"); |
81 |
1 |
final String hashPart = parts[2]; |
82 |
1 |
final Multihash hash = compute(hashPart); |
83 |
1 |
cache.evict(hash); |
84 |
1 |
return null; |
85 |
|
} else { |
86 |
6 |
return findUser(token); |
87 |
|
} |
88 |
|
} |
89 |
|
|
|
|
| 100% |
Uncovered Elements: 0 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
90 |
7 |
private boolean isLogoutRequest(String token) {... |
91 |
7 |
return token.startsWith("$$logout$$"); |
92 |
|
} |
93 |
|
|
|
|
| 70% |
Uncovered Elements: 6 (20) |
Complexity: 5 |
Complexity Density: 0.36 |
|
94 |
6 |
private User findUser(String token) {... |
95 |
6 |
final Multihash multihash = compute(token); |
96 |
6 |
Cache.ValueWrapper value = cache.get(multihash); |
97 |
6 |
if (value != null && value.get() != null) { |
98 |
0 |
return (User) value.get(); |
99 |
|
} |
100 |
|
|
101 |
6 |
final String total = messageAuthenticationCode.id(token); |
102 |
5 |
final String[] parts = total.split("#"); |
103 |
|
|
104 |
5 |
if (parts.length != 2) { |
105 |
0 |
throw new InvalidTokenException("Nope"); |
106 |
|
} |
107 |
5 |
final Identifier id = Identifier.valueOf(encrypter.decrypt(parts[0])); |
108 |
5 |
final String password = encrypter.decrypt(parts[1]); |
109 |
|
|
110 |
5 |
User user = |
111 |
|
entityManager |
112 |
|
.createQuery( |
113 |
|
"select u from User u " + "left join fetch u.roles as r " + "where u.id = :id", |
114 |
|
User.class) |
115 |
|
.setParameter("id", id.value()) |
116 |
|
.getSingleResult(); |
117 |
5 |
if (password.equals(user.getPassword())) { |
118 |
5 |
return user; |
119 |
|
} |
120 |
0 |
throw new InvalidCredentialException("Credential was invalid"); |
121 |
|
} |
122 |
|
|
|
|
| 100% |
Uncovered Elements: 0 (1) |
Complexity: 1 |
Complexity Density: 1 |
|
123 |
7 |
private Multihash compute(String token) {... |
124 |
7 |
return hashFunction.compute(token.getBytes()); |
125 |
|
} |
126 |
|
} |