-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathAuthTokenValidatorBuilder.java
More file actions
283 lines (260 loc) · 13.3 KB
/
AuthTokenValidatorBuilder.java
File metadata and controls
283 lines (260 loc) · 13.3 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
/*
* Copyright (c) 2020-2025 Estonian Information System Authority
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package eu.webeid.security.validator;
import eu.webeid.security.exceptions.JceException;
import eu.webeid.security.validator.ocsp.OcspClient;
import eu.webeid.security.validator.ocsp.OcspClientImpl;
import eu.webeid.security.validator.ocsp.service.DesignatedOcspServiceConfiguration;
import eu.webeid.security.validator.ocsp.service.FallbackOcspServiceConfiguration;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.core.IntervalFunction;
import io.github.resilience4j.retry.RetryConfig;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.util.Collections;
import java.util.stream.Collectors;
/**
* Builder for constructing {@link AuthTokenValidator} instances.
*/
public class AuthTokenValidatorBuilder {
private static final Logger LOG = LoggerFactory.getLogger(AuthTokenValidatorBuilder.class);
private final AuthTokenValidationConfiguration configuration = new AuthTokenValidationConfiguration();
private OcspClient ocspClient;
/**
* Sets the expected site origin, i.e. the domain that the application is running on.
* <p>
* Origin is a mandatory configuration parameter.
*
* @param origin origin URL as defined in <a href="https://developer.mozilla.org/en-US/docs/Web/API/Location/origin">MDN</a>,
* in the form of {@code <scheme> "://" <hostname> [ ":" <port> ]}
* @return the builder instance for method chaining
*/
public AuthTokenValidatorBuilder withSiteOrigin(URI origin) {
configuration.setSiteOrigin(origin);
LOG.debug("Origin set to {}", configuration.getSiteOrigin());
return this;
}
/**
* Adds the given certificates to the list of trusted intermediate Certificate Authorities
* used during validation of subject and OCSP responder certificates.
* In order for a user or OCSP responder certificate to be considered valid, the certificate
* of the issuer of the certificate must be present in this list.
* <p>
* At least one trusted intermediate Certificate Authority must be provided as a mandatory configuration parameter.
*
* @param certificates trusted intermediate Certificate Authority certificates
* @return the builder instance for method chaining
*/
public AuthTokenValidatorBuilder withTrustedCertificateAuthorities(X509Certificate... certificates) {
Collections.addAll(configuration.getTrustedCACertificates(), certificates);
if (LOG.isDebugEnabled()) {
LOG.debug("Trusted intermediate certificate authorities set to {}",
configuration.getTrustedCACertificates().stream()
.map(X509Certificate::getSubjectX500Principal)
.collect(Collectors.toList()));
}
return this;
}
/**
* Adds the given policies to the list of disallowed user certificate policies.
* In order for the user certificate to be considered valid, it must not contain any policies
* present in this list.
*
* @param policies disallowed user certificate policies
* @return the builder instance for method chaining
*/
public AuthTokenValidatorBuilder withDisallowedCertificatePolicies(ASN1ObjectIdentifier... policies) {
Collections.addAll(configuration.getDisallowedSubjectCertificatePolicies(), policies);
LOG.debug("Disallowed subject certificate policies set to {}", configuration.getDisallowedSubjectCertificatePolicies());
return this;
}
/**
* Turns off user certificate revocation check with OCSP.
* <p>
* <b>Turning off user certificate revocation check with OCSP is dangerous and should be
* used only in exceptional circumstances.</b>
* By default, the revocation check is turned on.
*
* @return the builder instance for method chaining.
*/
public AuthTokenValidatorBuilder withoutUserCertificateRevocationCheckWithOcsp() {
configuration.setUserCertificateRevocationCheckWithOcspDisabled();
LOG.warn("User certificate revocation check with OCSP is disabled, " +
"you should turn off the revocation check only in exceptional circumstances");
return this;
}
/**
* Sets both the connection and response timeout of user certificate revocation check OCSP requests.
* <p>
* This is an optional configuration parameter, the default is 5 seconds.
*
* @param ocspRequestTimeout the duration of OCSP request connection and response timeout
* @return the builder instance for method chaining.
*/
public AuthTokenValidatorBuilder withOcspRequestTimeout(Duration ocspRequestTimeout) {
configuration.setOcspRequestTimeout(ocspRequestTimeout);
LOG.debug("OCSP request timeout set to {}", ocspRequestTimeout);
return this;
}
/**
* Sets the allowed time skew for OCSP response's thisUpdate and nextUpdate times.
* This parameter is used to allow discrepancies between the system clock and the OCSP responder's clock,
* which may occur due to clock drift, network delays or revocation updates that are not published in real time.
* <p>
* This is an optional configuration parameter, the default is 15 minutes.
* The relatively long default is specifically chosen to account for one particular OCSP responder that used
* CRLs for authoritative revocation info, these CRLs were updated every 15 minutes.
*
* @param allowedTimeSkew the allowed time skew
* @return the builder instance for method chaining.
*/
public AuthTokenValidatorBuilder withAllowedOcspResponseTimeSkew(Duration allowedTimeSkew) {
configuration.setAllowedOcspResponseTimeSkew(allowedTimeSkew);
LOG.debug("Allowed OCSP response time skew set to {}", allowedTimeSkew);
return this;
}
/**
* Sets the maximum age of the OCSP response's thisUpdate time before it is considered too old.
* <p>
* This is an optional configuration parameter, the default is 2 minutes.
*
* @param maxThisUpdateAge the maximum age of the OCSP response's thisUpdate time
* @return the builder instance for method chaining.
*/
public AuthTokenValidatorBuilder withMaxOcspResponseThisUpdateAge(Duration maxThisUpdateAge) {
configuration.setMaxOcspResponseThisUpdateAge(maxThisUpdateAge);
LOG.debug("Maximum OCSP response thisUpdate age set to {}", maxThisUpdateAge);
return this;
}
/**
* Adds the given URLs to the list of OCSP URLs for which the nonce protocol extension will be disabled.
* The OCSP URL is extracted from the user certificate and some OCSP services don't support the nonce extension.
*
* @param urls OCSP URLs for which the nonce protocol extension will be disabled
* @return the builder instance for method chaining
*/
public AuthTokenValidatorBuilder withNonceDisabledOcspUrls(URI... urls) {
Collections.addAll(configuration.getNonceDisabledOcspUrls(), urls);
LOG.debug("OCSP URLs for which the nonce protocol extension is disabled set to {}", configuration.getNonceDisabledOcspUrls());
return this;
}
/**
* Activates the provided designated OCSP service for user certificate revocation check with OCSP.
* The designated service is only used for checking the status of the certificates whose issuers are
* supported by the service, falling back to the default OCSP service access location from
* the certificate's AIA extension if not.
*
* @param serviceConfiguration configuration of the designated OCSP service
* @return the builder instance for method chaining
*/
public AuthTokenValidatorBuilder withDesignatedOcspServiceConfiguration(DesignatedOcspServiceConfiguration serviceConfiguration) {
configuration.setDesignatedOcspServiceConfiguration(serviceConfiguration);
LOG.debug("Using designated OCSP service configuration");
return this;
}
/**
* // TODO: Describe the configuration option
*
* @param serviceConfiguration configurations of the fallback OCSP services
* @return the builder instance for method chaining
*/
public AuthTokenValidatorBuilder withFallbackOcspServiceConfiguration(FallbackOcspServiceConfiguration... serviceConfiguration) {
// TODO: Validate that no two configurations have the same OCSP service access location
Collections.addAll(configuration.getFallbackOcspServiceConfigurations(), serviceConfiguration);
LOG.debug("Fallback OCSP services set to {}", configuration.getFallbackOcspServiceConfigurations());
return this;
}
/**
* // TODO: Describe the configuration option
*
* @param slidingWindowSize
* @param minimumNumberOfCalls
* @param failureRateThreshold
* @param permittedNumberOfCallsInHalfOpenState
* @param waitDurationInOpenState
* @return the builder instance for method chaining
*/
public AuthTokenValidatorBuilder withCircuitBreakerConfig(int slidingWindowSize, int minimumNumberOfCalls, int failureRateThreshold, int permittedNumberOfCallsInHalfOpenState, Duration waitDurationInOpenState) { // TODO: What do we allow to configure? Use configuration builder.
configuration.setCircuitBreakerConfig(CircuitBreakerConfig.custom()
.slidingWindowSize(slidingWindowSize)
.minimumNumberOfCalls(minimumNumberOfCalls)
.failureRateThreshold(failureRateThreshold)
.permittedNumberOfCallsInHalfOpenState(permittedNumberOfCallsInHalfOpenState)
.waitIntervalFunctionInOpenState(IntervalFunction.of(waitDurationInOpenState))
.build());
LOG.debug("Using the OCSP circuit breaker configuration");
return this;
}
/**
* // TODO: Describe the configuration option
*
* @return the builder instance for method chaining
*/
public AuthTokenValidatorBuilder withCircuitBreakerRetryConfig() { // TODO: What do we allow to configure? Use configuration builder.
configuration.setCircuitBreakerRetryConfig(RetryConfig.ofDefaults());
LOG.debug("Using the OCSP circuit breaker retry configuration");
return this;
}
/**
* // TODO: Describe the configuration option
*
* @param rejectUnknownOcspResponseStatus configures whether only GOOD or REVOKED are accepted as valid OCSP response statuses
* @return the builder instance for method chaining
*/
public AuthTokenValidatorBuilder withRejectUnknownOcspResponseStatus(boolean rejectUnknownOcspResponseStatus) {
configuration.setRejectUnknownOcspResponseStatus(rejectUnknownOcspResponseStatus);
LOG.debug("Using the reject unknown OCSP response status validation configuration");
return this;
}
/**
* Uses the provided OCSP client instance during user certificate revocation check with OCSP.
* The provided client instance must be thread-safe.
*
* @param ocspClient OCSP client instance
* @return the builder instance for method chaining
*/
public AuthTokenValidatorBuilder withOcspClient(OcspClient ocspClient) {
this.ocspClient = ocspClient;
LOG.debug("Using the OCSP client provided by API consumer");
return this;
}
/**
* Validates the configuration and builds the {@link AuthTokenValidator} object with it.
* The returned {@link AuthTokenValidator} object is immutable/thread-safe.
*
* @return the configured authentication token validator object
* @throws NullPointerException when required parameters are null
* @throws IllegalArgumentException when any parameter is invalid
* @throws RuntimeException when JCE configuration is invalid
*/
public AuthTokenValidator build() throws NullPointerException, IllegalArgumentException, JceException {
configuration.validate();
if (configuration.isUserCertificateRevocationCheckWithOcspEnabled() && ocspClient == null) {
ocspClient = OcspClientImpl.build(configuration.getOcspRequestTimeout());
}
return new AuthTokenValidatorImpl(configuration, ocspClient);
}
}