Skip to content

Commit 3f70284

Browse files
committed
Add ValidationInfo and OcspValidationInfo in validation response and exception
1 parent 7dbf346 commit 3f70284

15 files changed

+317
-108
lines changed

example/src/main/java/eu/webeid/example/security/AuthTokenDTOAuthenticationProvider.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import eu.webeid.security.challenge.ChallengeNonceStore;
2828
import eu.webeid.security.exceptions.AuthTokenException;
2929
import eu.webeid.security.validator.AuthTokenValidator;
30+
import eu.webeid.security.validator.ValidationInfo;
3031
import org.slf4j.Logger;
3132
import org.slf4j.LoggerFactory;
3233
import org.springframework.security.authentication.AuthenticationProvider;
@@ -72,7 +73,8 @@ public Authentication authenticate(Authentication auth) throws AuthenticationExc
7273

7374
try {
7475
final String nonce = challengeNonceStore.getAndRemove().getBase64EncodedNonce();
75-
final X509Certificate userCertificate = tokenValidator.validate(authToken, nonce);
76+
final ValidationInfo validationInfo = tokenValidator.validate(authToken, nonce);
77+
final X509Certificate userCertificate = validationInfo.getSubjectCertificate();
7678
return WebEidAuthentication.fromCertificate(userCertificate, authorities);
7779
} catch (AuthTokenException e) {
7880
throw new AuthenticationServiceException("Web eID token validation failed", e);

src/main/java/eu/webeid/security/exceptions/UserCertificateOCSPCheckFailedException.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,33 @@
2222

2323
package eu.webeid.security.exceptions;
2424

25+
import eu.webeid.security.validator.ocsp.OcspValidationInfo;
26+
2527
/**
2628
* Thrown when user certificate revocation check with OCSP fails.
2729
*/
2830
public class UserCertificateOCSPCheckFailedException extends AuthTokenException {
31+
private final OcspValidationInfo ocspValidationInfo;
32+
2933
public UserCertificateOCSPCheckFailedException(Throwable cause) {
30-
super("User certificate revocation check has failed", cause);
34+
this(cause, null);
3135
}
3236

3337
public UserCertificateOCSPCheckFailedException(String message) {
38+
this(message, null);
39+
}
40+
41+
public UserCertificateOCSPCheckFailedException(Throwable cause, OcspValidationInfo ocspValidationInfo) {
42+
super("User certificate revocation check has failed", cause);
43+
this.ocspValidationInfo = ocspValidationInfo;
44+
}
45+
46+
public UserCertificateOCSPCheckFailedException(String message, OcspValidationInfo ocspValidationInfo) {
3447
super("User certificate revocation check has failed: " + message);
48+
this.ocspValidationInfo = ocspValidationInfo;
49+
}
50+
51+
public OcspValidationInfo getOcspValidationInfo() {
52+
return ocspValidationInfo;
3553
}
3654
}

src/main/java/eu/webeid/security/exceptions/UserCertificateRevokedException.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,25 @@
2222

2323
package eu.webeid.security.exceptions;
2424

25+
import eu.webeid.security.validator.ocsp.OcspValidationInfo;
26+
2527
/**
2628
* Thrown when the user certificate has been revoked.
2729
*/
2830
public class UserCertificateRevokedException extends AuthTokenException {
29-
public UserCertificateRevokedException() {
31+
private final OcspValidationInfo ocspValidationInfo;
32+
33+
public UserCertificateRevokedException(OcspValidationInfo ocspValidationInfo) {
3034
super("User certificate has been revoked");
35+
this.ocspValidationInfo = ocspValidationInfo;
3136
}
3237

33-
public UserCertificateRevokedException(String msg) {
38+
public UserCertificateRevokedException(String msg, OcspValidationInfo ocspValidationInfo) {
3439
super("User certificate has been revoked: " + msg);
40+
this.ocspValidationInfo = ocspValidationInfo;
41+
}
42+
43+
public OcspValidationInfo getOcspValidationInfo() {
44+
return ocspValidationInfo;
3545
}
3646
}

src/main/java/eu/webeid/security/exceptions/UserCertificateUnknownException.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,20 @@
2222

2323
package eu.webeid.security.exceptions;
2424

25+
import eu.webeid.security.validator.ocsp.OcspValidationInfo;
26+
2527
/**
2628
* Thrown when the user certificate has been revoked.
2729
*/
2830
public class UserCertificateUnknownException extends AuthTokenException {
31+
private final OcspValidationInfo ocspValidationInfo;
2932

30-
public UserCertificateUnknownException(String msg) {
33+
public UserCertificateUnknownException(String msg, OcspValidationInfo ocspValidationInfo) {
3134
super(msg);
35+
this.ocspValidationInfo = ocspValidationInfo;
36+
}
37+
38+
public OcspValidationInfo getOcspValidationInfo() {
39+
return ocspValidationInfo;
3240
}
3341
}

src/main/java/eu/webeid/security/validator/AuthTokenValidator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,6 @@ public interface AuthTokenValidator {
5757
* @return validated subject certificate
5858
* @throws AuthTokenException when validation fails
5959
*/
60-
X509Certificate validate(WebEidAuthToken authToken, String currentChallengeNonce) throws AuthTokenException;
60+
ValidationInfo validate(WebEidAuthToken authToken, String currentChallengeNonce) throws AuthTokenException;
6161

6262
}

src/main/java/eu/webeid/security/validator/AuthTokenValidatorImpl.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import eu.webeid.security.validator.certvalidators.SubjectCertificateValidatorBatch;
3838
import eu.webeid.security.validator.ocsp.OcspClient;
3939
import eu.webeid.security.validator.ocsp.OcspServiceProvider;
40+
import eu.webeid.security.validator.ocsp.OcspValidationInfo;
4041
import eu.webeid.security.validator.ocsp.ResilientOcspService;
4142
import eu.webeid.security.validator.ocsp.service.AiaOcspServiceConfiguration;
4243
import org.slf4j.Logger;
@@ -119,7 +120,7 @@ public WebEidAuthToken parse(String authToken) throws AuthTokenException {
119120
}
120121

121122
@Override
122-
public X509Certificate validate(WebEidAuthToken authToken, String currentChallengeNonce) throws AuthTokenException {
123+
public ValidationInfo validate(WebEidAuthToken authToken, String currentChallengeNonce) throws AuthTokenException {
123124
try {
124125
LOG.info("Starting token validation");
125126
return validateToken(authToken, currentChallengeNonce);
@@ -151,7 +152,7 @@ private WebEidAuthToken parseToken(String authToken) throws AuthTokenParseExcept
151152
}
152153
}
153154

154-
private X509Certificate validateToken(WebEidAuthToken token, String currentChallengeNonce) throws AuthTokenException {
155+
private ValidationInfo validateToken(WebEidAuthToken token, String currentChallengeNonce) throws AuthTokenException {
155156
if (token.getFormat() == null || !token.getFormat().startsWith(CURRENT_TOKEN_FORMAT_VERSION)) {
156157
throw new AuthTokenParseException("Only token format version '" + CURRENT_TOKEN_FORMAT_VERSION +
157158
"' is currently supported");
@@ -162,7 +163,7 @@ private X509Certificate validateToken(WebEidAuthToken token, String currentChall
162163
final X509Certificate subjectCertificate = CertificateLoader.decodeCertificateFromBase64(token.getUnverifiedCertificate());
163164

164165
simpleSubjectCertificateValidators.executeFor(subjectCertificate);
165-
getCertTrustValidators().executeFor(subjectCertificate);
166+
OcspValidationInfo ocspValidationInfo = validateCertificateTrust(subjectCertificate);
166167

167168
// It is guaranteed that if the signature verification succeeds, then the origin and challenge
168169
// have been implicitly and correctly verified without the need to implement any additional checks.
@@ -171,25 +172,23 @@ private X509Certificate validateToken(WebEidAuthToken token, String currentChall
171172
subjectCertificate.getPublicKey(),
172173
currentChallengeNonce);
173174

174-
return subjectCertificate;
175+
return new ValidationInfo(subjectCertificate, ocspValidationInfo);
175176
}
176177

177178
/**
178-
* Creates the certificate trust validators batch.
179+
* Validates the certificate trust and optionally the revocation status.
179180
* As SubjectCertificateTrustedValidator has mutable state that SubjectCertificateNotRevokedValidator depends on,
180181
* they cannot be reused/cached in an instance variable in a multi-threaded environment. Hence, they are
181182
* re-created for each validation run for thread safety.
182183
*
183-
* @return certificate trust validator batch
184+
* @return ocsp validation information if revocation check is performed, null otherwise
184185
*/
185-
private SubjectCertificateValidatorBatch getCertTrustValidators() {
186+
private OcspValidationInfo validateCertificateTrust(X509Certificate subjectCertificate) throws AuthTokenException {
186187
final SubjectCertificateTrustedValidator certTrustedValidator =
187188
new SubjectCertificateTrustedValidator(trustedCACertificateAnchors, trustedCACertificateCertStore);
188-
return SubjectCertificateValidatorBatch.createFrom(
189-
certTrustedValidator::validateCertificateTrusted
190-
).addOptional(configuration.isUserCertificateRevocationCheckWithOcspEnabled(),
191-
new SubjectCertificateNotRevokedValidator(resilientOcspService, certTrustedValidator)::validateCertificateNotRevoked
192-
);
189+
certTrustedValidator.validateCertificateTrusted(subjectCertificate);
190+
return configuration.isUserCertificateRevocationCheckWithOcspEnabled() ? new SubjectCertificateNotRevokedValidator(resilientOcspService, certTrustedValidator)
191+
.validateCertificateNotRevoked(subjectCertificate) : null;
193192
}
194193

195194
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (c) 2020-2025 Estonian Information System Authority
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all
12+
* copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
22+
23+
package eu.webeid.security.validator;
24+
25+
import eu.webeid.security.validator.ocsp.OcspValidationInfo;
26+
27+
import java.security.cert.X509Certificate;
28+
29+
public class ValidationInfo {
30+
private final X509Certificate subjectCertificate;
31+
private final OcspValidationInfo ocspValidationInfo;
32+
33+
public ValidationInfo(X509Certificate subjectCertificate, OcspValidationInfo ocspValidationInfo) {
34+
this.subjectCertificate = subjectCertificate;
35+
this.ocspValidationInfo = ocspValidationInfo;
36+
}
37+
38+
public X509Certificate getSubjectCertificate() {
39+
return subjectCertificate;
40+
}
41+
42+
public OcspValidationInfo getOcspValidationInfo() {
43+
return ocspValidationInfo;
44+
}
45+
}

src/main/java/eu/webeid/security/validator/certvalidators/SubjectCertificateNotRevokedValidator.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
package eu.webeid.security.validator.certvalidators;
2424

2525
import eu.webeid.security.exceptions.AuthTokenException;
26+
import eu.webeid.security.validator.ocsp.OcspValidationInfo;
2627
import eu.webeid.security.validator.ocsp.ResilientOcspService;
2728
import org.bouncycastle.jce.provider.BouncyCastleProvider;
2829

@@ -50,8 +51,8 @@ public SubjectCertificateNotRevokedValidator(ResilientOcspService resilientOcspS
5051
* @param subjectCertificate user certificate to be validated
5152
* @throws AuthTokenException when user certificate is revoked or revocation check fails.
5253
*/
53-
public void validateCertificateNotRevoked(X509Certificate subjectCertificate) throws AuthTokenException {
54+
public OcspValidationInfo validateCertificateNotRevoked(X509Certificate subjectCertificate) throws AuthTokenException {
5455
final X509Certificate issuerCertificate = Objects.requireNonNull(trustValidator.getSubjectCertificateIssuerCertificate());
55-
resilientOcspService.validateSubjectCertificateNotRevoked(subjectCertificate, issuerCertificate);
56+
return resilientOcspService.validateSubjectCertificateNotRevoked(subjectCertificate, issuerCertificate);
5657
}
5758
}

0 commit comments

Comments
 (0)