3636import io .github .resilience4j .circuitbreaker .CircuitBreakerConfig ;
3737import io .github .resilience4j .retry .RetryConfig ;
3838import org .bouncycastle .cert .ocsp .BasicOCSPResp ;
39+ import org .bouncycastle .cert .ocsp .CertificateStatus ;
3940import org .bouncycastle .cert .ocsp .OCSPResp ;
4041import org .bouncycastle .cert .ocsp .RevokedStatus ;
4142import org .bouncycastle .cert .ocsp .SingleResp ;
@@ -72,13 +73,16 @@ public class ResilientOcspCertificateRevocationCheckerTest {
7273
7374 private X509Certificate estEid2018Cert ;
7475 private X509Certificate testEsteid2018CA ;
76+
7577 private OCSPResp ocspRespGood ;
78+ private OCSPResp ocspRespRevoked ;
7679
7780 @ BeforeEach
7881 void setUp () throws Exception {
7982 estEid2018Cert = getJaakKristjanEsteid2018Cert ();
8083 testEsteid2018CA = getTestEsteid2018CA ();
8184 ocspRespGood = new OCSPResp (getOcspResponseBytesFromResources ("ocsp_response.der" ));
85+ ocspRespRevoked = new OCSPResp (getOcspResponseBytesFromResources ("ocsp_response_revoked.der" ));
8286 }
8387
8488 @ Test
@@ -133,8 +137,6 @@ void whenMultipleValidationCalls_thenPreviousResultsAreNotModified() throws Exce
133137
134138 @ Test
135139 void whenFirstFallbackReturnsRevoked_thenRevocationPropagatesWithoutSecondFallback () throws Exception {
136- OCSPResp ocspRespRevoked = new OCSPResp (getOcspResponseBytesFromResources ("ocsp_response_revoked.der" ));
137-
138140 OcspClient ocspClient = mock (OcspClient .class );
139141 when (ocspClient .request (eq (PRIMARY_URI ), any ()))
140142 .thenThrow (new OCSPClientException ("Primary OCSP service unavailable" ));
@@ -152,6 +154,25 @@ void whenFirstFallbackReturnsRevoked_thenRevocationPropagatesWithoutSecondFallba
152154 verify (ocspClient , never ()).request (eq (SECOND_FALLBACK_URI ), any ());
153155 }
154156
157+ @ Test
158+ void whenMaxAttemptsIsOneAndAllCallsFail_thenRevocationInfoListShouldHaveThreeElements () throws Exception {
159+ OcspClient ocspClient = mock (OcspClient .class );
160+ when (ocspClient .request (eq (PRIMARY_URI ), any ()))
161+ .thenThrow (new OCSPClientException ());
162+ when (ocspClient .request (eq (FALLBACK_URI ), any ()))
163+ .thenThrow (new OCSPClientException ());
164+ when (ocspClient .request (eq (SECOND_FALLBACK_URI ), any ()))
165+ .thenThrow (new OCSPClientException ());
166+
167+ RetryConfig retryConfig = RetryConfig .custom ()
168+ .maxAttempts (1 )
169+ .build ();
170+
171+ ResilientOcspCertificateRevocationChecker checker = buildChecker (ocspClient , retryConfig , false );
172+ ResilientUserCertificateOCSPCheckFailedException ex = assertThrows (ResilientUserCertificateOCSPCheckFailedException .class , () -> checker .validateCertificateNotRevoked (estEid2018Cert , testEsteid2018CA ));
173+ assertThat (ex .getValidationInfo ().revocationInfoList ().size ()).isEqualTo (3 );
174+ }
175+
155176 @ Test
156177 void whenMaxAttemptsIsTwoAndAllCallsFail_thenRevocationInfoListShouldHaveFourElements () throws Exception {
157178 OcspClient ocspClient = mock (OcspClient .class );
@@ -179,6 +200,10 @@ void whenMaxAttemptsIsTwoAndFirstCallFails_thenTwoCallsToPrimaryShouldBeRecorded
179200 when (ocspClient .request (eq (PRIMARY_URI ), any ()))
180201 .thenThrow (new OCSPClientException ("Primary OCSP service unavailable (call1)" ))
181202 .thenReturn (ocspRespGood );
203+ when (ocspClient .request (eq (FALLBACK_URI ), any ()))
204+ .thenReturn (ocspRespRevoked );
205+ when (ocspClient .request (eq (SECOND_FALLBACK_URI ), any ()))
206+ .thenReturn (ocspRespRevoked );
182207
183208 RetryConfig retryConfig = RetryConfig .custom ()
184209 .maxAttempts (2 )
@@ -206,36 +231,41 @@ void whenFirstCallSucceeds_thenRevocationInfoListShouldHaveOneElementAndItShould
206231 OcspClient ocspClient = mock (OcspClient .class );
207232 when (ocspClient .request (eq (PRIMARY_URI ), any ()))
208233 .thenReturn (ocspRespGood );
234+ when (ocspClient .request (eq (FALLBACK_URI ), any ()))
235+ .thenReturn (ocspRespRevoked );
236+ when (ocspClient .request (eq (SECOND_FALLBACK_URI ), any ()))
237+ .thenReturn (ocspRespRevoked );
209238
210239 ResilientOcspCertificateRevocationChecker checker = buildChecker (ocspClient , null , false );
211240
212241 List <RevocationInfo > revocationInfoList = checker .validateCertificateNotRevoked (estEid2018Cert , testEsteid2018CA );
213242 assertThat (revocationInfoList .size ()).isEqualTo (1 );
214243 Map <String , Object > responseAttributes = revocationInfoList .get (0 ).ocspResponseAttributes ();
215244 OCSPResp ocspResp = (OCSPResp ) responseAttributes .get ("OCSP_RESPONSE" );
216- final BasicOCSPResp basicResponse = (BasicOCSPResp ) ocspResp .getResponseObject ();
217- final SingleResp certStatusResponse = basicResponse .getResponses ()[0 ];
218- assertThat (certStatusResponse .getCertStatus ()).isEqualTo (org .bouncycastle .cert .ocsp .CertificateStatus .GOOD );
245+ CertificateStatus status = getCertificateStatus (ocspResp );
246+ assertThat (status ).isEqualTo (org .bouncycastle .cert .ocsp .CertificateStatus .GOOD );
219247 }
220248
221249 @ Test
222250 @ Disabled ("Primary supplier has allowThisUpdateInPast disabled and that is checked before revocation, " +
223251 "which results in ResilientUserCertificateOCSPCheckFailedException" )
224252 void whenFirstCallResultsInRevoked_thenRevocationInfoListShouldHaveOneElementAndItShouldHaveRevokedStatus () throws Exception {
225253 OcspClient ocspClient = mock (OcspClient .class );
226- OCSPResp ocspRespRevoked = new OCSPResp (getOcspResponseBytesFromResources ("ocsp_response_revoked.der" ));
227254 when (ocspClient .request (eq (PRIMARY_URI ), any ()))
228255 .thenReturn (ocspRespRevoked );
256+ when (ocspClient .request (eq (FALLBACK_URI ), any ()))
257+ .thenReturn (ocspRespGood );
258+ when (ocspClient .request (eq (SECOND_FALLBACK_URI ), any ()))
259+ .thenReturn (ocspRespGood );
229260
230261 ResilientOcspCertificateRevocationChecker checker = buildChecker (ocspClient , null , false );
231262 ResilientUserCertificateRevokedException ex = assertThrows (ResilientUserCertificateRevokedException .class , () -> checker .validateCertificateNotRevoked (estEid2018Cert , testEsteid2018CA ));
232263 List <RevocationInfo > revocationInfoList = ex .getValidationInfo ().revocationInfoList ();
233264 assertThat (revocationInfoList .size ()).isEqualTo (1 );
234265 Map <String , Object > responseAttributes = ex .getValidationInfo ().revocationInfoList ().get (0 ).ocspResponseAttributes ();
235266 OCSPResp ocspResp = (OCSPResp ) responseAttributes .get ("OCSP_RESPONSE" );
236- final BasicOCSPResp basicResponse = (BasicOCSPResp ) ocspResp .getResponseObject ();
237- final SingleResp certStatusResponse = basicResponse .getResponses ()[0 ];
238- assertThat (certStatusResponse .getCertStatus ()).isInstanceOf (RevokedStatus .class );
267+ CertificateStatus status = getCertificateStatus (ocspResp );
268+ assertThat (status ).isInstanceOf (RevokedStatus .class );
239269 }
240270
241271 private ResilientOcspCertificateRevocationChecker buildChecker (OcspClient ocspClient , RetryConfig retryConfig , boolean rejectUnknownOcspResponseStatus ) throws Exception {
@@ -266,4 +296,10 @@ private ResilientOcspCertificateRevocationChecker buildChecker(OcspClient ocspCl
266296 rejectUnknownOcspResponseStatus
267297 );
268298 }
299+
300+ private CertificateStatus getCertificateStatus (OCSPResp ocspResp ) throws Exception {
301+ final BasicOCSPResp basicResponse = (BasicOCSPResp ) ocspResp .getResponseObject ();
302+ final SingleResp certStatusResponse = basicResponse .getResponses ()[0 ];
303+ return certStatusResponse .getCertStatus ();
304+ }
269305}
0 commit comments