1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.bremersee.spring.security.oauth2.server.resource.authentication;
18
19 import static java.util.Objects.requireNonNullElseGet;
20 import static org.springframework.util.ObjectUtils.isEmpty;
21
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.util.List;
25 import java.util.Objects;
26 import java.util.Optional;
27 import java.util.Set;
28 import java.util.regex.Pattern;
29 import java.util.stream.Collectors;
30 import java.util.stream.Stream;
31 import lombok.AccessLevel;
32 import lombok.EqualsAndHashCode;
33 import lombok.Getter;
34 import lombok.ToString;
35 import org.bremersee.spring.security.core.NormalizedUser;
36 import org.springframework.core.convert.converter.Converter;
37 import org.springframework.lang.NonNull;
38 import org.springframework.security.authentication.AbstractAuthenticationToken;
39 import org.springframework.security.core.GrantedAuthority;
40 import org.springframework.security.core.authority.SimpleGrantedAuthority;
41 import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
42 import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
43 import org.springframework.security.oauth2.jwt.Jwt;
44
45
46
47
48
49
50 @Getter(AccessLevel.PROTECTED)
51 @ToString(callSuper = true)
52 @EqualsAndHashCode
53 public class JsonPathJwtConverter implements Converter<Jwt, AbstractAuthenticationToken> {
54
55
56
57
58 private final String nameJsonPath;
59
60
61
62
63 private final String firstNameJsonPath;
64
65
66
67
68 private final String lastNameJsonPath;
69
70
71
72
73 private final String emailJsonPath;
74
75
76
77
78 private final String rolesJsonPath;
79
80
81
82
83
84 private final boolean rolesValueList;
85
86
87
88
89 private final String rolesValueSeparator;
90
91
92
93
94 private final GrantedAuthoritiesMapper authoritiesMapper;
95
96
97
98
99
100
101
102
103
104
105
106
107
108 public JsonPathJwtConverter(
109 String nameJsonPath,
110 String firstNameJsonPath,
111 String lastNameJsonPath,
112 String emailJsonPath,
113 String rolesJsonPath,
114 boolean rolesValueList,
115 String rolesValueSeparator,
116 GrantedAuthoritiesMapper authoritiesMapper) {
117
118 this.nameJsonPath = nameJsonPath;
119 this.firstNameJsonPath = firstNameJsonPath;
120 this.lastNameJsonPath = lastNameJsonPath;
121 this.emailJsonPath = emailJsonPath;
122 this.rolesJsonPath = rolesJsonPath;
123 this.rolesValueList = rolesValueList;
124 this.rolesValueSeparator = rolesValueSeparator;
125 this.authoritiesMapper = requireNonNullElseGet(authoritiesMapper, SimpleAuthorityMapper::new);
126 }
127
128 @NonNull
129 @Override
130 public NormalizedJwtAuthenticationToken convert(@NonNull Jwt source) {
131 JsonPathJwtParser parser = new JsonPathJwtParser(source);
132 return new NormalizedJwtAuthenticationToken(
133 source,
134 new NormalizedUser(
135 getUsername(source, parser),
136 getFirstName(parser),
137 getLastName(parser),
138 getEmail(parser)),
139 getGrantedAuthorities(parser));
140 }
141
142
143
144
145
146
147
148 protected Collection<? extends GrantedAuthority> getGrantedAuthorities(JsonPathJwtParser parser) {
149 Stream<String> values = isRolesValueList()
150 ? getAuthoritiesFromList(parser)
151 : getAuthoritiesFromValue(parser);
152 Set<GrantedAuthority> authorities = values.map(SimpleGrantedAuthority::new)
153 .collect(Collectors.toSet());
154 return authoritiesMapper.mapAuthorities(authorities);
155 }
156
157
158
159
160
161
162
163 protected Stream<String> getAuthoritiesFromList(JsonPathJwtParser parser) {
164
165 return Stream.ofNullable(getRolesJsonPath())
166 .map(path -> parser.read(path, List.class))
167 .filter(Objects::nonNull)
168 .map(list -> (List<String>) list)
169 .flatMap(Collection::stream);
170 }
171
172
173
174
175
176
177
178 protected Stream<String> getAuthoritiesFromValue(JsonPathJwtParser parser) {
179 return Stream.ofNullable(getRolesJsonPath())
180 .filter(path -> !isEmpty(getRolesValueSeparator()))
181 .map(path -> parser.read(path, String.class))
182 .filter(Objects::nonNull)
183 .map(value -> value.split(Pattern.quote(getRolesValueSeparator())))
184 .flatMap(Arrays::stream)
185 .map(String::valueOf);
186 }
187
188
189
190
191
192
193
194
195 protected String getUsername(Jwt source, JsonPathJwtParser parser) {
196 return Optional.ofNullable(getNameJsonPath())
197 .filter(jsonPath -> !jsonPath.isBlank())
198 .map(jsonPath -> parser.read(jsonPath, String.class))
199 .orElseGet(source::getSubject);
200 }
201
202
203
204
205
206
207
208 protected String getFirstName(JsonPathJwtParser parser) {
209 return parser.read(getFirstNameJsonPath(), String.class);
210 }
211
212
213
214
215
216
217
218 protected String getLastName(JsonPathJwtParser parser) {
219 return parser.read(getLastNameJsonPath(), String.class);
220 }
221
222
223
224
225
226
227
228 protected String getEmail(JsonPathJwtParser parser) {
229 return parser.read(getEmailJsonPath(), String.class);
230 }
231
232 }