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 static org.bremersee.data.ldaptive.LdaptiveEntryMapper.getAttributeValue;
20 import static org.bremersee.data.ldaptive.LdaptiveEntryMapper.getAttributeValuesAsSet;
21 import static org.bremersee.data.ldaptive.transcoder.UserAccountControlValueTranscoder.isUserAccountEnabled;
22
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.stream.Collectors;
29 import lombok.AccessLevel;
30 import lombok.Getter;
31 import lombok.ToString;
32 import org.bremersee.data.ldaptive.LdaptiveEntryMapper;
33 import org.bremersee.data.ldaptive.transcoder.UserAccountControlValueTranscoder;
34 import org.ldaptive.AttributeModification;
35 import org.ldaptive.LdapEntry;
36 import org.ldaptive.transcode.AbstractStringValueTranscoder;
37 import org.ldaptive.transcode.ValueTranscoder;
38 import org.springframework.security.core.GrantedAuthority;
39 import org.springframework.security.core.authority.SimpleGrantedAuthority;
40 import org.springframework.security.core.userdetails.User;
41 import org.springframework.security.core.userdetails.UserDetails;
42 import org.springframework.util.StringUtils;
43
44
45
46
47
48
49 @ToString
50 public class UserDetailsLdapMapper implements LdaptiveEntryMapper<UserDetails> {
51
52 @Getter(value = AccessLevel.PROTECTED)
53 private final String userName;
54
55 @Getter(value = AccessLevel.PROTECTED)
56 private final String userAccountControlAttributeName;
57
58 @Getter(value = AccessLevel.PROTECTED)
59 private final List<String> authorities;
60
61 @Getter(value = AccessLevel.PROTECTED)
62 private final String authorityAttributeName;
63
64 @Getter(value = AccessLevel.PROTECTED)
65 private final String authorityPrefix;
66
67 @Getter(value = AccessLevel.PROTECTED)
68 private final ValueTranscoder<GrantedAuthority> authorityTranscoder;
69
70 @Getter(value = AccessLevel.PROTECTED)
71 private final UserAccountControlValueTranscoder userAccountControlValueTranscoder;
72
73
74
75
76
77
78
79
80
81
82
83
84 public UserDetailsLdapMapper(
85 String userName,
86 String userAccountControlAttributeName,
87 List<String> authorities,
88 String authorityAttributeName,
89 boolean authorityDn,
90 Map<String, String> authorityMap,
91 String authorityPrefix) {
92
93 this.userName = userName;
94 this.userAccountControlAttributeName = userAccountControlAttributeName;
95 this.authorities = authorities != null ? authorities : Collections.emptyList();
96 this.authorityAttributeName = authorityAttributeName;
97 this.authorityPrefix = authorityPrefix;
98 this.authorityTranscoder = new GrantedAuthorityValueTranscoder(authorityDn, authorityMap, authorityPrefix);
99 if (StringUtils.hasText(userAccountControlAttributeName)) {
100 userAccountControlValueTranscoder = new UserAccountControlValueTranscoder();
101 } else {
102 userAccountControlValueTranscoder = null;
103 }
104 }
105
106 @Override
107 public String[] getObjectClasses() {
108 return null;
109 }
110
111 @Override
112 public String mapDn(UserDetails domainObject) {
113 return null;
114 }
115
116 @Override
117 public UserDetails map(LdapEntry ldapEntry) {
118 return new User(
119 userName,
120 userName,
121 isAccountEnabled(ldapEntry),
122 isAccountNonExpired(ldapEntry),
123 isCredentialsNonExpired(ldapEntry),
124 isAccountNonLocked(ldapEntry),
125 getGrantedAuthorities(ldapEntry));
126 }
127
128 @Override
129 public void map(LdapEntry source, UserDetails destination) {
130 throw new UnsupportedOperationException("User details are unmodifiable.");
131 }
132
133 @Override
134 public AttributeModification[] mapAndComputeModifications(UserDetails source, LdapEntry destination) {
135 return new AttributeModification[0];
136 }
137
138
139
140
141
142
143
144 protected boolean isAccountEnabled(LdapEntry ldapEntry) {
145 return !StringUtils.hasText(getUserAccountControlAttributeName()) || isUserAccountEnabled(getAttributeValue(
146 ldapEntry, getUserAccountControlAttributeName(), getUserAccountControlValueTranscoder(), null));
147 }
148
149
150
151
152
153
154
155 protected boolean isAccountNonExpired(@SuppressWarnings("unused") LdapEntry ldapEntry) {
156 return true;
157 }
158
159
160
161
162
163
164
165 protected boolean isCredentialsNonExpired(@SuppressWarnings("unused") LdapEntry ldapEntry) {
166 return true;
167 }
168
169
170
171
172
173
174
175 protected boolean isAccountNonLocked(@SuppressWarnings("unused") LdapEntry ldapEntry) {
176 return true;
177 }
178
179
180
181
182
183
184
185 protected Collection<? extends GrantedAuthority> getGrantedAuthorities(LdapEntry ldapEntry) {
186 Set<GrantedAuthority> grantedAuthorities = getAuthorities().stream()
187 .map(value -> UserDetailsLdapMapper.prefixAuthority(getAuthorityPrefix(), value))
188 .map(SimpleGrantedAuthority::new)
189 .collect(Collectors.toSet());
190 if (StringUtils.hasText(getAuthorityAttributeName())) {
191 grantedAuthorities.addAll(
192 getAttributeValuesAsSet(ldapEntry, getAuthorityAttributeName(), getAuthorityTranscoder()));
193 }
194 return grantedAuthorities;
195 }
196
197
198
199
200
201
202
203
204 protected static String prefixAuthority(String prefix, String value) {
205 return StringUtils.hasText(prefix) && !value.startsWith(prefix) ? prefix + value : value;
206 }
207
208
209
210
211
212
213 @ToString
214 protected static class GrantedAuthorityValueTranscoder extends AbstractStringValueTranscoder<GrantedAuthority> {
215
216 @Getter(value = AccessLevel.PROTECTED)
217 private final boolean authorityDn;
218
219 @Getter(value = AccessLevel.PROTECTED)
220 private final Map<String, String> authorityMap;
221
222 @Getter(value = AccessLevel.PROTECTED)
223 private final String authorityPrefix;
224
225
226
227
228
229
230
231
232 public GrantedAuthorityValueTranscoder(
233 boolean authorityDn,
234 Map<String, String> authorityMap,
235 String authorityPrefix) {
236 this.authorityDn = authorityDn;
237 this.authorityMap = authorityMap != null ? authorityMap : Collections.emptyMap();
238 this.authorityPrefix = authorityPrefix;
239 }
240
241 @Override
242 public GrantedAuthority decodeStringValue(String value) {
243 String ldapValue = isAuthorityDn() ? LdaptiveEntryMapper.getRdn(value) : value;
244 String mappedValue = getAuthorityMap().getOrDefault(ldapValue, ldapValue);
245 String authorityValue = UserDetailsLdapMapper.prefixAuthority(getAuthorityPrefix(), mappedValue);
246 return new SimpleGrantedAuthority(authorityValue);
247 }
248
249 @Override
250 public String encodeStringValue(GrantedAuthority value) {
251 throw new UnsupportedOperationException("Getting ldap attribute value from granted authority is not supported.");
252 }
253
254 @Override
255 public Class<GrantedAuthority> getType() {
256 return GrantedAuthority.class;
257 }
258 }
259
260 }