This is an automated email from the ASF dual-hosted git repository.

cris pushed a commit to branch SLING-10193/test-coverage
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git


The following commit(s) were added to refs/heads/SLING-10193/test-coverage by 
this push:
     new f4449bf  Added setup for Java Keystore tests, added tests for 
JksCredentials, KeyPairCredentials and VerifySignatureCredentials
f4449bf is described below

commit f4449bfa1571bd555602fcba67caa6493636ca19
Author: Cris Rockwell, College of LSA University of Michigan 
<[email protected]>
AuthorDate: Tue Mar 23 14:17:38 2021 -0400

    Added setup for Java Keystore tests, added tests for JksCredentials, 
KeyPairCredentials and VerifySignatureCredentials
---
 .../saml2/impl/AuthenticationHandlerSAML2Impl.java |   4 +-
 .../sling/auth/saml2/sp/Saml2LoginModule.java      |   2 +-
 .../org/apache/sling/auth/saml2/SamlHandlerIT.java |  10 +-
 .../apache/sling/auth/saml2/impl/JKSHelper.java    | 137 +++++++++++++++++++++
 .../apache/sling/auth/saml2/impl/OsgiSamlTest.java |  87 ++++++++++++-
 5 files changed, 228 insertions(+), 12 deletions(-)

diff --git 
a/saml-handler/src/main/java/org/apache/sling/auth/saml2/impl/AuthenticationHandlerSAML2Impl.java
 
