1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.bremersee.security.core.userdetails;
18
19 import java.nio.charset.StandardCharsets;
20 import java.security.MessageDigest;
21 import java.security.NoSuchAlgorithmException;
22 import java.util.Base64;
23 import lombok.AccessLevel;
24 import lombok.Getter;
25 import lombok.ToString;
26 import lombok.extern.slf4j.Slf4j;
27 import org.bremersee.exception.ServiceException;
28 import org.springframework.security.crypto.factory.PasswordEncoderFactories;
29 import org.springframework.security.crypto.password.PasswordEncoder;
30 import org.springframework.util.StringUtils;
31
32
33
34
35
36
37 @ToString
38 @Slf4j
39 public class LdaptivePasswordEncoder implements PasswordEncoder {
40
41
42
43
44
45
46 public static LdaptivePasswordEncoder plain() {
47 return new LdaptivePasswordEncoder("plain", null);
48 }
49
50
51
52
53
54
55 public static LdaptivePasswordEncoder plainWithNoLabel() {
56 return new LdaptivePasswordEncoder(null, null);
57 }
58
59
60
61
62 protected static final PasswordEncoder delegate = PasswordEncoderFactories.createDelegatingPasswordEncoder();
63
64 @Getter(value = AccessLevel.PROTECTED)
65 private final String label;
66
67 @Getter(value = AccessLevel.PROTECTED)
68 private final String algorithm;
69
70
71
72
73 public LdaptivePasswordEncoder() {
74 this("SHA", "SHA");
75 }
76
77
78
79
80
81
82
83 public LdaptivePasswordEncoder(String label, String algorithm) {
84 this.label = label;
85 this.algorithm = algorithm;
86 }
87
88 @Override
89 public String encode(CharSequence rawPassword) {
90 String raw = rawPassword != null ? rawPassword.toString() : "";
91 StringBuilder sb = new StringBuilder();
92 if (StringUtils.hasText(getLabel())) {
93 sb.append('{').append(getLabel()).append('}');
94 }
95 if (!StringUtils.hasText(getAlgorithm()) || "plain".equalsIgnoreCase(getAlgorithm())) {
96 sb.append(rawPassword);
97 } else {
98 sb.append(encrypt(raw));
99 }
100 return sb.toString();
101 }
102
103 private String encrypt(String raw) {
104 try {
105 final MessageDigest md = MessageDigest.getInstance(getAlgorithm());
106 md.update(raw.getBytes(StandardCharsets.UTF_8));
107 byte[] hash = md.digest();
108 return new String(Base64.getEncoder().encode(hash), StandardCharsets.UTF_8);
109
110 } catch (NoSuchAlgorithmException e) {
111 throw ServiceException.internalServerError("Algorithm '" + getAlgorithm() + "' was not found.", e);
112 }
113 }
114
115 @Override
116 public boolean matches(CharSequence rawPassword, String encodedPassword) {
117 String raw = rawPassword != null ? rawPassword.toString() : "";
118 String enc = encodedPassword != null ? encodedPassword : "";
119 int index = enc.indexOf('}');
120 if (enc.startsWith("{") && index > 0) {
121 String foundLabel = enc.substring(1, index);
122 if ("plain".equalsIgnoreCase(foundLabel)) {
123 return enc.equals(LdaptivePasswordEncoder.plain().encode(raw));
124 } else if (foundLabel.equals(getLabel())) {
125 return enc.equals(encode(raw));
126 } else {
127 return delegate.matches(raw, enc);
128 }
129 } else if (!StringUtils.hasText(getLabel())) {
130 return StringUtils.hasText(getAlgorithm())
131 ? enc.equals(encode(raw))
132 : enc.equals(LdaptivePasswordEncoder.plainWithNoLabel().encode(raw));
133 }
134 return false;
135 }
136
137 }