diff --git a/appserver/admin/gf_template/src/main/resources/config/domain.xml b/appserver/admin/gf_template/src/main/resources/config/domain.xml index 467828bd330..a8aa51aedfb 100644 --- a/appserver/admin/gf_template/src/main/resources/config/domain.xml +++ b/appserver/admin/gf_template/src/main/resources/config/domain.xml @@ -144,7 +144,9 @@ - + + + @@ -370,7 +372,9 @@ - + + + diff --git a/appserver/admin/gf_template_web/src/main/resources/config/domain.xml b/appserver/admin/gf_template_web/src/main/resources/config/domain.xml index 4e659f97cc4..10b9180bee0 100644 --- a/appserver/admin/gf_template_web/src/main/resources/config/domain.xml +++ b/appserver/admin/gf_template_web/src/main/resources/config/domain.xml @@ -139,7 +139,9 @@ - + + + @@ -361,7 +363,9 @@ - + + + diff --git a/appserver/tests/payara-samples/samples/client-certificate-validator/pom.xml b/appserver/tests/payara-samples/samples/client-certificate-validator/pom.xml new file mode 100644 index 00000000000..36f7d8e0841 --- /dev/null +++ b/appserver/tests/payara-samples/samples/client-certificate-validator/pom.xml @@ -0,0 +1,61 @@ + + + + + fish.payara.samples + payara-samples-profiled-tests + 5.2021.8-SNAPSHOT + + 4.0.0 + + war + fish.payara.samples.client-certificate-validator + client-certificate-validator + Payara-Samples - Payara - Client Certificate Validator + + + 8 + 8 + + + \ No newline at end of file diff --git a/appserver/tests/payara-samples/samples/client-certificate-validator/src/main/java/fish/payara/samples/security/validation/HelloServlet.java b/appserver/tests/payara-samples/samples/client-certificate-validator/src/main/java/fish/payara/samples/security/validation/HelloServlet.java new file mode 100644 index 00000000000..de2dc9f5184 --- /dev/null +++ b/appserver/tests/payara-samples/samples/client-certificate-validator/src/main/java/fish/payara/samples/security/validation/HelloServlet.java @@ -0,0 +1,61 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 2021 Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package fish.payara.samples.security.validation; + +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * + * @author James Hillyard + */ + +@WebServlet(value = "/secure/hello") +public class HelloServlet extends HttpServlet { + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + resp.getOutputStream().print("Hello " + req.getRemoteUser()); + } +} diff --git a/appserver/tests/payara-samples/samples/client-certificate-validator/src/main/webapp/WEB-INF/beans.xml b/appserver/tests/payara-samples/samples/client-certificate-validator/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 00000000000..ec9d5950981 --- /dev/null +++ b/appserver/tests/payara-samples/samples/client-certificate-validator/src/main/webapp/WEB-INF/beans.xml @@ -0,0 +1,47 @@ + + + + + + diff --git a/appserver/tests/payara-samples/samples/client-certificate-validator/src/main/webapp/WEB-INF/web.xml b/appserver/tests/payara-samples/samples/client-certificate-validator/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..236dfc752aa --- /dev/null +++ b/appserver/tests/payara-samples/samples/client-certificate-validator/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,65 @@ + + + + + + CLIENT-CERT + certificate + + + + + + secureAccess + /secure/* + + + myRole + + + + + myRole + + \ No newline at end of file diff --git a/appserver/tests/payara-samples/samples/client-certificate-validator/src/test/java/fish/payara/samples/security/validation/ClientValidationTest.java b/appserver/tests/payara-samples/samples/client-certificate-validator/src/test/java/fish/payara/samples/security/validation/ClientValidationTest.java new file mode 100644 index 00000000000..0b25607ac95 --- /dev/null +++ b/appserver/tests/payara-samples/samples/client-certificate-validator/src/test/java/fish/payara/samples/security/validation/ClientValidationTest.java @@ -0,0 +1,159 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 2021 Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package fish.payara.samples.security.validation; + +import fish.payara.samples.PayaraArquillianTestRunner; +import fish.payara.samples.SecurityUtils; +import fish.payara.samples.ServerOperations; +import fish.payara.samples.SincePayara; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.InSequence; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.omnifaces.utils.security.Certificates; + +import javax.net.ssl.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.*; +import java.security.cert.CertificateException; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * + * @author James Hillyard + */ + +@RunWith(PayaraArquillianTestRunner.class) +@SincePayara("5.2021.8") +public class ClientValidationTest { + + private static String certPath; + + private static final String CERTIFICATE_ALIAS = "omnikey"; + private static final String LOCALHOST_URL = "https://localhost:8181/security/secure/hello"; + + @Deployment + public static WebArchive deploy() { + return ShrinkWrap.create(WebArchive.class, "security.war") + .addPackage(ClientValidationTest.class.getPackage()) + .addPackages(true, "org.bouncycastle") + .addPackages(true, "com.gargoylesoftware") + .addPackages(true, "net.sourceforge.htmlunit") + .addPackages(true, "org.eclipse") + .addPackages(true, PayaraArquillianTestRunner.class.getPackage()) + .addClasses(ServerOperations.class, SecurityUtils.class, Certificates.class) + .addAsWebInfResource(new File("src/main/webapp", "WEB-INF/web.xml")) + .addAsWebInfResource(new File("src/main/webapp", "WEB-INF/beans.xml")); + } + + @Test + @InSequence(1) + public void generateCertsInTrustStore() throws IOException { + if (ServerOperations.isServer()) { + certPath = ServerOperations.generateClientKeyStore(true, true, CERTIFICATE_ALIAS); + } + } + + @Test + @InSequence(2) + public void validationFailTest() throws Exception { + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + SSLSocketFactory sslSocketFactory = getSslSocketFactory(certPath, kmf, CERTIFICATE_ALIAS); + assertEquals(401, callEndpoint(sslSocketFactory)); + assertTrue(checkForAPIValidationFailure()); + + } + + private static int callEndpoint(SSLSocketFactory sslSocketFactory) throws IOException { + URL url = new URL(LOCALHOST_URL); + HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); + connection.setSSLSocketFactory(sslSocketFactory); + return connection.getResponseCode(); + } + + private static SSLSocketFactory getSslSocketFactory(String certPath, KeyManagerFactory kmf, String alias) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException { + String keystorePassword = "changeit"; + + KeyStore keyStore = KeyStore.getInstance("JKS"); + keyStore.load(new FileInputStream(certPath), keystorePassword.toCharArray()); + kmf.init(keyStore, keystorePassword.toCharArray()); + + KeyManager[] keyManagers = kmf.getKeyManagers(); + + SSLContext ctx = SSLContext.getInstance("TLS"); + ctx.init(new KeyManager[]{new MyKeyManager((X509ExtendedKeyManager) keyManagers[0], alias)}, null, null); + return ctx.getSocketFactory(); + } + + /** + * @return true if the correct warning is found in the logs + * @throws IOException + */ + public boolean checkForAPIValidationFailure() throws IOException { + List log = viewLog(); + for (String line : log) { + if (line.contains("Certificate Validation Failed via API")) { + return true; + } + } + return false; + } + + /** + * @return the contents of the server log + */ + private List viewLog() throws IOException { + Path serverLog = ServerOperations.getDomainPath("logs/server.log"); + return Files.readAllLines(serverLog); + } + + +} diff --git a/appserver/tests/payara-samples/samples/client-certificate-validator/src/test/java/fish/payara/samples/security/validation/MyKeyManager.java b/appserver/tests/payara-samples/samples/client-certificate-validator/src/test/java/fish/payara/samples/security/validation/MyKeyManager.java new file mode 100644 index 00000000000..3ab79346abe --- /dev/null +++ b/appserver/tests/payara-samples/samples/client-certificate-validator/src/test/java/fish/payara/samples/security/validation/MyKeyManager.java @@ -0,0 +1,90 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 2021 Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package fish.payara.samples.security.validation; + + +import javax.net.ssl.X509ExtendedKeyManager; +import java.net.Socket; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; + +public class MyKeyManager extends X509ExtendedKeyManager { + + private final X509ExtendedKeyManager wrapped; + + private final String certAlias; + + public MyKeyManager(X509ExtendedKeyManager wrapped, String certAlias) { + this.wrapped = wrapped; + this.certAlias = certAlias; + } + + @Override + public String[] getClientAliases(String s, Principal[] principals) { + return wrapped.getClientAliases(s, principals); + } + + @Override + public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) { + return certAlias; + } + + @Override + public String[] getServerAliases(String s, Principal[] principals) { + throw new UnsupportedOperationException(); + } + + @Override + public String chooseServerAlias(String s, Principal[] principals, Socket socket) { + throw new UnsupportedOperationException(); + } + + @Override + public X509Certificate[] getCertificateChain(String s) { + return wrapped.getCertificateChain(s); + } + + @Override + public PrivateKey getPrivateKey(String s) { + return wrapped.getPrivateKey(s); + } +} diff --git a/appserver/tests/payara-samples/samples/pom.xml b/appserver/tests/payara-samples/samples/pom.xml index 2b4cfb3da90..1183473325e 100644 --- a/appserver/tests/payara-samples/samples/pom.xml +++ b/appserver/tests/payara-samples/samples/pom.xml @@ -41,6 +41,7 @@ rolesallowed-unprotected-methods microprofile-rc-ft multiple-keystores + client-certificate-validator diff --git a/appserver/tests/payara-samples/test-utils/src/main/java/fish/payara/samples/SecurityUtils.java b/appserver/tests/payara-samples/test-utils/src/main/java/fish/payara/samples/SecurityUtils.java index bf327dc8f2f..ce91db17f90 100644 --- a/appserver/tests/payara-samples/test-utils/src/main/java/fish/payara/samples/SecurityUtils.java +++ b/appserver/tests/payara-samples/test-utils/src/main/java/fish/payara/samples/SecurityUtils.java @@ -41,8 +41,7 @@ package fish.payara.samples; import java.net.MalformedURLException; import java.net.URL; -import java.security.KeyPair; -import java.security.PrivateKey; +import java.security.*; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Date; @@ -57,8 +56,6 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.omnifaces.utils.security.Certificates; import static java.math.BigInteger.ONE; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; import static java.time.Instant.now; import static java.time.temporal.ChronoUnit.DAYS; @@ -92,6 +89,27 @@ public static X509Certificate createSelfSignedCertificate(KeyPair keys) { } } + public static X509Certificate createExpiredSelfSignedCertificate(KeyPair keys) { + try { + return new JcaX509CertificateConverter() + .setProvider(PROVIDER) + .getCertificate( + new X509v3CertificateBuilder( + new X500Name("CN=lfoo, OU=bar, O=kaz, L=zak, ST=lak, C=UK"), + ONE, + Date.from(now().minus(2, DAYS)), + Date.from(now().minus(1, DAYS)), + new X500Name("CN=lfoo, OU=bar, O=kaz, L=zak, ST=lak, C=UK"), + SubjectPublicKeyInfo.getInstance(keys.getPublic().getEncoded())) + .build( + new JcaContentSignerBuilder("SHA256WithRSA") + .setProvider(PROVIDER) + .build(keys.getPrivate()))); + } catch (CertificateException | OperatorCreationException e) { + throw new IllegalStateException(e); + } + } + static URL getHostFromCertificate(X509Certificate[] serverCertificateChain, URL existingURL) { try { URL httpsUrl = new URL( diff --git a/appserver/tests/payara-samples/test-utils/src/main/java/fish/payara/samples/ServerOperations.java b/appserver/tests/payara-samples/test-utils/src/main/java/fish/payara/samples/ServerOperations.java index b1e0403a430..ecfa5366bb8 100644 --- a/appserver/tests/payara-samples/test-utils/src/main/java/fish/payara/samples/ServerOperations.java +++ b/appserver/tests/payara-samples/test-utils/src/main/java/fish/payara/samples/ServerOperations.java @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright (c) 2020 Payara Foundation and/or its affiliates. All rights reserved. + * Copyright (c) 2020-2021 Payara Foundation and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development @@ -95,6 +95,7 @@ public class ServerOperations { = "Check 'payara.containerType' system property configuration"; private static final String CLIENT_CERTIFICATE_FILE = "payara-test-client.crt"; private static final String CLIENT_CERTIFICATE_PATH = "certificates"; + private static final String DEFAULT_ALIAS = "arquillianClientTestCert"; public enum ServerType { SERVER, MICRO @@ -212,6 +213,10 @@ public static Path getDomainPath(String relativePathInDomain) { } static void addCertificateToContainerTrustStore(Certificate clientCertificate, KeyPair clientKeyPair) throws IOException { + addCertificateToContainerTrustStore(clientCertificate, clientKeyPair, DEFAULT_ALIAS); + } + + static void addCertificateToContainerTrustStore(Certificate clientCertificate, KeyPair clientKeyPair, String alias) throws IOException { if (runtimeType != RuntimeType.SERVER) { throw new IllegalStateException(ERR_MESSAGE_UNSUPPORTED); } @@ -224,12 +229,12 @@ static void addCertificateToContainerTrustStore(Certificate clientCertificate, K logger.info("*** Adding certificate to container trust store: " + cacertsPath.toAbsolutePath()); - KeyStore keyStore = null; + KeyStore keyStore; try (InputStream in = new FileInputStream(cacertsPath.toAbsolutePath().toFile())) { keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(in, "changeit".toCharArray()); - keyStore.setCertificateEntry("arquillianClientTestCert", clientCertificate); + keyStore.setCertificateEntry(alias, clientCertificate); keyStore.store(new FileOutputStream(cacertsPath.toAbsolutePath().toFile()), "changeit".toCharArray()); } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) { @@ -431,12 +436,31 @@ public static String createClientKeyStore() throws IOException { } public static String generateClientKeyStore(boolean addToContainer) throws IOException { + return generateClientKeyStore(addToContainer, false, DEFAULT_ALIAS); + } + + /** + * + * @param addToContainer Adds the client certificate to the truststore + * @param expired if true will create an expired SSL certificate + * @param alias the alias of the keystore, useful to not cause conflict with the cert of another payara-sample + * @return path to the new keystore created + * @throws IOException + */ + public static String generateClientKeyStore(boolean addToContainer, boolean expired, String alias) throws IOException { // ### Generate keys for the client, create a certificate, and add those to a new local key store // Generate a Private/Public key pair for the client KeyPair clientKeyPair = SecurityUtils.generateRandomRSAKeys(); // Create a certificate containing the client public key and signed with the private key - X509Certificate clientCertificate = SecurityUtils.createSelfSignedCertificate(clientKeyPair); + X509Certificate clientCertificate; + if(expired) { + clientCertificate = SecurityUtils.createExpiredSelfSignedCertificate(clientKeyPair); + } + else { + clientCertificate = SecurityUtils.createSelfSignedCertificate(clientKeyPair); + } + if (addToContainer) { if (runtimeType != RuntimeType.SERVER) { @@ -446,7 +470,7 @@ public static String generateClientKeyStore(boolean addToContainer) throws IOExc // Add the client certificate that we just generated to the trust store of the server. // That way the server will trust our certificate. // Set the actual domain used with -Dpayara.domain.name=[domain name] - addCertificateToContainerTrustStore(clientCertificate, clientKeyPair); + addCertificateToContainerTrustStore(clientCertificate, clientKeyPair, alias); } // Create a new local key store containing the client private key and the certificate diff --git a/nucleus/security/core/src/main/java/com/sun/enterprise/security/auth/realm/certificate/CertificateRealm.java b/nucleus/security/core/src/main/java/com/sun/enterprise/security/auth/realm/certificate/CertificateRealm.java index adea359cad7..3acef296db7 100644 --- a/nucleus/security/core/src/main/java/com/sun/enterprise/security/auth/realm/certificate/CertificateRealm.java +++ b/nucleus/security/core/src/main/java/com/sun/enterprise/security/auth/realm/certificate/CertificateRealm.java @@ -100,6 +100,7 @@ public final class CertificateRealm extends BaseRealm { private static final String COMMON_NAME_AS_PRINCIPAL_NAME = "common-name-as-principal-name"; private static final String DN_PARTS_USED_FOR_GROUPS = "dn-parts-used-for-groups"; + private static final String VALIDATION_CHECK_PROP = "certificate-validation"; /** Descriptive string of the authentication type of this realm. */ public static final String AUTH_TYPE = "certificate"; @@ -114,6 +115,9 @@ public final class CertificateRealm extends BaseRealm { protected void init(Properties props) throws BadRealmException, NoSuchRealmException { super.init(props); + final String validationCheck = props.getProperty(VALIDATION_CHECK_PROP); + setProperty(VALIDATION_CHECK_PROP, validationCheck); + final String jaasCtx = props.getProperty(JAAS_CONTEXT_PARAM); setProperty(JAAS_CONTEXT_PARAM, jaasCtx); @@ -199,16 +203,14 @@ private void validateSubjectViaAPI(Subject subject, X500Principal principal) { _logger.log(Level.WARNING, "Exception while loading certificate validation class", exc); clientCertificateValidatorMap.remove(Utility.getClassLoader()); } - + validators.add(new ClientCertificateExpiryValidator(getProperty(VALIDATION_CHECK_PROP))); boolean failed = false; - if (!validators.isEmpty()) { - for (ClientCertificateValidator validator : validators) { - if (!validator.isValid(subject, principal, certificate)) { - _logger.info(() -> String.format("Client Certificate validation failed for (subject=%s, principal=%s) by %s" - , subject, principal, validator.getClass().getName())); - failed = true; - break; - } + for (ClientCertificateValidator validator : validators) { + if (!validator.isValid(subject, principal, certificate)) { + _logger.info(() -> String.format("Client Certificate validation failed for (subject=%s, principal=%s) by %s" + , subject, principal, validator.getClass().getName())); + failed = true; + break; } } if (failed) { diff --git a/nucleus/security/core/src/main/java/com/sun/enterprise/security/auth/realm/certificate/ClientCertificateExpiryValidator.java b/nucleus/security/core/src/main/java/com/sun/enterprise/security/auth/realm/certificate/ClientCertificateExpiryValidator.java new file mode 100644 index 00000000000..e8ca3f78c82 --- /dev/null +++ b/nucleus/security/core/src/main/java/com/sun/enterprise/security/auth/realm/certificate/ClientCertificateExpiryValidator.java @@ -0,0 +1,71 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 2021 Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/master/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ + +package com.sun.enterprise.security.auth.realm.certificate; + +import fish.payara.security.client.ClientCertificateValidator; + +import javax.security.auth.Subject; +import javax.security.auth.x500.X500Principal; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.X509Certificate; + +public class ClientCertificateExpiryValidator implements ClientCertificateValidator { + private boolean validationCheck; + + public ClientCertificateExpiryValidator(String validationCheck) { + this.validationCheck = "true".equalsIgnoreCase(validationCheck); + } + + @Override + public boolean isValid(Subject subject, X500Principal principal, X509Certificate certificate) { + if (validationCheck) { + try { + certificate.checkValidity(); + } catch (CertificateExpiredException e) { + return false; + } catch (CertificateNotYetValidException e) { + return false; + } + } + return true; + } +}