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());
+ }
+ }
}