1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.opensaml.xml.security.x509;
18
19 import java.security.cert.X509Certificate;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Set;
23
24 import javax.security.auth.x500.X500Principal;
25
26 import org.opensaml.xml.security.SecurityException;
27 import org.opensaml.xml.util.DatatypeHelper;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 public class BasicX509CredentialNameEvaluator implements X509CredentialNameEvaluator {
60
61
62 private final Logger log = LoggerFactory.getLogger(BasicX509CredentialNameEvaluator.class);
63
64
65 private boolean checkSubjectAltNames;
66
67
68 private boolean checkSubjectDNCommonName;
69
70
71 private boolean checkSubjectDN;
72
73
74 private Set<Integer> subjectAltNameTypes;
75
76
77 private X500DNHandler x500DNHandler;
78
79
80 public BasicX509CredentialNameEvaluator() {
81
82 x500DNHandler = new InternalX500DNHandler();
83 subjectAltNameTypes = new HashSet<Integer>(5);
84
85
86 setCheckSubjectAltNames(true);
87 setCheckSubjectDNCommonName(true);
88 setCheckSubjectDN(true);
89 subjectAltNameTypes.add(X509Util.DNS_ALT_NAME);
90 subjectAltNameTypes.add(X509Util.URI_ALT_NAME);
91 }
92
93
94
95
96
97
98 public boolean isNameCheckingActive() {
99 return checkSubjectAltNames() || checkSubjectDNCommonName() || checkSubjectDN();
100 }
101
102
103
104
105
106
107
108
109
110 public Set<Integer> getSubjectAltNameTypes() {
111 return subjectAltNameTypes;
112 }
113
114
115
116
117
118
119
120
121 public boolean checkSubjectAltNames() {
122 return checkSubjectAltNames;
123 }
124
125
126
127
128
129
130
131
132 public void setCheckSubjectAltNames(boolean check) {
133 checkSubjectAltNames = check;
134 }
135
136
137
138
139
140
141
142
143 public boolean checkSubjectDNCommonName() {
144 return checkSubjectDNCommonName;
145 }
146
147
148
149
150
151
152
153
154 public void setCheckSubjectDNCommonName(boolean check) {
155 checkSubjectDNCommonName = check;
156 }
157
158
159
160
161
162
163
164 public boolean checkSubjectDN() {
165 return checkSubjectDN;
166 }
167
168
169
170
171
172
173
174
175 public void setCheckSubjectDN(boolean check) {
176 checkSubjectDN = check;
177 }
178
179
180
181
182
183
184
185
186 public X500DNHandler getX500DNHandler() {
187 return x500DNHandler;
188 }
189
190
191
192
193
194
195
196
197 public void setX500DNHandler(X500DNHandler handler) {
198 if (handler == null) {
199 throw new IllegalArgumentException("X500DNHandler may not be null");
200 }
201 x500DNHandler = handler;
202 }
203
204
205
206
207
208
209
210
211
212
213 @SuppressWarnings("unchecked")
214 public boolean evaluate(X509Credential credential, Set<String> trustedNames) throws SecurityException {
215 if (!isNameCheckingActive()) {
216 log.debug("No trusted name options are active, skipping name evaluation");
217 return true;
218 } else if (trustedNames == null || trustedNames.isEmpty()) {
219 log.debug("Supplied trusted names are null or empty, skipping name evaluation");
220 return true;
221 }
222
223 if (log.isDebugEnabled()) {
224 log.debug("Checking trusted names against credential: {}",
225 X509Util.getIdentifiersToken(credential, x500DNHandler));
226 log.debug("Trusted names being evaluated are: {}",
227 trustedNames.toString());
228 }
229 return processNameChecks(credential, trustedNames);
230 }
231
232
233
234
235
236
237
238
239 protected boolean processNameChecks(X509Credential credential, Set<String> trustedNames) {
240 X509Certificate entityCertificate = credential.getEntityCertificate();
241
242 if (checkSubjectAltNames()) {
243 if (processSubjectAltNames(entityCertificate, trustedNames)) {
244 if (log.isDebugEnabled()) {
245 log.debug("Credential {} passed name check based on subject alt names.",
246 X509Util.getIdentifiersToken(credential, x500DNHandler));
247 }
248 return true;
249 }
250 }
251
252 if (checkSubjectDNCommonName()) {
253 if (processSubjectDNCommonName(entityCertificate, trustedNames)) {
254 if (log.isDebugEnabled()) {
255 log.debug("Credential {} passed name check based on subject common name.",
256 X509Util.getIdentifiersToken(credential, x500DNHandler));
257 }
258 return true;
259 }
260 }
261
262 if (checkSubjectDN()) {
263 if (processSubjectDN(entityCertificate, trustedNames)) {
264 if (log.isDebugEnabled()) {
265 log.debug("Credential {} passed name check based on subject DN.",
266 X509Util.getIdentifiersToken(credential, x500DNHandler));
267 }
268 return true;
269 }
270 }
271
272 log.error("Credential failed name check: "
273 + X509Util.getIdentifiersToken(credential, x500DNHandler));
274 return false;
275 }
276
277
278
279
280
281
282
283
284
285
286 protected boolean processSubjectDNCommonName(X509Certificate certificate, Set<String> trustedNames) {
287 log.debug("Processing subject DN common name");
288 X500Principal subjectPrincipal = certificate.getSubjectX500Principal();
289 List<String> commonNames = X509Util.getCommonNames(subjectPrincipal);
290 if (commonNames == null || commonNames.isEmpty()) {
291 return false;
292 }
293
294
295 String commonName = commonNames.get(0);
296 log.debug("Extracted common name from certificate: {}", commonName);
297
298 if (DatatypeHelper.isEmpty(commonName)) {
299 return false;
300 }
301 if (trustedNames.contains(commonName)) {
302 log.debug("Matched subject DN common name to trusted names: {}", commonName);
303 return true;
304 } else {
305 return false;
306 }
307 }
308
309
310
311
312
313
314
315
316
317 protected boolean processSubjectDN(X509Certificate certificate, Set<String> trustedNames) {
318 log.debug("Processing subject DN");
319 X500Principal subjectPrincipal = certificate.getSubjectX500Principal();
320
321 if (log.isDebugEnabled()) {
322 log.debug("Extracted X500Principal from certificate: {}", x500DNHandler.getName(subjectPrincipal));
323 }
324 for (String trustedName : trustedNames) {
325 X500Principal trustedNamePrincipal = null;
326 try {
327 trustedNamePrincipal = x500DNHandler.parse(trustedName);
328 log.debug("Evaluating principal successfully parsed from trusted name: {}", trustedName);
329 if (subjectPrincipal.equals(trustedNamePrincipal)) {
330 if (log.isDebugEnabled()) {
331 log.debug("Matched subject DN to trusted names: {}", x500DNHandler.getName(subjectPrincipal));
332 }
333 return true;
334 }
335 } catch (IllegalArgumentException e) {
336
337
338
339 log.debug("Trusted name was not a DN or could not be parsed: {}", trustedName);
340 continue;
341 }
342 }
343 return false;
344 }
345
346
347
348
349
350
351
352
353
354 protected boolean processSubjectAltNames(X509Certificate certificate, Set<String> trustedNames) {
355 log.debug("Processing subject alt names");
356 Integer[] nameTypes = new Integer[subjectAltNameTypes.size()];
357 subjectAltNameTypes.toArray(nameTypes);
358 List altNames = X509Util.getAltNames(certificate, nameTypes);
359
360 log.debug("Extracted subject alt names from certificate: {}", altNames);
361
362 for (Object altName : altNames) {
363 if (trustedNames.contains(altName)) {
364 log.debug("Matched subject alt name to trusted names: {}", altName.toString());
365 return true;
366 }
367 }
368 return false;
369 }
370
371 }