package org.apereo.cas.adaptors.x509.authentication.handler.support; import org.apereo.cas.adaptors.x509.authentication.ExpiredCRLException; import org.apereo.cas.adaptors.x509.authentication.revocation.policy.AllowRevocationPolicy; import org.apereo.cas.adaptors.x509.authentication.revocation.checker.CRLDistributionPointRevocationChecker; import org.apereo.cas.adaptors.x509.authentication.revocation.checker.RevocationChecker; import org.apereo.cas.adaptors.x509.authentication.revocation.RevokedCertificateException; import org.apereo.cas.adaptors.x509.authentication.revocation.policy.ThresholdExpiredCRLRevocationPolicy; import org.apereo.cas.adaptors.x509.util.MockWebServer; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import org.apache.commons.io.IOUtils; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.FileSystemResource; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; import java.math.BigInteger; import java.security.GeneralSecurityException; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Collection; /** * Unit test for {@link CRLDistributionPointRevocationChecker} class. * * @author Marvin S. Addison * @since 3.4.76 */ @RunWith(Parameterized.class) public class CRLDistributionPointRevocationCheckerTests extends AbstractCRLRevocationCheckerTests { private static final Logger LOGGER = LoggerFactory.getLogger(CRLDistributionPointRevocationCheckerTests.class); /** * Instance under test. */ private final CRLDistributionPointRevocationChecker checker; /** * Answers requests for CRLs made to localhost:8085. */ private final MockWebServer webServer; /** * Creates a new test instance with given parameters. * * @param checker Revocation checker instance. * @param certFiles File names of certificates to check. * @param crlFile File name of CRL file to serve out. * @param expected Expected result of check; null to indicate expected success. */ public CRLDistributionPointRevocationCheckerTests( final CRLDistributionPointRevocationChecker checker, final String[] certFiles, final String crlFile, final GeneralSecurityException expected) throws Exception { super(certFiles, expected); final File file = new File(System.getProperty("java.io.tmpdir"), "ca.crl"); if (file.exists()) { file.delete(); } final OutputStream out = new FileOutputStream(file); IOUtils.copy(new ClassPathResource(crlFile).getInputStream(), out); this.checker = checker; this.webServer = new MockWebServer(8085, new FileSystemResource(file), "text/plain"); LOGGER.debug("Web server listening on port 8085 serving file [{}]", crlFile); } /** * Gets the unit test parameters. * * @return Test parameter data. */ @Parameters public static Collection<Object[]> getTestParameters() throws Exception { CacheManager.getInstance().removeAllCaches(); final Collection<Object[]> params = new ArrayList<>(); Cache cache; final ThresholdExpiredCRLRevocationPolicy defaultPolicy = new ThresholdExpiredCRLRevocationPolicy(0); final ThresholdExpiredCRLRevocationPolicy zeroThresholdPolicy = new ThresholdExpiredCRLRevocationPolicy(0); // Test case #0 // Valid certificate on valid CRL data with encoded url cache = new Cache("crlCache-0", 100, false, false, 20, 10); CacheManager.getInstance().addCache(cache); params.add(new Object[]{ new CRLDistributionPointRevocationChecker(cache, defaultPolicy, null), new String[]{"uservalid-encoded-crl.crt"}, "test ca.crl", null, }); // Test case #1 // Valid certificate on valid CRL data cache = new Cache("crlCache-1", 100, false, false, 20, 10); CacheManager.getInstance().addCache(cache); params.add(new Object[]{ new CRLDistributionPointRevocationChecker(cache, defaultPolicy, null, true), new String[]{"user-valid-distcrl.crt"}, "userCA-valid.crl", null, }); // Test case #2 // Revoked certificate on valid CRL data cache = new Cache("crlCache-2", 100, false, false, 20, 10); CacheManager.getInstance().addCache(cache); params.add(new Object[]{ new CRLDistributionPointRevocationChecker(cache, defaultPolicy, null), new String[]{"user-revoked-distcrl.crt"}, "userCA-valid.crl", new RevokedCertificateException(ZonedDateTime.now(ZoneOffset.UTC), new BigInteger("1")), }); // Test case #3 // Valid certificate on expired CRL data cache = new Cache("crlCache-3", 100, false, false, 20, 10); CacheManager.getInstance().addCache(cache); params.add(new Object[]{ new CRLDistributionPointRevocationChecker(cache, zeroThresholdPolicy, null), new String[]{"user-valid-distcrl.crt"}, "userCA-expired.crl", new ExpiredCRLException("test", ZonedDateTime.now(ZoneOffset.UTC)), }); // Test case #4 // Valid certificate on expired CRL data with custom expiration // policy to always allow expired CRL data cache = new Cache("crlCache-4", 100, false, false, 20, 10); CacheManager.getInstance().addCache(cache); params.add(new Object[]{ new CRLDistributionPointRevocationChecker(cache, crl -> { }, null), new String[]{"user-valid-distcrl.crt"}, "userCA-expired.crl", null, }); // Test case #5 // Valid certificate with no CRL distribution points defined but with // "AllowRevocationPolicy" set to allow unavailable CRL data cache = new Cache("crlCache-5", 100, false, false, 20, 10); CacheManager.getInstance().addCache(cache); final CRLDistributionPointRevocationChecker checker5 = new CRLDistributionPointRevocationChecker(cache, defaultPolicy, new AllowRevocationPolicy()); params.add(new Object[]{ checker5, new String[]{"user-valid.crt"}, "userCA-expired.crl", null, }); // Test case #6 // EJBCA test case // Revoked certificate with CRL distribution point URI that is technically // not a valid URI since the issuer DN in the query string is not encoded per // the escaping of reserved characters in RFC 2396. // Make sure we can convert given URI to valid URI and confirm it's revoked cache = new Cache("crlCache-6", 100, false, false, 20, 10); CacheManager.getInstance().addCache(cache); params.add(new Object[]{ new CRLDistributionPointRevocationChecker(cache, defaultPolicy, null), new String[]{"user-revoked-distcrl2.crt"}, "userCA-valid.crl", new RevokedCertificateException(ZonedDateTime.now(ZoneOffset.UTC), new BigInteger("1")), }); return params; } /** * Called once before every test. * * @throws Exception On setup errors. */ @Before public void setUp() throws Exception { this.webServer.start(); Thread.sleep(500); } /** * Called once before every test. * * @throws Exception On setup errors. */ @After public void tearDown() throws Exception { LOGGER.debug("Stopping web server..."); this.webServer.stop(); Thread.sleep(500); LOGGER.debug("Web server stopped [{}]", !this.webServer.isRunning()); } @AfterClass public static void destroy() { final File file = new File("ca.crl"); if (file.exists()) { file.delete(); } } @Override protected RevocationChecker getChecker() { return this.checker; } }