diff options
author | Stefan Seelmann <mail@stefan-seelmann.de> | 2021-05-15 14:35:47 +0300 |
---|---|---|
committer | Stefan Seelmann <mail@stefan-seelmann.de> | 2021-05-15 14:35:47 +0300 |
commit | e92d19cea095829085eaf3eb74eb4d9a7997fc23 (patch) | |
tree | bab4df57ba18d8c21281a05a2816f5ecdb371c6a | |
parent | fa1bb4d4c8283e7e36247f4a0226e423ced63664 (diff) |
Changes required for updated ldap-api
7 files changed, 296 insertions, 5 deletions
diff --git a/eclipse-trgt-platform/pom-first.xml b/eclipse-trgt-platform/pom-first.xml index 527296845..22ed56854 100644 --- a/eclipse-trgt-platform/pom-first.xml +++ b/eclipse-trgt-platform/pom-first.xml @@ -74,6 +74,18 @@ <version>${org.apache.commons.pool.version}</version> </dependency> + <!-- Bouncycastle modules --> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcprov-jdk15on</artifactId> + <version>${org.bouncycastle.version}</version> + </dependency> + + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcpkix-jdk15on</artifactId> + <version>${org.bouncycastle.version}</version> + </dependency> <!-- Mina modules --> <dependency> diff --git a/eclipse-trgt-platform/template/org.apache.directory.studio.eclipse-trgt-platform.template b/eclipse-trgt-platform/template/org.apache.directory.studio.eclipse-trgt-platform.template index 5fdc2f5fc..bd5844e1d 100644 --- a/eclipse-trgt-platform/template/org.apache.directory.studio.eclipse-trgt-platform.template +++ b/eclipse-trgt-platform/template/org.apache.directory.studio.eclipse-trgt-platform.template @@ -19,12 +19,13 @@ @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> --> <?pde version="3.8"?> -<target name="Apache Directory Studio Platform" sequenceNumber="465"> +<target name="Apache Directory Studio Platform" sequenceNumber="467"> <locations> <location includeAllPlatforms="false" includeConfigurePhase="true" includeMode="planner" includeSource="true" type="InstallableUnit"> <!-- External jars --> <unit id="bcprov" version="1.62.0"/> + <unit id="bcpkix" version="1.62.0"/> <unit id="org.apache.servicemix.bundles.antlr" version="2.7.7.5"/> <unit id="org.apache.servicemix.bundles.dom4j" version="2.1.3.1"/> <unit id="org.apache.servicemix.bundles.xpp3" version="1.1.4.c"/> @@ -90,8 +90,8 @@ <org.apache.commons.collections4.bundleversion>4.4.0</org.apache.commons.collections4.bundleversion> <org.apache.commons.io.version>2.6</org.apache.commons.io.version> <org.apache.commons.io.bundleversion>2.6.0</org.apache.commons.io.bundleversion> - <org.apache.commons.lang3.version>3.11</org.apache.commons.lang3.version> - <org.apache.commons.lang3.bundleversion>3.11</org.apache.commons.lang3.bundleversion> + <org.apache.commons.lang3.version>3.12.0</org.apache.commons.lang3.version> + <org.apache.commons.lang3.bundleversion>3.12.0</org.apache.commons.lang3.bundleversion> <org.apache.commons.pool.version>2.9.0</org.apache.commons.pool.version> <org.apache.commons.pool.bundleversion>2.9.0</org.apache.commons.pool.bundleversion> <org.apache.directory.api.version>2.0.2-SNAPSHOT</org.apache.directory.api.version> @@ -102,6 +102,7 @@ <org.apache.poi.version>3.9</org.apache.poi.version> <org.apache.poi.bundleversion>3.9.0</org.apache.poi.bundleversion> <org.apache.xmlgraphics.fop.version>1.0</org.apache.xmlgraphics.fop.version> + <org.bouncycastle.version>1.62</org.bouncycastle.version> <org.slf4j.version>1.7.25</org.slf4j.version> <org.slf4j.bundleversion>1.7.25</org.slf4j.bundleversion> <org.xpp3.version>1.1.4.c</org.xpp3.version> diff --git a/tests/test.integration.core/pom-first.xml b/tests/test.integration.core/pom-first.xml index 00979367f..d7e25297f 100644 --- a/tests/test.integration.core/pom-first.xml +++ b/tests/test.integration.core/pom-first.xml @@ -86,6 +86,14 @@ <Import-Package>org.apache.commons.codec.digest, org.apache.http.conn.ssl, + org.bouncycastle.asn1, + org.bouncycastle.asn1.x509, + org.bouncycastle.cert, + org.bouncycastle.cert.jcajce, + org.bouncycastle.jce.provider, + org.bouncycastle.operator, + org.bouncycastle.operator.jcajce, + org.bouncycastle.x509, org.dom4j, org.dom4j.io</Import-Package> diff --git a/tests/test.integration.core/src/main/java/org/apache/directory/studio/test/integration/junit5/ApacheDirectoryServer.java b/tests/test.integration.core/src/main/java/org/apache/directory/studio/test/integration/junit5/ApacheDirectoryServer.java index d9f94e5da..3f0d9af0c 100644 --- a/tests/test.integration.core/src/main/java/org/apache/directory/studio/test/integration/junit5/ApacheDirectoryServer.java +++ b/tests/test.integration.core/src/main/java/org/apache/directory/studio/test/integration/junit5/ApacheDirectoryServer.java @@ -28,7 +28,6 @@ import java.io.File; import org.apache.directory.server.core.api.DirectoryService; import org.apache.directory.server.core.api.partition.Partition; import org.apache.directory.server.core.factory.DefaultDirectoryServiceFactory; -import org.apache.directory.server.core.security.CertificateUtil; import org.apache.directory.server.ldap.LdapServer; import org.apache.directory.server.ldap.handlers.extended.PwdModifyHandler; import org.apache.directory.server.ldap.handlers.extended.StartTlsHandler; diff --git a/tests/test.integration.core/src/main/java/org/apache/directory/studio/test/integration/junit5/CertificateUtil.java b/tests/test.integration.core/src/main/java/org/apache/directory/studio/test/integration/junit5/CertificateUtil.java new file mode 100644 index 000000000..8aa819751 --- /dev/null +++ b/tests/test.integration.core/src/main/java/org/apache/directory/studio/test/integration/junit5/CertificateUtil.java @@ -0,0 +1,270 @@ +/* + * 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.directory.studio.test.integration.junit5; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandom; +import java.security.Security; +import java.security.SignatureException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.time.Duration; +import java.time.Instant; +import java.util.Date; +import java.util.Enumeration; + +import javax.net.ssl.KeyManagerFactory; +import javax.security.auth.x500.X500Principal; + +import org.apache.directory.api.util.Strings; +import org.bouncycastle.asn1.x509.BasicConstraints; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.GeneralNames; +import org.bouncycastle.cert.CertIOException; +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.OperatorCreationException; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; + +/** + * Helper class used to generate self-signed certificates, and load a KeyStore + * + * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> + */ +public final class CertificateUtil +{ + private static final boolean SELF_SIGNED = true; + private static final boolean CA_SIGNED = false; + private static final boolean CRITICAL = true; + + private CertificateUtil() + { + // Nothing to do + } + + public static X509Certificate generateX509Certificate( X500Principal subjectDn, X500Principal issuerDn, KeyPair keyPair, + long daysValidity, String sigAlgorithm, boolean isCa ) + throws CertificateException + { + Instant from = Instant.now(); + Instant to = from.plus( Duration.ofDays( daysValidity ) ); + BigInteger serialNumber = new BigInteger( 64, new SecureRandom() ); + try + { + ContentSigner signer = new JcaContentSignerBuilder( sigAlgorithm ).build( keyPair.getPrivate() ); + InetAddress localHost = InetAddress.getLocalHost(); + GeneralName[] sanLocalHost = new GeneralName[] { + new GeneralName( GeneralName.dNSName, + localHost.getHostName() ), + new GeneralName( GeneralName.iPAddress, localHost.getHostAddress() ) + }; + X509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder( issuerDn, + serialNumber, + Date.from( from ), + Date.from( to ), + subjectDn, + keyPair.getPublic() ) + .addExtension( Extension.basicConstraints, CRITICAL, new BasicConstraints( isCa ) ) + .addExtension( Extension.subjectAlternativeName, false, new GeneralNames( sanLocalHost ) ); + + return new JcaX509CertificateConverter().setProvider( new BouncyCastleProvider() ) + .getCertificate( certificateBuilder.build( signer ) ); + } + catch ( OperatorCreationException | CertIOException | UnknownHostException e ) + { + throw new CertificateException( "BouncyCastle failed to generate the X509 certificate.", e ); + } + } + + /** + * Create a self signed certificate + * + * @param issuer The Issuer (which is the same as the subject + * @param keyPair The asymmetric keyPair + * @param days Validity number of days + * @param algoStr Algorithm + * @return A self signed CA certificate + * @throws CertificateException If the info store din the certificate is invalid + * @throws IOException If we can't store some info in the certificate + * @throws NoSuchAlgorithmException If the algorithm does not exist + * @throws SignatureException If the certificate cannot be signed + * @throws NoSuchProviderException If we don't have a security provider + * @throws InvalidKeyException If the KeyPair is invalid + */ + public static X509Certificate generateSelfSignedCertificate( X500Principal issuer, KeyPair keyPair, int days, String algoStr ) + throws CertificateException, IOException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException + { + return generateX509Certificate( issuer, issuer, keyPair, days, algoStr, SELF_SIGNED ); + } + + /** + * Generate a Certificate signed by a CA certificate + * + * @param issuer The Issuer (which is the same as the subject + * @param keyPair The asymmetric keyPair + * @param days Validity number of days + * @param algoStr Algorithm + * @return A self signed CA certificate + * @throws CertificateException If the info store din the certificate is invalid + * @throws IOException If we can't store some info in the certificate + * @throws NoSuchAlgorithmException If the algorithm does not exist + * @throws SignatureException If the certificate cannot be signed + * @throws NoSuchProviderException If we don't have a security provider + * @throws InvalidKeyException If the KeyPair is invalid + */ + public static X509Certificate generateCertificate( X500Principal subject, X500Principal issuer, KeyPair keyPair, int days, String algoStr ) + throws CertificateException, IOException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException + { + return generateX509Certificate( subject, issuer, keyPair, days, algoStr, CA_SIGNED ); + } + + + /** + * Loads the digital certificate from a keystore file + * + * @param keyStoreFile The KeyStore file to load + * @param keyStorePasswordStr The KeyStore password + * @return The KeyManager factory it created + * @throws Exception If the KeyStore can't be loaded + */ + public static KeyManagerFactory loadKeyStore( String keyStoreFile, String keyStorePasswordStr ) throws Exception + { + char[] keyStorePassword = Strings.isEmpty( keyStorePasswordStr ) ? null : keyStorePasswordStr.toCharArray(); + + if ( !Strings.isEmpty( keyStoreFile ) ) + { + // We have a provided KeyStore file: read it + KeyStore keyStore = KeyStore.getInstance( KeyStore.getDefaultType() ); + + try ( InputStream is = Files.newInputStream( Paths.get( keyStoreFile ) ) ) + { + keyStore.load( is, keyStorePassword ); + } + + /* + * Verify key store: + * * Must only contain one entry which must be a key entry + * * Must contain a certificate chain + * * The private key must be recoverable by the key store password + */ + Enumeration<String> aliases = keyStore.aliases(); + + if ( !aliases.hasMoreElements() ) + { + throw new KeyStoreException( "Key store is empty" ); + } + + String alias = aliases.nextElement(); + + if ( aliases.hasMoreElements() ) + { + throw new KeyStoreException( "Key store contains more than one entry" ); + } + + if ( !keyStore.isKeyEntry( alias ) ) + { + throw new KeyStoreException( "Key store must contain a key entry" ); + } + + if ( keyStore.getCertificateChain( alias ) == null ) + { + throw new KeyStoreException( "Key store must contain a certificate chain" ); + } + + if ( keyStore.getKey( alias, keyStorePassword ) == null ) + { + throw new KeyStoreException( "Private key must be recoverable by the key store password" ); + } + + // Set up key manager factory to use our key store + String algorithm = Security.getProperty( "ssl.KeyManagerFactory.algorithm" ); + + if ( algorithm == null ) + { + algorithm = KeyManagerFactory.getDefaultAlgorithm(); + } + + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance( algorithm ); + + keyManagerFactory.init( keyStore, keyStorePassword ); + + return keyManagerFactory; + } + else + { + return null; + } + } + + + public static File createTempKeyStore( String keyStoreName, char[] keyStorePassword ) throws IOException, KeyStoreException, + NoSuchAlgorithmException, CertificateException, InvalidKeyException, NoSuchProviderException, SignatureException + { + // Create a temporary keystore, be sure to remove it when exiting the test + File keyStoreFile = Files.createTempFile( keyStoreName, "ks" ).toFile(); + keyStoreFile.deleteOnExit(); + + KeyStore keyStore = KeyStore.getInstance( KeyStore.getDefaultType() ); + + try ( InputStream keyStoreData = new FileInputStream( keyStoreFile ) ) + { + keyStore.load( null, keyStorePassword ); + } + + // Generate the asymmetric keys, using EC algorithm + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( "EC" ); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + + // Generate the subject's name + X500Principal owner = new X500Principal( "CN=apacheds,OU=directory,O=apache,C=US" ); + + // Create the self-signed certificate + X509Certificate certificate = CertificateUtil.generateSelfSignedCertificate( owner, keyPair, 365, "SHA256WithECDSA" ); + + keyStore.setKeyEntry( "apachedsKey", keyPair.getPrivate(), keyStorePassword, new X509Certificate[] { certificate } ); + + try ( FileOutputStream out = new FileOutputStream( keyStoreFile ) ) + { + keyStore.store( out, keyStorePassword ); + } + + return keyStoreFile; + } +} diff --git a/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/CertificateValidationTest.java b/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/CertificateValidationTest.java index c6bdd7bd3..0c8714fe3 100644 --- a/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/CertificateValidationTest.java +++ b/tests/test.integration.ui/src/main/java/org/apache/directory/studio/test/integration/ui/CertificateValidationTest.java @@ -537,7 +537,7 @@ public class CertificateValidationTest extends AbstractTestBase trustDialogBot.selectDontTrust(); clickOkButtonExpectingCertficateErrorDialog( trustDialogBot, "Failed to verify certification path", - "Algorithm constraints check failed on keysize limits", "RSA 512bit key used" ); + "Algorithm constraints check failed on keysize limits", "RSA 512", "bit key used" ); wizardBot.clickCancelButton(); } |