-
Notifications
You must be signed in to change notification settings - Fork 99
Expand file tree
/
Copy pathValidatorUtils.java
More file actions
334 lines (304 loc) · 10.4 KB
/
ValidatorUtils.java
File metadata and controls
334 lines (304 loc) · 10.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
package com.coveo.saml;
import java.util.List;
import org.joda.time.DateTime;
import org.opensaml.saml.common.SignableSAMLObject;
import org.opensaml.saml.saml2.core.Assertion;
import org.opensaml.saml.saml2.core.Conditions;
import org.opensaml.saml.saml2.core.LogoutRequest;
import org.opensaml.saml.saml2.core.LogoutResponse;
import org.opensaml.saml.saml2.core.RequestAbstractType;
import org.opensaml.saml.saml2.core.Response;
import org.opensaml.saml.saml2.core.StatusCode;
import org.opensaml.saml.saml2.core.StatusResponseType;
import org.opensaml.security.credential.Credential;
import org.opensaml.xmlsec.signature.Signature;
import org.opensaml.xmlsec.signature.support.SignatureException;
import org.opensaml.xmlsec.signature.support.SignatureValidator;
/**
* The type Validator utils.
*/
class ValidatorUtils {
/**
* Validate response.
*
* @param response the response
* @param responseIssuer the response issuer
* @throws SamlException the saml exception
*/
private static void validateResponse(StatusResponseType response, String responseIssuer)
throws SamlException {
try {
new ResponseSchemaValidator().validate(response);
} catch (SamlException e) {
throw new SamlException("The response schema validation failed", e);
}
validateIssuer(response, responseIssuer);
}
/**
* Validate status.
*
* @param response the response
* @throws SamlException the saml exception
*/
private static void validateStatus(StatusResponseType response) throws SamlException {
String statusCode = response.getStatus().getStatusCode().getValue();
if (!StatusCode.SUCCESS.equals(statusCode)) {
throw new SamlException("Invalid status code: " + statusCode);
}
}
/**
* Validate issuer.
*
* @param response the response
* @param responseIssuer the response issuer
* @throws SamlException the saml exception
*/
private static void validateIssuer(StatusResponseType response, String responseIssuer)
throws SamlException {
if (!response.getIssuer().getValue().equals(responseIssuer)) {
throw new SamlException("The response issuer didn't match the expected value");
}
}
/**
* Validate issuer.
*
* @param request the response
* @param requestIssuer the request issuer
* @throws SamlException the saml exception
*/
private static void validateIssuer(RequestAbstractType request, String requestIssuer)
throws SamlException {
if (!request.getIssuer().getValue().equals(requestIssuer)) {
throw new SamlException("The request issuer didn't match the expected value");
}
}
/**
* Validate assertion.
*
* @param response the response
* @param responseIssuer the response issuer
* @param now the current date time (for unit test only)
* @param notBeforeSkew the notBeforeSkew
* @throws SamlException the saml exception
*/
private static void validateAssertion(
Response response, String responseIssuer, DateTime now, long notBeforeSkew)
throws SamlException {
if (response.getAssertions().size() != 1) {
throw new SamlException("The response doesn't contain exactly 1 assertion");
}
Assertion assertion = response.getAssertions().get(0);
if (!assertion.getIssuer().getValue().equals(responseIssuer)) {
throw new SamlException("The assertion issuer didn't match the expected value");
}
if (assertion.getSubject().getNameID() == null) {
throw new SamlException(
"The NameID value is missing from the SAML response; this is likely an IDP configuration issue");
}
enforceConditions(assertion.getConditions(), now, notBeforeSkew);
}
/**
* Enforce conditions.
*
* @param conditions the conditions
* @param _now the current date time (for unit test only)
* @param notBeforeSkew the notBeforeSkew
* @throws SamlException the saml exception
*/
private static void enforceConditions(Conditions conditions, DateTime _now, long notBeforeSkew)
throws SamlException {
DateTime now = _now != null ? _now : DateTime.now();
DateTime notBefore = conditions.getNotBefore();
DateTime skewedNotBefore = notBefore.minus(notBeforeSkew);
if (now.isBefore(skewedNotBefore)) {
throw new SamlException("The assertion cannot be used before " + notBefore.toString());
}
DateTime notOnOrAfter = conditions.getNotOnOrAfter();
if (now.isAfter(notOnOrAfter)) {
throw new SamlException("The assertion cannot be used after " + notOnOrAfter.toString());
}
}
/**
* Validate signature.
*
* @param response the response
* @param credentials the credentials
* @throws SamlException the saml exception
*/
private static void validateSignature(SignableSAMLObject response, List<Credential> credentials)
throws SamlException {
if (response.getSignature() != null && !validate(response.getSignature(), credentials)) {
throw new SamlException("The response signature is invalid");
}
}
/**
* Validate assertion signature.
*
* @param response the response
* @param credentials the credentials
* @throws SamlException the saml exception
*/
private static void validateAssertionSignature(Response response, List<Credential> credentials)
throws SamlException {
Signature assertionSignature = response.getAssertions().get(0).getSignature();
if (response.getSignature() == null && assertionSignature == null) {
throw new SamlException("No signature is present in either response or assertion");
}
if (assertionSignature != null && !validate(assertionSignature, credentials)) {
throw new SamlException("The assertion signature is invalid");
}
}
/**
* Validate boolean.
*
* @param signature the signature
* @param credentials the credentials
* @return the boolean
*/
private static boolean validate(Signature signature, List<Credential> credentials) {
if (signature == null) {
return false;
}
// It's fine if any of the credentials match the signature
return credentials
.stream()
.anyMatch(
credential -> {
try {
SignatureValidator.validate(signature, credential);
return true;
} catch (SignatureException ex) {
return false;
}
});
}
/**
* Validate.
*
* @param response the response
* @param responseIssuer the response issuer
* @param credentials the credentials
* @param now the current date time (for unit test only)
* @param notBeforeSkew the notBeforeSkew
* @throws SamlException the saml exception
*/
public static void validate(
Response response,
String responseIssuer,
List<Credential> credentials,
DateTime now,
long notBeforeSkew)
throws SamlException {
validateResponse(response, responseIssuer);
validateAssertion(response, responseIssuer, now, notBeforeSkew);
validateSignature(response, credentials);
validateAssertionSignature(response, credentials);
}
/**
* Validate.
*
* @param logoutRequest the response
* @param responseIssuer the response issuer
* @param credentials the credentials
* @throws SamlException the saml exception
*/
public static void validate(
LogoutRequest logoutRequest,
String responseIssuer,
List<Credential> credentials,
String nameID)
throws SamlException {
validateLogoutRequest(logoutRequest, responseIssuer, nameID);
validateSignature(logoutRequest, credentials);
}
/**
* Validate.
*
* @param logoutRequest the response
* @param responseIssuer the response issuer
* @param credentials the credentials
* @throws SamlException the saml exception
*/
public static void validate(
LogoutRequest logoutRequest, String responseIssuer, List<Credential> credentials)
throws SamlException {
validateLogoutRequest(logoutRequest, responseIssuer);
validateSignature(logoutRequest, credentials);
}
/**
* Validate.
*
* @param response the response
* @param responseIssuer the response issuer
* @param credentials the credentials
* @throws SamlException the saml exception
*/
public static void validate(
LogoutResponse response, String responseIssuer, List<Credential> credentials)
throws SamlException {
validateResponse(response, responseIssuer);
validateSignature(response, credentials);
}
/**
* Validate response.
*
* @param response the response
* @param responseIssuer the response issuer
* @throws SamlException the saml exception
*/
private static void validateResponse(Response response, String responseIssuer)
throws SamlException {
try {
new ResponseSchemaValidator().validate(response);
} catch (SamlException ex) {
throw new SamlException("The response schema validation failed", ex);
}
validateIssuer(response, responseIssuer);
validateStatus(response);
}
/**
* Validate response.
*
* @param request the request
* @param requestIssuer the response issuer
* @throws SamlException the saml exception
*/
private static void validateLogoutRequest(
LogoutRequest request, String requestIssuer, String nameID) throws SamlException {
try {
new LogoutRequestSchemaValidator().validate(request);
} catch (SamlException ex) {
throw new SamlException("The request schema validation failed", ex);
}
validateIssuer(request, requestIssuer);
validateNameId(request, nameID);
}
/**
* Validate response.
*
* @param request the request
* @param requestIssuer the response issuer
* @throws SamlException the saml exception
*/
private static void validateLogoutRequest(LogoutRequest request, String requestIssuer)
throws SamlException {
try {
new LogoutRequestSchemaValidator().validate(request);
} catch (SamlException ex) {
throw new SamlException("The request schema validation failed", ex);
}
validateIssuer(request, requestIssuer);
}
/**
* Validate the logout request name id.
*
* @param request the request
* @param nameID the name id
* @throws SamlException the saml exception
*/
private static void validateNameId(LogoutRequest request, String nameID) throws SamlException {
if (nameID == null || !nameID.equals(request.getNameID().getValue())) {
throw new SamlException("The nameID of the logout request is incorrect");
}
}
}