b/saml-handler/src/main/java/org/apache/sling/auth/saml2/impl/AuthenticationHandlerSAML2Impl.java
index 5be41e0..ae3cd0d 100644
--- 
a/saml-handler/src/main/java/org/apache/sling/auth/saml2/impl/AuthenticationHandlerSAML2Impl.java
+++ 
b/saml-handler/src/main/java/org/apache/sling/auth/saml2/impl/AuthenticationHandlerSAML2Impl.java
@@ -433,8 +433,8 @@ public class AuthenticationHandlerSAML2Impl extends 
AbstractSamlHandler implemen
 
     User doUserManagement(final Assertion assertion) {
         if (assertion == null ||
-                assertion.getAttributeStatements().size() == 0 ||
-                
assertion.getAttributeStatements().get(0).getAttributes().size() == 0) {
+                assertion.getAttributeStatements().isEmpty() ||
+                
assertion.getAttributeStatements().get(0).getAttributes().isEmpty()) {
             logger.warn("SAML Assertion Attribute Statement or Attributes was 
null ");
             return null;
         }
diff --git 
a/saml-handler/src/main/java/org/apache/sling/auth/saml2/sp/Saml2LoginModule.java
 
b/saml-handler/src/main/java/org/apache/sling/auth/saml2/sp/Saml2LoginModule.java
index 2eca683..f7f7e92 100644
--- 
a/saml-handler/src/main/java/org/apache/sling/auth/saml2/sp/Saml2LoginModule.java
+++ 
b/saml-handler/src/main/java/org/apache/sling/auth/saml2/sp/Saml2LoginModule.java
@@ -43,7 +43,7 @@ import java.util.Set;
 
 public class Saml2LoginModule extends AbstractLoginModule {
 
-    static Set<Class> SUPPORTED_CREDENTIALS = new HashSet<Class>();
+    static Set<Class> SUPPORTED_CREDENTIALS = new HashSet<>();
     private final Logger logger = 
LoggerFactory.getLogger(Saml2LoginModule.class);
 
     static {
diff --git 
a/saml-handler/src/test/java/org/apache/sling/auth/saml2/SamlHandlerIT.java 
b/saml-handler/src/test/java/org/apache/sling/auth/saml2/SamlHandlerIT.java
index 3683a07..165ec8d 100644
--- a/saml-handler/src/test/java/org/apache/sling/auth/saml2/SamlHandlerIT.java
+++ b/saml-handler/src/test/java/org/apache/sling/auth/saml2/SamlHandlerIT.java
@@ -18,6 +18,7 @@
  */
 
 package org.apache.sling.auth.saml2;
+
 import org.apache.commons.lang3.StringUtils;
 import org.apache.jackrabbit.api.JackrabbitSession;
 import org.apache.jackrabbit.api.security.user.Authorizable;
@@ -29,7 +30,6 @@ import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceResolverFactory;
 import org.apache.sling.auth.core.AuthenticationSupport;
 import org.apache.sling.auth.core.spi.AuthenticationHandler;
-import org.apache.sling.auth.saml2.impl.AuthenticationHandlerSAML2Impl;
 import org.apache.sling.testing.paxexam.SlingOptions;
 import org.apache.sling.testing.paxexam.TestSupport;
 import org.junit.After;
@@ -41,9 +41,6 @@ import org.ops4j.pax.exam.Option;
 import org.ops4j.pax.exam.junit.PaxExam;
 import org.ops4j.pax.exam.options.ModifiableCompositeOption;
 import org.ops4j.pax.exam.options.extra.VMOption;
-import javax.inject.Inject;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
 import org.ops4j.pax.exam.spi.reactors.PerClass;
 import org.ops4j.pax.exam.util.Filter;
@@ -53,13 +50,16 @@ import org.osgi.service.cm.ConfigurationAdmin;
 import org.osgi.service.http.HttpService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
 import java.util.Arrays;
 
 import static org.apache.sling.testing.paxexam.SlingOptions.logback;
 import static org.apache.sling.testing.paxexam.SlingOptions.slingAuthForm;
 import static 
org.apache.sling.testing.paxexam.SlingOptions.slingQuickstartOakTar;
 import static org.apache.sling.testing.paxexam.SlingOptions.versionResolver;
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
diff --git 
a/saml-handler/src/test/java/org/apache/sling/auth/saml2/impl/JKSHelper.java 
b/saml-handler/src/test/java/org/apache/sling/auth/saml2/impl/JKSHelper.java
new file mode 100644
index 0000000..905f71a
--- /dev/null
+++ b/saml-handler/src/test/java/org/apache/sling/auth/saml2/impl/JKSHelper.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.sling.auth.saml2.impl;
+
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.cert.CertIOException;
+import org.bouncycastle.cert.X509ExtensionUtils;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.DigestCalculator;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.bc.BcDigestCalculatorProvider;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+import static org.junit.Assert.fail;
+
+public class JKSHelper {
+    private static Logger logger = LoggerFactory.getLogger(JKSHelper.class);
+    static String KEYSTORE_TEST_PATH = "./target/exampleSaml2.jks";
+    static char[] KEYSTORE_TEST_PASSWORD = "password".toCharArray();
+    static String IDP_ALIAS = "idpCertAlias";
+    static String SP_ALIAS = "spAlias";
+    static char[] SP_TEST_PASSWORD = "sppassword".toCharArray();
+
+    static KeyStore createExampleJks(){
+        File file = new File(KEYSTORE_TEST_PATH);
+        try (FileOutputStream fos = new FileOutputStream(file)){
+            KeyStore ks;
+            ks = KeyStore.getInstance(KeyStore.getDefaultType());
+            if (!file.exists()) {
+                ks.load(null, KEYSTORE_TEST_PASSWORD);
+                ks.store(fos, KEYSTORE_TEST_PASSWORD);
+                logger.info("Example JKS created");
+            }
+            else {
+                logger.info("Example JKS exists");
+            }
+            return ks;
+        } catch (KeyStoreException | CertificateException | 
NoSuchAlgorithmException | IOException e) {
+            logger.error("Error encountered creating JKS", e);
+        }
+        return null;
+    }
+
+    static void addTestingCertsToKeystore(KeyStore testKeyStore){
+        try (FileOutputStream fos = new FileOutputStream(KEYSTORE_TEST_PATH)){
+            testKeyStore.load(null, KEYSTORE_TEST_PASSWORD);
+            KeyPairGenerator keyPairGenerator = 
KeyPairGenerator.getInstance("RSA");
+            keyPairGenerator.initialize(4096);
+            KeyPair keyPairIDP = keyPairGenerator.generateKeyPair();
+            KeyPair keyPairSP = keyPairGenerator.generateKeyPair();
+            final X509Certificate certIDP = JKSHelper.generate(keyPairIDP, 
"SHA256withRSA", "localhost", 730);
+            final X509Certificate certSP = JKSHelper.generate(keyPairSP, 
"SHA256withRSA", "localhost", 730);
+            testKeyStore.setCertificateEntry(IDP_ALIAS, certIDP);
+            testKeyStore.setKeyEntry(SP_ALIAS, keyPairSP.getPrivate(), 
SP_TEST_PASSWORD,  new Certificate[]{certSP});
+            testKeyStore.store(fos, KEYSTORE_TEST_PASSWORD);
+        } catch (Exception e){
+            fail(e.getMessage());
+        }
+    }
+
+    static X509Certificate generate(final KeyPair keyPair, final String 
hashAlgorithm, final String cn, final int days)
+            throws OperatorCreationException, CertificateException, 
CertIOException {
+        final Instant now = Instant.now();
+        final Date notBefore = Date.from(now);
+        final Date notAfter = Date.from(now.plus(Duration.ofDays(days)));
+        final ContentSigner contentSigner = new 
JcaContentSignerBuilder(hashAlgorithm).build(keyPair.getPrivate());
+        final X500Name x500Name = new X500Name("CN=" + cn);
+        final X509v3CertificateBuilder certificateBuilder =
+            new JcaX509v3CertificateBuilder(x500Name,
+                BigInteger.valueOf(now.toEpochMilli()),
+                notBefore, notAfter, x500Name, keyPair.getPublic())
+                .addExtension(Extension.subjectKeyIdentifier, false, 
createSubjectKeyId(keyPair.getPublic()))
+                .addExtension(Extension.authorityKeyIdentifier, false, 
createAuthorityKeyId(keyPair.getPublic()))
+                .addExtension(Extension.basicConstraints, true, new 
BasicConstraints(true));
+        return new JcaX509CertificateConverter()
+            .setProvider(new 
BouncyCastleProvider()).getCertificate(certificateBuilder.build(contentSigner));
+    }
+
+    private static SubjectKeyIdentifier createSubjectKeyId(final PublicKey 
publicKey) throws OperatorCreationException {
+        final SubjectPublicKeyInfo publicKeyInfo = 
SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
+        final DigestCalculator digCalc = new 
BcDigestCalculatorProvider().get(new 
AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1));
+        return new 
X509ExtensionUtils(digCalc).createSubjectKeyIdentifier(publicKeyInfo);
+    }
+
+    private static AuthorityKeyIdentifier createAuthorityKeyId(final PublicKey 
publicKey) throws OperatorCreationException {
+        final SubjectPublicKeyInfo publicKeyInfo = 
SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
+        final DigestCalculator digCalc = new 
BcDigestCalculatorProvider().get(new 
AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1));
+        return new 
X509ExtensionUtils(digCalc).createAuthorityKeyIdentifier(publicKeyInfo);
+    }
+
+}
diff --git 
a/saml-handler/src/test/java/org/apache/sling/auth/saml2/impl/OsgiSamlTest.java 
b/saml-handler/src/test/java/org/apache/sling/auth/saml2/impl/OsgiSamlTest.java
index 4acfdd0..2b6ac2f 100644
--- 
a/saml-handler/src/test/java/org/apache/sling/auth/saml2/impl/OsgiSamlTest.java
+++ 
b/saml-handler/src/test/java/org/apache/sling/auth/saml2/impl/OsgiSamlTest.java
@@ -24,10 +24,15 @@ import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolverFactory;
 import org.apache.sling.auth.saml2.Helpers;
+import org.apache.sling.auth.saml2.SAML2RuntimeException;
 import org.apache.sling.auth.saml2.Saml2User;
 import org.apache.sling.auth.saml2.Saml2UserMgtService;
+import org.apache.sling.auth.saml2.sp.KeyPairCredentials;
+import org.apache.sling.auth.saml2.sp.VerifySignatureCredentials;
 import org.apache.sling.testing.mock.osgi.MockOsgi;
 import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
+import org.bouncycastle.cert.CertIOException;
+import org.bouncycastle.operator.OperatorCreationException;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Rule;
@@ -49,13 +54,28 @@ import org.opensaml.saml.saml2.core.Issuer;
 import org.opensaml.saml.saml2.core.NameIDPolicy;
 import org.opensaml.saml.saml2.core.Response;
 import org.opensaml.saml.saml2.metadata.Endpoint;
+import org.opensaml.security.credential.Credential;
+import org.opensaml.security.x509.BasicX509Credential;
 import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
 import java.time.Instant;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
 import static org.apache.sling.auth.saml2.Activator.initializeOpenSaml;
+import static 
org.apache.sling.auth.saml2.impl.JKSHelper.KEYSTORE_TEST_PASSWORD;
+import static org.apache.sling.auth.saml2.impl.JKSHelper.KEYSTORE_TEST_PATH;
+import static org.apache.sling.auth.saml2.impl.JKSHelper.SP_ALIAS;
+import static org.apache.sling.auth.saml2.impl.JKSHelper.SP_TEST_PASSWORD;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -71,15 +91,22 @@ public class OsgiSamlTest {
     BundleContext bundleContext;
     Saml2UserMgtService userMgtService;
     AuthenticationHandlerSAML2Impl samlHandler;
+    AuthenticationHandlerSAML2Impl saml2handlerJKS;
     XMLObjectBuilder<XSString> valueBuilder;
+    static KeyStore testKeyStore;
+
+    private static Logger logger = LoggerFactory.getLogger(OsgiSamlTest.class);
 
     @BeforeClass
     public static void initializeOpenSAML(){
         try {
             initializeOpenSaml();
+            testKeyStore = JKSHelper.createExampleJks();
+            JKSHelper.addTestingCertsToKeystore(testKeyStore);
         } catch (InitializationException e) {
             fail(e.getMessage());
         }
+
     }
 
     @Before
@@ -88,13 +115,10 @@ public class OsgiSamlTest {
         try {
             bundleContext = MockOsgi.newBundleContext();
             ResourceResolverFactory mockFactory = 
Mockito.mock(ResourceResolverFactory.class);
-//            Saml2UserMgtService saml2UserMgtService = new 
Saml2UserMgtServiceImpl();
-//            MockOsgi.injectServices(mockFactory, bundleContext);
-//            MockOsgi.injectServices(saml2UserMgtService, bundleContext);
-//            MockOsgi.activate(saml2UserMgtService, bundleContext);
             osgiContext.registerService(ResourceResolverFactory.class, 
mockFactory);
             userMgtService = osgiContext.registerService(new 
Saml2UserMgtServiceImpl());
             samlHandler = osgiContext.registerInjectActivateService(new 
AuthenticationHandlerSAML2Impl());
+            setup_saml2handlerJKS();
         } catch (Exception e){
             fail(e.getMessage());
         }
@@ -247,4 +271,59 @@ public class OsgiSamlTest {
         Helpers.buildSAMLObject(Resource.class);
     }
 
+    @Test
+    public void test_withJKS() throws NoSuchAlgorithmException, 
CertificateException, CertIOException, OperatorCreationException, 
KeyStoreException {
+        assertEquals("./target/exampleSaml2.jks", 
saml2handlerJKS.getJksFileLocation());
+        assertEquals("password", saml2handlerJKS.getJksStorePassword());
+        assertTrue(saml2handlerJKS.getSaml2SPEncryptAndSign());
+        assertTrue(saml2handlerJKS.getSaml2SPEnabled());
+    }
+
+    @Test
+    public void test_JKS_sp_KeyPair() {
+        BasicX509Credential spX509Cred = KeyPairCredentials
+            .getCredential( saml2handlerJKS.getJksFileLocation(),
+                saml2handlerJKS.getJksStorePassword().toCharArray(),
+                saml2handlerJKS.getSpKeysAlias(),
+                saml2handlerJKS.getSpKeysPassword().toCharArray()
+            );
+        assertNotNull(spX509Cred);
+    }
+
+    @Test (expected = SAML2RuntimeException.class)
+    public void test_JKS_bad_sp_KeyPair() {
+        BasicX509Credential spX509Cred = KeyPairCredentials
+            .getCredential( saml2handlerJKS.getJksFileLocation(),
+                    saml2handlerJKS.getJksStorePassword().toCharArray(),
+                    saml2handlerJKS.getSpKeysAlias(),
+                    "bad password".toCharArray()
+                );
+    }
+
+    @Test (expected = SAML2RuntimeException.class)
+    public void test_JKS_bad_idp_cert() {
+        Credential idpX509Cred = VerifySignatureCredentials
+            .getCredential( saml2handlerJKS.getJksFileLocation(),
+                    "bad password".toCharArray(),
+                    saml2handlerJKS.getIdpCertAlias()
+            );
+    }
+
+
+    void setup_saml2handlerJKS(){
+        Dictionary<String, Object> props = new Hashtable<>();
+        props.put("jksFileLocation","./target/exampleSaml2.jks");
+        props.put("saml2SPEnabled",true);
+        props.put("saml2SPEncryptAndSign",true);
+        props.put("jksStorePassword","password");
+        props.put("idpCertAlias","idpCertAlias");
+        props.put("spKeysAlias","spAlias");
+        props.put("spKeysPassword","sppassword");
+        try {
+            saml2handlerJKS = osgiContext.registerInjectActivateService(new 
AuthenticationHandlerSAML2Impl(), props);
+        } catch (Exception e) {
+            e.printStackTrace();
+            fail(e.getMessage());
+        }
+    }
 }

Reply via email to