Merge branch 'master' of
https://gitbox.apache.org/repos/asf/directory-server
# Conflicts:
# service/src/test/java/org/apache/directory/server/UberJarMainTest.java
diff --git a/all/pom.xml b/all/pom.xml
index 96cd601..533c931 100644
--- a/all/pom.xml
+++ b/all/pom.xml
@@ -163,11 +163,11 @@
<promoteTransitiveDependencies>true</promoteTransitiveDependencies>
<filters>
<filter>
- <artifact>org.bouncycastle:bcprov-jdk15on</artifact>
+ <artifact>*:*</artifact>
<excludes>
- <exclude>META-INF/BCK*.SF</exclude>
- <exclude>META-INF/BCK*.DSA</exclude>
- <exclude>META-INF/BCK*.RSA</exclude>
+ <exclude>META-INF/*.SF</exclude>
+ <exclude>META-INF/*.DSA</exclude>
+ <exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
diff --git a/core-annotations/pom.xml b/core-annotations/pom.xml
index 7cf584d..d61876c 100644
--- a/core-annotations/pom.xml
+++ b/core-annotations/pom.xml
@@ -88,6 +88,12 @@
<groupId>org.apache.directory.mavibot</groupId>
<artifactId>mavibot</artifactId>
</dependency>
+
+ <!-- Override the default version bundled with Mavibot -->
+ <dependency>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
diff --git a/core-annotations/src/main/java/org/apache/directory/server/core/factory/DSAnnotationProcessor.java b/core-annotations/src/main/java/org/apache/directory/server/core/factory/DSAnnotationProcessor.java
index b5be49c..028808c 100644
--- a/core-annotations/src/main/java/org/apache/directory/server/core/factory/DSAnnotationProcessor.java
+++ b/core-annotations/src/main/java/org/apache/directory/server/core/factory/DSAnnotationProcessor.java
@@ -472,7 +472,7 @@
private static boolean isDn( String str )
{
- if ( ( Strings.isEmpty( str ) ) | ( str.length() < 3 ) )
+ if ( ( Strings.isEmpty( str ) ) || ( str.length() < 3 ) )
{
return false;
}
diff --git a/core-integ/src/test/java/org/apache/directory/server/core/operations/move/MoveIT.java b/core-integ/src/test/java/org/apache/directory/server/core/operations/move/MoveIT.java
index 13f75d4..93a72e2 100644
--- a/core-integ/src/test/java/org/apache/directory/server/core/operations/move/MoveIT.java
+++ b/core-integ/src/test/java/org/apache/directory/server/core/operations/move/MoveIT.java
@@ -86,7 +86,7 @@
Dn dn = new Dn( oldDn );
Entry entry = new DefaultEntry( getService().getSchemaManager(), dn,
- "ObjectClass: top",
+ "ObjectClass: top",
"ObjectClass: person",
"sn: TEST",
"cn: test" );
@@ -100,7 +100,7 @@
assertNotNull( connection.lookup( newDn ) );
assertNull( connection.lookup( oldDn ) );
-
+
connection.close();
}
@@ -115,29 +115,29 @@
LdapConnection connection = IntegrationUtils.getAdminConnection( getService() );
Entry test1 = new DefaultEntry( getService().getSchemaManager(), "cn=test1,ou=system",
- "ObjectClass: top",
+ "ObjectClass: top",
"ObjectClass: person",
"sn: Test1",
"cn: tes1t" );
Entry childTest1 = new DefaultEntry( getService().getSchemaManager(), "cn=childTest1,cn=test1,ou=system",
- "ObjectClass: top",
+ "ObjectClass: top",
"ObjectClass: person",
"sn: child test1",
"cn: childTest1" );
Entry test2 = new DefaultEntry( getService().getSchemaManager(), "cn=test2,ou=system",
- "ObjectClass: top",
+ "ObjectClass: top",
"ObjectClass: person",
"sn: Test2",
"cn: test2" );
Entry childTest2 = new DefaultEntry( getService().getSchemaManager(), "cn=childTest2,cn=test2,ou=system",
- "ObjectClass: top",
+ "ObjectClass: top",
"ObjectClass: person",
"sn: child test2",
"cn: childTest2" );
-
+
connection.add( test1 );
connection.add( test2 );
connection.add( childTest1 );
@@ -156,11 +156,11 @@
assertNotNull( connection.lookup( "cn=childTest2,cn=test2,ou=system" ) );
assertNotNull( connection.lookup( "cn=test1,cn=test2,ou=system" ) );
assertNotNull( connection.lookup( "cn=childTest1,cn=test1,cn=test2,ou=system" ) );
-
+
connection.close();
}
-
-
+
+
/**
* Test a move operation to a non existing parent:
* cn=test,ou=system will be moved to cn=test,ou=users,ou=system
@@ -176,7 +176,7 @@
Dn dn = new Dn( oldDn );
Entry entry = new DefaultEntry( getService().getSchemaManager(), dn,
- "ObjectClass: top",
+ "ObjectClass: top",
"ObjectClass: person",
"sn: TEST",
"cn: test" );
@@ -198,7 +198,7 @@
assertNull( connection.lookup( newDn ) );
assertNotNull( connection.lookup( oldDn ) );
-
+
connection.close();
}
@@ -219,7 +219,7 @@
Dn dn = new Dn( oldDn );
Entry entry = new DefaultEntry( getService().getSchemaManager(), dn,
- "ObjectClass: top",
+ "ObjectClass: top",
"ObjectClass: person",
"sn: TEST",
"cn: test" );
@@ -228,7 +228,7 @@
Dn targetDn = new Dn( targetDnStr );
Entry target = new DefaultEntry( getService().getSchemaManager(), targetDn,
- "ObjectClass: top",
+ "ObjectClass: top",
"ObjectClass: person",
"sn: TEST",
"cn: test" );
@@ -247,7 +247,7 @@
assertNotNull( connection.lookup( newDn ) );
assertNotNull( connection.lookup( oldDn ) );
}
-
+
connection.close();
}
}
diff --git a/core-integ/src/test/java/org/apache/directory/server/core/operations/moveAndRename/MoveAndRenameIT.java b/core-integ/src/test/java/org/apache/directory/server/core/operations/moveAndRename/MoveAndRenameIT.java
index 2af0261..0900b7e 100644
--- a/core-integ/src/test/java/org/apache/directory/server/core/operations/moveAndRename/MoveAndRenameIT.java
+++ b/core-integ/src/test/java/org/apache/directory/server/core/operations/moveAndRename/MoveAndRenameIT.java
@@ -134,25 +134,25 @@
Entry oldCommon = connection.lookup( "ou=people,ou=system", "*", "+" );
Entry oldSuperior = connection.lookup( "ou=committers,ou=Apache,ou=people,ou=system", "*", "+" );
Entry newSuperior = connection.lookup( "dc=domain,ou=system", "*", "+" );
-
+
// Check the old common
Attribute nbSubordinate = oldCommon.get( "nbSubordinates" );
Attribute nbChildren = oldCommon.get( "nbChildren" );
-
+
assertEquals( "5", nbSubordinate.getString() );
assertEquals( "1", nbChildren.getString() );
// The old superior
nbSubordinate = oldSuperior.get( "nbSubordinates" );
nbChildren = oldSuperior.get( "nbChildren" );
-
+
assertEquals( "2", nbSubordinate.getString() );
assertEquals( "2", nbChildren.getString() );
// The new superior
nbSubordinate = newSuperior.get( "nbSubordinates" );
nbChildren = newSuperior.get( "nbChildren" );
-
+
assertEquals( "0", nbSubordinate.getString() );
assertEquals( "0", nbChildren.getString() );
@@ -166,41 +166,41 @@
connection.moveAndRename( oldDn, newDn, true );
assertNull( connection.lookup( oldDn ) );
-
+
Entry movedEntry = connection.lookup( newDn, "*", "+" );
assertNotNull( movedEntry );
assertTrue( movedEntry.contains( "cn", "emmanuel" ) );
assertFalse( movedEntry.contains( "cn", "elecharny" ) );
-
+
// Get the nbSubordinates before the move
oldCommon = connection.lookup( "ou=people,ou=system", "*", "+" );
oldSuperior = connection.lookup( "ou=committers,ou=Apache,ou=people,ou=system", "*", "+" );
newSuperior = connection.lookup( "dc=domain,ou=system", "*", "+" );
-
+
// Check the old common
nbSubordinate = oldCommon.get( "nbSubordinates" );
nbChildren = oldCommon.get( "nbChildren" );
-
+
assertEquals( "4", nbSubordinate.getString() );
assertEquals( "1", nbChildren.getString() );
// The old superior
nbSubordinate = oldSuperior.get( "nbSubordinates" );
nbChildren = oldSuperior.get( "nbChildren" );
-
+
assertEquals( "1", nbSubordinate.getString() );
assertEquals( "1", nbChildren.getString() );
// The new superior
nbSubordinate = newSuperior.get( "nbSubordinates" );
nbChildren = newSuperior.get( "nbChildren" );
-
+
assertEquals( "1", nbSubordinate.getString() );
assertEquals( "1", nbChildren.getString() );
connection.close();
}
-
+
/**
* Test a simple MoveAndRename move operation
* cn=elecharny,ou=committers,ou=Apache,ou=people,ou=system will be moved to
@@ -220,25 +220,25 @@
Entry oldCommon = connection.lookup( "ou=people,ou=system", "*", "+" );
Entry oldSuperior = connection.lookup( "ou=committers,ou=Apache,ou=people,ou=system", "*", "+" );
Entry newSuperior = connection.lookup( "dc=domain,ou=system", "*", "+" );
-
+
// Check the old common
Attribute nbSubordinate = oldCommon.get( "nbSubordinates" );
Attribute nbChildren = oldCommon.get( "nbChildren" );
-
+
assertEquals( "5", nbSubordinate.getString() );
assertEquals( "1", nbChildren.getString() );
// The old superior
nbSubordinate = oldSuperior.get( "nbSubordinates" );
nbChildren = oldSuperior.get( "nbChildren" );
-
+
assertEquals( "2", nbSubordinate.getString() );
assertEquals( "2", nbChildren.getString() );
// The new superior
nbSubordinate = newSuperior.get( "nbSubordinates" );
nbChildren = newSuperior.get( "nbChildren" );
-
+
assertEquals( "0", nbSubordinate.getString() );
assertEquals( "0", nbChildren.getString() );
@@ -252,42 +252,42 @@
connection.moveAndRename( oldDn, newDn, false );
assertNull( connection.lookup( oldDn ) );
-
+
Entry movedEntry = connection.lookup( newDn, "*", "+" );
assertNotNull( movedEntry );
assertTrue( movedEntry.contains( "cn", "emmanuel" ) );
assertTrue( movedEntry.contains( "cn", "elecharny" ) );
-
+
// Get the nbSubordinates before the move
oldCommon = connection.lookup( "ou=people,ou=system", "*", "+" );
oldSuperior = connection.lookup( "ou=committers,ou=Apache,ou=people,ou=system", "*", "+" );
newSuperior = connection.lookup( "dc=domain,ou=system", "*", "+" );
-
+
// Check the old common
nbSubordinate = oldCommon.get( "nbSubordinates" );
nbChildren = oldCommon.get( "nbChildren" );
-
+
assertEquals( "4", nbSubordinate.getString() );
assertEquals( "1", nbChildren.getString() );
// The old superior
nbSubordinate = oldSuperior.get( "nbSubordinates" );
nbChildren = oldSuperior.get( "nbChildren" );
-
+
assertEquals( "1", nbSubordinate.getString() );
assertEquals( "1", nbChildren.getString() );
// The new superior
nbSubordinate = newSuperior.get( "nbSubordinates" );
nbChildren = newSuperior.get( "nbChildren" );
-
+
assertEquals( "1", nbSubordinate.getString() );
assertEquals( "1", nbChildren.getString() );
connection.close();
}
-
+
/**
* Test a simple MoveAndRename move operation
* ou=Apache,ou=system will be moved to cn=test,ou=users,ou=system
@@ -300,7 +300,6 @@
public void testMoveAndRenameRdnNotInObjectClass() throws Exception
{
LdapConnection connection = IntegrationUtils.getAdminConnection( getService() );
-
String oldDn = "ou=Apache,ou=system";
String newDn = "uid=test,ou=people,ou=system";
@@ -311,17 +310,17 @@
connection.moveAndRename( oldDn, newDn );
assertNull( connection.lookup( oldDn ) );
-
+
Entry movedEntry = connection.lookup( newDn );
assertNotNull( movedEntry );
assertTrue( movedEntry.contains( "cn", "test" ) );
assertTrue( movedEntry.contains( "cn", "jDoe" ) );
assertTrue( movedEntry.contains( "ou", "Apache" ) );
-
+
connection.close();
}
-
-
+
+
/**
* Check that when doing a rename, with a SV RDN, we don't have the previous RDN in the entry,
* if the deleteOldrdn flag is set to true
@@ -353,9 +352,9 @@
"c: FR" );
connection.add( frEntry );
-
+
Entry original = connection.lookup( frDn );
-
+
assertNotNull( original );
// rename the FR entry to DE entry : should fail as DE entry already exists
diff --git a/core-integ/src/test/java/org/apache/directory/server/core/operations/rename/RenameIT.java b/core-integ/src/test/java/org/apache/directory/server/core/operations/rename/RenameIT.java
index a93d904..a2c3f88 100644
--- a/core-integ/src/test/java/org/apache/directory/server/core/operations/rename/RenameIT.java
+++ b/core-integ/src/test/java/org/apache/directory/server/core/operations/rename/RenameIT.java
@@ -88,24 +88,24 @@
"cn: test1" );
connection.add( entry );
-
+
Entry original = connection.lookup( oldDn );
-
+
assertNotNull( original );
connection.rename( oldDn, "cn=TEST2" );
-
+
Entry renamed = connection.lookup( newDn );
-
+
assertNotNull( renamed );
assertEquals( newDn, renamed.getDn().toString() );
Attribute attribute = renamed.get( "cn" );
-
- assertTrue( attribute.contains( "test1" ) );
- assertTrue( attribute.contains( "test2" ) );
+
+ assertTrue( attribute.contains( "test1" ) );
+ assertTrue( attribute.contains( "test2" ) );
}
-
-
+
+
/**
* Check that when doing a rename, with a MV RDN, and teh deleteOldRdn flag set to true,
* we don't have the previous RDN in the entry.
@@ -128,25 +128,25 @@
"cn: test1" );
connection.add( entry );
-
+
Entry original = connection.lookup( oldDn );
-
+
assertNotNull( original );
connection.rename( oldDn, "cn=test2", true );
-
+
assertNull( connection.lookup( oldDn ) );
Entry renamed = connection.lookup( newDn );
-
+
assertNotNull( renamed );
assertEquals( newDn, renamed.getDn().toString() );
Attribute attribute = renamed.get( "cn" );
-
+
assertFalse( attribute.contains( "test1" ) );
assertTrue( attribute.contains( "test2" ) );
}
-
-
+
+
/**
* Check that when doing a rename, with a MV RDN, and the deleteOldRdn flag set to false,
* we have the previous RDN in the entry.
@@ -169,25 +169,25 @@
"cn: test1" );
connection.add( entry );
-
+
Entry original = connection.lookup( oldDn );
-
+
assertNotNull( original );
connection.rename( oldDn, "cn=test2", false );
-
+
assertNull( connection.lookup( oldDn ) );
Entry renamed = connection.lookup( newDn );
-
+
assertNotNull( renamed );
assertEquals( newDn, renamed.getDn().toString() );
Attribute attribute = renamed.get( "cn" );
-
+
assertTrue( attribute.contains( "test1" ) );
assertTrue( attribute.contains( "test2" ) );
}
-
-
+
+
/**
* Check that when doing a rename, with a SV RDN, we get an error if the deleteOldRdn flag is
* set to false
@@ -209,9 +209,9 @@
"c: FR" );
connection.add( entry );
-
+
Entry original = connection.lookup( oldDn );
-
+
assertNotNull( original );
try
@@ -222,12 +222,12 @@
{
System.out.println( e.getMessage() );
}
-
+
assertNotNull( connection.lookup( oldDn ) );
assertNull( connection.lookup( newDn ) );
}
-
-
+
+
/**
* Check that when doing a rename, with a SV RDN, we don't have the previous RDN in the entry,
* if the deleteOldrdn flgg is set to true
@@ -249,25 +249,25 @@
"c: FR" );
connection.add( entry );
-
+
Entry original = connection.lookup( oldDn );
-
+
assertNotNull( original );
connection.rename( oldDn, "c=DE", true );
-
+
assertNull( connection.lookup( oldDn ) );
Entry renamed = connection.lookup( newDn );
-
+
assertNotNull( renamed );
assertEquals( newDn, renamed.getDn().toString() );
Attribute countryName = renamed.get( "c" );
-
+
assertTrue( countryName.contains( "DE" ) );
assertFalse( countryName.contains( "FR" ) );
}
-
-
+
+
/**
* Check that when doing a rename, with a SV RDN, we don't have the previous RDN in the entry,
* if the deleteOldrdn flag is set to true
@@ -299,9 +299,9 @@
"c: FR" );
connection.add( frEntry );
-
+
Entry original = connection.lookup( frDn );
-
+
assertNotNull( original );
// rename the FR entry to DE entry : should fail as DE entry already exists
@@ -325,15 +325,15 @@
assertFalse( originalDe.get( "c" ).contains( "FR" ) );
}
}
-
-
+
+
/**
* Check that when doing a rename, with a SV RDN, we get an error if the deleteOldRdn flag is
* set to false
*
* @throws Exception
*/
- @Test
+ @Test
public void testRenameMvAttributeSVAttributeKeepOldRdn() throws Exception
{
LdapConnection connection = IntegrationUtils.getAdminConnection( getService() );
@@ -351,26 +351,26 @@
"cn: test" );
connection.add( entry );
-
+
Entry original = connection.lookup( oldDn );
-
+
assertNotNull( original );
connection.rename( oldDn, "displayName=myTest", false );
-
+
assertNull( connection.lookup( oldDn ) );
Entry renamed = connection.lookup( newDn );
-
+
assertNotNull( renamed );
assertEquals( newDn, renamed.getDn().toString() );
Attribute displayName = renamed.get( "displayName" );
Attribute cn = renamed.get( "cn" );
-
+
assertTrue( displayName.contains( "mytest" ) );
assertTrue( cn.contains( "test" ) );
}
-
-
+
+
/**
* Check that when doing a rename, from a MV attribute to a SV attribute, we don't have
* the previous RDN in the entry, if the deleteOldrdn flgg is set to true
@@ -393,24 +393,24 @@
"ObjectClass: inetOrgPerson",
"sn: TEST",
"cn: test",
- "gn: test");
+ "gn: test" );
connection.add( entry );
-
+
Entry original = connection.lookup( oldDn );
-
+
assertNotNull( original );
connection.rename( oldDn, "displayName=MyTest", true );
-
+
assertNull( connection.lookup( oldDn ) );
Entry renamed = connection.lookup( newDn );
-
+
assertNotNull( renamed );
assertEquals( newDn, renamed.getDn().toString() );
Attribute displayName = renamed.get( "displayName" );
Attribute cn = renamed.get( "gn" );
-
+
assertTrue( displayName.contains( "mytest" ) );
assertNull( cn );
}
diff --git a/core/pom.xml b/core/pom.xml
index 1821f93..393f52e 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -158,6 +158,11 @@
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-jdk15on</artifactId>
+ </dependency>
</dependencies>
<build>
@@ -261,6 +266,10 @@
org.bouncycastle.x509;version=${bcprov.version},
org.bouncycastle.asn1;version=${bcprov.version},
org.bouncycastle.asn1.x509;version=${bcprov.version},
+ org.bouncycastle.operator;version=${bcprov.version},
+ org.bouncycastle.operator.jcajce;version=${bcprov.version},
+ org.bouncycastle.cert;version=${bcprov.version},
+ org.bouncycastle.cert.jcajce;version=${bcprov.version},
org.slf4j;version=${slf4j.api.bundleversion}
</Import-Package>
</instructions>
diff --git a/core/src/main/java/org/apache/directory/server/core/security/CertificateUtil.java b/core/src/main/java/org/apache/directory/server/core/security/CertificateUtil.java
index be1e40f..11ada86 100644
--- a/core/src/main/java/org/apache/directory/server/core/security/CertificateUtil.java
+++ b/core/src/main/java/org/apache/directory/server/core/security/CertificateUtil.java
@@ -26,6 +26,7 @@
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;
@@ -40,36 +41,33 @@
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 sun.security.x509.AlgorithmId;
-import sun.security.x509.BasicConstraintsExtension;
-import sun.security.x509.CertificateAlgorithmId;
-import sun.security.x509.CertificateExtensions;
-import sun.security.x509.CertificateSerialNumber;
-import sun.security.x509.CertificateValidity;
-import sun.security.x509.CertificateVersion;
-import sun.security.x509.CertificateX509Key;
-import sun.security.x509.DNSName;
-import sun.security.x509.GeneralName;
-import sun.security.x509.GeneralNames;
-import sun.security.x509.IPAddressName;
-import sun.security.x509.SubjectAlternativeNameExtension;
-import sun.security.x509.X500Name;
-import sun.security.x509.X509CertImpl;
-import sun.security.x509.X509CertInfo;
+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>
*/
-@SuppressWarnings("restriction")
public final class CertificateUtil
{
private static final boolean SELF_SIGNED = true;
@@ -81,94 +79,40 @@
// Nothing to do
}
-
- private static void setInfo( X509CertInfo info, X500Name subject, X500Name issuer, KeyPair keyPair, int days,
- String algoStr, boolean isCA )
- throws CertificateException, IOException, NoSuchAlgorithmException
+ public static X509Certificate generateX509Certificate( X500Principal subjectDn, X500Principal issuerDn, KeyPair keyPair,
+ long daysValidity, String sigAlgorithm, boolean isCa )
+ throws CertificateException
{
- Date from = new Date();
- Date to = new Date( from.getTime() + days * 86_400_000L );
- CertificateValidity interval = new CertificateValidity( from, to );
-
- // Feed the certificate info structure
- // version [0] EXPLICIT Version DEFAULT v1
- // Version ::= INTEGER { v1(0), v2(1), v3(2) }
- info.set( X509CertInfo.VERSION, new CertificateVersion( CertificateVersion.V3 ) );
-
- // serialNumber CertificateSerialNumber
- // CertificateSerialNumber ::= INTEGER
+ Instant from = Instant.now();
+ Instant to = from.plus( Duration.ofDays( daysValidity ) );
BigInteger serialNumber = new BigInteger( 64, new SecureRandom() );
- info.set( X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber( serialNumber ) );
+ 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 ) );
- // signature AlgorithmIdentifier
- AlgorithmId algo = AlgorithmId.get( algoStr );
- info.set( X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId( algo ) );
-
- // issuer Name
- // Name ::= CHOICE {
- // RDNSequence }
- // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
- // RelativeDistinguishedName ::=
- // SET OF AttributeTypeAndValue
- // AttributeTypeAndValue ::= SEQUENCE {
- // type AttributeType,
- // value AttributeValue }
- // AttributeType ::= OBJECT IDENTIFIER
- // AttributeValue ::= ANY DEFINED BY AttributeType
- info.set( X509CertInfo.ISSUER, issuer );
-
- // validity Validity,
- // Validity ::= SEQUENCE {
- // notBefore Time,
- // notAfter Time }
- info.set( X509CertInfo.VALIDITY, interval );
-
- // subject Name
- // Name ::= CHOICE {
- // RDNSequence }
- // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
- // RelativeDistinguishedName ::=
- // SET OF AttributeTypeAndValue
- // AttributeTypeAndValue ::= SEQUENCE {
- // type AttributeType,
- // value AttributeValue }
- // AttributeType ::= OBJECT IDENTIFIER
- // AttributeValue ::= ANY DEFINED BY AttributeType
- info.set( X509CertInfo.SUBJECT, subject );
-
- // subjectPublicKeyInfo SubjectPublicKeyInfo,
- // SubjectPublicKeyInfo ::= SEQUENCE {
- // algorithm AlgorithmIdentifier,
- // subjectPublicKey BIT STRING }
- info.set( X509CertInfo.KEY, new CertificateX509Key( keyPair.getPublic() ) );
-
- // Extensions. Basically, a subjectAltName and a Basic-Constraint
- CertificateExtensions extensions = new CertificateExtensions();
-
- // SubjectAltName
- GeneralNames names = new GeneralNames();
- names.add( new GeneralName( new DNSName( InetAddress.getLocalHost().getHostName() ) ) );
- String ipAddress = InetAddress.getLocalHost().getHostAddress();
- names.add( new GeneralName( new IPAddressName( ipAddress ) ) );
-
- // A wildcard
- //names.add( new GeneralName(
- // new DNSName(
- // new DerValue(
- // DerValue.tag_IA5String, "*.apache.org" ) ) ) );
- SubjectAlternativeNameExtension subjectAltName = new SubjectAlternativeNameExtension( names );
-
- extensions.set( subjectAltName.getExtensionId().toString(), subjectAltName );
-
- // The Basic-Constraint,
- BasicConstraintsExtension basicConstraint = new BasicConstraintsExtension( CRITICAL, isCA, -1 );
- extensions.set( basicConstraint.getExtensionId().toString(), basicConstraint );
-
- // Inject the extensions into the cert
- info.set( X509CertInfo.EXTENSIONS, extensions );
+ 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
*
@@ -184,23 +128,12 @@
* @throws NoSuchProviderException If we don't have a security provider
* @throws InvalidKeyException If the KeyPair is invalid
*/
- public static X509Certificate generateSelfSignedCertificate( X500Name issuer, KeyPair keyPair, int days, String algoStr )
+ public static X509Certificate generateSelfSignedCertificate( X500Principal issuer, KeyPair keyPair, int days, String algoStr )
throws CertificateException, IOException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException
{
- // Create the certificate info
- X509CertInfo info = new X509CertInfo();
-
- // Set the common certificate info
- setInfo( info, issuer, issuer, keyPair, days, algoStr, SELF_SIGNED );
-
- // Sign the cert to identify the algorithm that's used.
- X509CertImpl certificate = new X509CertImpl( info );
- certificate.sign( keyPair.getPrivate(), algoStr );
-
- return certificate;
+ return generateX509Certificate( issuer, issuer, keyPair, days, algoStr, SELF_SIGNED );
}
-
/**
* Generate a Certificate signed by a CA certificate
*
@@ -216,20 +149,10 @@
* @throws NoSuchProviderException If we don't have a security provider
* @throws InvalidKeyException If the KeyPair is invalid
*/
- public static X509Certificate generateCertificate( X500Name subject, X500Name issuer, KeyPair keyPair, int days, String algoStr )
+ public static X509Certificate generateCertificate( X500Principal subject, X500Principal issuer, KeyPair keyPair, int days, String algoStr )
throws CertificateException, IOException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException
{
- // Create the certificate info
- X509CertInfo info = new X509CertInfo();
-
- // Set the common certificate info
- setInfo( info, subject, issuer, keyPair, days, algoStr, CA_SIGNED );
-
- // Sign the cert to identify the algorithm that's used.
- X509CertImpl certificate = new X509CertImpl( info );
- certificate.sign( keyPair.getPrivate(), algoStr );
-
- return certificate;
+ return generateX509Certificate( subject, issuer, keyPair, days, algoStr, CA_SIGNED );
}
@@ -330,8 +253,7 @@
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// Generate the subject's name
- @SuppressWarnings("restriction")
- X500Name owner = new X500Name( "apacheds", "directory", "apache", "US" );
+ 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" );
diff --git a/core/src/test/java/org/apache/directory/server/core/DefaultDirectoryServiceTest.java b/core/src/test/java/org/apache/directory/server/core/DefaultDirectoryServiceTest.java
index df0df02..90c2731 100644
--- a/core/src/test/java/org/apache/directory/server/core/DefaultDirectoryServiceTest.java
+++ b/core/src/test/java/org/apache/directory/server/core/DefaultDirectoryServiceTest.java
@@ -46,7 +46,7 @@
for ( int i = 0; i < service.getInterceptors().size(); i++ )
{
Interceptor interceptor = service.getInterceptors().get( i );
-
+
if ( existingInterceptorName.equals( interceptor.getName() ) )
{
final Interceptor nextInterceptor = service.getInterceptors().get( i + 1 );
diff --git a/core/src/test/java/org/apache/directory/server/core/security/CertificateUtilTest.java b/core/src/test/java/org/apache/directory/server/core/security/CertificateUtilTest.java
index 2ccc5a5..0a60df2 100644
--- a/core/src/test/java/org/apache/directory/server/core/security/CertificateUtilTest.java
+++ b/core/src/test/java/org/apache/directory/server/core/security/CertificateUtilTest.java
@@ -25,9 +25,9 @@
import java.security.KeyPairGenerator;
import java.security.cert.X509Certificate;
-import org.junit.Test;
+import javax.security.auth.x500.X500Principal;
-import sun.security.x509.X500Name;
+import org.junit.Test;
/**
* Test for the CertificateUtil class.
@@ -42,7 +42,7 @@
public void testSelfSignedCertificateCreation() throws IOException, GeneralSecurityException
{
// Generate the subject's name
- X500Name owner = new X500Name( "apacheds", "directory", "apache", "US" );
+ X500Principal owner = new X500Principal( "CN=apacheds,OU=directory,O=apache,C=US" );
// generate the asymetric keys
diff --git a/kerberos-codec/src/main/java/org/apache/directory/shared/kerberos/KerberosUtils.java b/kerberos-codec/src/main/java/org/apache/directory/shared/kerberos/KerberosUtils.java
index 43b3f21..23381c8 100644
--- a/kerberos-codec/src/main/java/org/apache/directory/shared/kerberos/KerberosUtils.java
+++ b/kerberos-codec/src/main/java/org/apache/directory/shared/kerberos/KerberosUtils.java
@@ -389,11 +389,11 @@
{
String cipherName = Strings.toLowerCaseAscii( encType.getName() );
- for ( String c : cipherAlgoMap.keySet() )
+ for ( Map.Entry<String, String> entry : cipherAlgoMap.entrySet() )
{
- if ( cipherName.startsWith( c ) )
+ if ( cipherName.startsWith( entry.getKey() ) )
{
- return cipherAlgoMap.get( c );
+ return entry.getValue();
}
}
diff --git a/ldap-client-test/pom.xml b/ldap-client-test/pom.xml
index ac48d74..682bccd 100644
--- a/ldap-client-test/pom.xml
+++ b/ldap-client-test/pom.xml
@@ -98,6 +98,12 @@
<groupId>org.apache.directory.mavibot</groupId>
<artifactId>mavibot</artifactId>
</dependency>
+
+ <!-- Override the default version bundled with Mavibot -->
+ <dependency>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ </dependency>
<dependency>
<groupId>org.apache.directory.api</groupId>
diff --git a/mavibot-partition/pom.xml b/mavibot-partition/pom.xml
index 253c2f0..2b73ade 100644
--- a/mavibot-partition/pom.xml
+++ b/mavibot-partition/pom.xml
@@ -32,6 +32,12 @@
<artifactId>mavibot</artifactId>
</dependency>
+ <!-- Override the default version bundled with Mavibot -->
+ <dependency>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ </dependency>
+
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>apacheds-core-api</artifactId>
diff --git a/pom.xml b/pom.xml
index 2bebe80..dbf7a16 100644
--- a/pom.xml
+++ b/pom.xml
@@ -54,20 +54,20 @@
<skin.version>1.0.3</skin.version>
<!-- Set versions for depending jars -->
- <ant.version>1.10.8</ant.version>
- <bcprov.version>1.65</bcprov.version>
+ <ant.version>1.10.9</ant.version>
+ <bcprov.version>1.67</bcprov.version>
<commons.cli.version>1.4</commons.cli.version>
<commons.codec.version>1.14</commons.codec.version>
<commons.collections.version>4.4</commons.collections.version>
<commons.daemon.version>1.2.0</commons.daemon.version>
<commons.lang.version>3.9</commons.lang.version>
<commons.net.version>3.6</commons.net.version>
- <commons.pool.version>2.8.0</commons.pool.version>
+ <commons.pool.version>2.8.1</commons.pool.version>
<dnsjava.version>2.1.9</dnsjava.version>
<caffeine.version>2.7.0</caffeine.version>
<findbugs.annotations.version>1.0.0</findbugs.annotations.version>
<forbiddenapis.version>2.6</forbiddenapis.version>
- <jetty.version>9.4.24.v20191120</jetty.version>
+ <jetty.version>9.4.34.v20201102</jetty.version>
<!-- The Jetty bundle exports are using version 9.4.5, not 9.4.5.v20170502... -->
<jetty.bundle.version>9.4.19</jetty.bundle.version>
<junit.version>4.12</junit.version>
@@ -1071,6 +1071,13 @@
<groupId>org.apache.directory.mavibot</groupId>
<artifactId>mavibot</artifactId>
<version>${org.apache.directory.mavibot.version}</version>
+ <!-- Can be removed once we pick up the next Mavibot version -->
+ <exclusions>
+ <exclusion>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<!-- Mina dependencies -->
@@ -1088,6 +1095,13 @@
<artifactId>commons-codec</artifactId>
<version>${commons.codec.version}</version>
</dependency>
+
+ <!-- Can be removed once we pick up the next Mavibot version -->
+ <dependency>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ <version>3.2.2</version>
+ </dependency>
<dependency>
<groupId>org.apache.commons</groupId>
@@ -1265,6 +1279,12 @@
<artifactId>bcprov-jdk15on</artifactId>
<version>${bcprov.version}</version>
</dependency>
+
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-jdk15on</artifactId>
+ <version>${bcprov.version}</version>
+ </dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
@@ -1277,7 +1297,7 @@
<artifactId>annotations</artifactId>
<version>${findbugs.annotations.version}</version>
</dependency>
-
+
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
diff --git a/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/KerberosConfig.java b/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/KerberosConfig.java
index 5237d9c..b3e2e9a 100644
--- a/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/KerberosConfig.java
+++ b/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/KerberosConfig.java
@@ -26,6 +26,8 @@
import javax.security.auth.kerberos.KerberosPrincipal;
import org.apache.directory.server.constants.ServerDNConstants;
+import org.apache.directory.server.kerberos.shared.replay.ReplayCache;
+import org.apache.directory.server.kerberos.shared.replay.ReplayCacheImpl;
import org.apache.directory.shared.kerberos.KerberosUtils;
import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
import org.apache.directory.shared.kerberos.codec.types.PrincipalNameType;
@@ -80,6 +82,9 @@
public static final String[] DEFAULT_ENCRYPTION_TYPES = new String[]
{ "aes128-cts-hmac-sha1-96", "des-cbc-md5", "des3-cbc-sha1-kd" };
+ /** The default ReplayCache type */
+ public static final Class<? extends ReplayCache> DEFAULT_REPLAY_CACHE_TYPE = ReplayCacheImpl.class;
+
/** The primary realm */
private String primaryRealm = KerberosConfig.DEFAULT_REALM;
@@ -119,6 +124,9 @@
/** Whether to verify the body checksum. */
private boolean isBodyChecksumVerified = KerberosConfig.DEFAULT_VERIFY_BODY_CHECKSUM;
+ /** Replay cache implementing class. */
+ private Class<? extends ReplayCache> replayCacheType = KerberosConfig.DEFAULT_REPLAY_CACHE_TYPE;
+
/** The encryption types. */
private Set<EncryptionType> encryptionTypes;
@@ -419,6 +427,18 @@
}
+ public Class<? extends ReplayCache> getReplayCacheType()
+ {
+ return replayCacheType;
+ }
+
+
+ public void setReplayCacheType( Class<? extends ReplayCache> replayCacheType )
+ {
+ this.replayCacheType = replayCacheType;
+ }
+
+
public long getMinimumTicketLifetime()
{
return minimumTicketLifetime;
diff --git a/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/KdcServer.java b/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/KdcServer.java
index cd919da..c2a3696 100644
--- a/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/KdcServer.java
+++ b/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/KdcServer.java
@@ -29,7 +29,6 @@
import org.apache.directory.server.kerberos.protocol.KerberosProtocolHandler;
import org.apache.directory.server.kerberos.protocol.codec.KerberosProtocolCodecFactory;
import org.apache.directory.server.kerberos.shared.replay.ReplayCache;
-import org.apache.directory.server.kerberos.shared.replay.ReplayCacheImpl;
import org.apache.directory.server.kerberos.shared.store.PrincipalStore;
import org.apache.directory.server.protocol.shared.DirectoryBackedService;
import org.apache.directory.server.protocol.shared.transport.TcpTransport;
@@ -89,6 +88,8 @@
this.config = config;
super.setServiceName( SERVICE_NAME );
super.setSearchBaseDn( config.getSearchBaseDn() );
+
+ initReplayCache();
}
@@ -110,10 +111,6 @@
store = new DirectoryPrincipalStore( getDirectoryService(), new Dn( this.getSearchBaseDn() ) );
- LOG.debug( "initializing the kerberos replay cache" );
-
- replayCache = new ReplayCacheImpl( config.getAllowableClockSkew() );
-
// Kerberos can use UDP or TCP
for ( Transport transport : transports )
{
@@ -255,4 +252,36 @@
return sb.toString();
}
+
+ private void initReplayCache()
+ {
+ LOG.debug( "initializing the kerberos replay cache" );
+
+ Class<? extends ReplayCache> clazz = config.getReplayCacheType();
+ if ( clazz == null )
+ {
+ LOG.trace( "Kerberos replay cache is disabled" );
+ return;
+ }
+
+ LOG.debug( "Creating ReplayCache of type {}", clazz.getName() );
+ ReplayCache instance = null;
+ try
+ {
+ try
+ {
+ instance = clazz.getConstructor( Long.TYPE ).newInstance( config.getAllowableClockSkew() );
+ }
+ catch ( NoSuchMethodException e )
+ {
+ instance = clazz.newInstance();
+ }
+ }
+ catch ( Exception e )
+ {
+ LOG.error( "Failed to create the ReplayCache instance. No replay cache will be used!", e );
+ }
+ replayCache = instance;
+ }
+
}
diff --git a/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/TicketGrantingService.java b/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/TicketGrantingService.java
index 1cd8797..54266b9 100644
--- a/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/TicketGrantingService.java
+++ b/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/TicketGrantingService.java
@@ -322,7 +322,7 @@
EncTicketPart encTicketPart = tgt.getEncTicketPart();
EncryptionKey sessionKey = encTicketPart.getKey();
- if ( authenticatorChecksum == null || authenticatorChecksum.getChecksumType() == null
+ if ( authenticatorChecksum.getChecksumType() == null
|| authenticatorChecksum.getChecksumValue() == null || bodyBytes == null )
{
throw new KerberosException( ErrorType.KRB_AP_ERR_INAPP_CKSUM );
diff --git a/protocol-kerberos/src/test/java/org/apache/directory/server/kerberos/protocol/TGSReplayCacheTest.java b/protocol-kerberos/src/test/java/org/apache/directory/server/kerberos/protocol/TGSReplayCacheTest.java
new file mode 100644
index 0000000..2273068
--- /dev/null
+++ b/protocol-kerberos/src/test/java/org/apache/directory/server/kerberos/protocol/TGSReplayCacheTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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.server.kerberos.protocol;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.text.ParseException;
+
+import javax.security.auth.kerberos.KerberosPrincipal;
+
+import org.apache.directory.server.kerberos.KerberosConfig;
+import org.apache.directory.server.kerberos.kdc.KdcServer;
+import org.apache.directory.server.kerberos.protocol.AbstractAuthenticationServiceTest.KrbDummySession;
+import org.apache.directory.server.kerberos.shared.crypto.encryption.CipherTextHandler;
+import org.apache.directory.server.kerberos.shared.replay.ReplayCache;
+import org.apache.directory.shared.kerberos.KerberosTime;
+import org.apache.directory.shared.kerberos.codec.options.KdcOptions;
+import org.apache.directory.shared.kerberos.components.EncTicketPart;
+import org.apache.directory.shared.kerberos.components.EncryptionKey;
+import org.apache.directory.shared.kerberos.components.KdcReq;
+import org.apache.directory.shared.kerberos.components.KdcReqBody;
+import org.apache.directory.shared.kerberos.exceptions.ErrorType;
+import org.apache.directory.shared.kerberos.exceptions.KerberosException;
+import org.apache.directory.shared.kerberos.messages.KrbError;
+import org.apache.directory.shared.kerberos.messages.TgsRep;
+import org.apache.directory.shared.kerberos.messages.Ticket;
+import org.junit.After;
+import org.junit.Test;
+
+/**
+ * Tests for configurable {@link ReplayCache}.
+ */
+public class TGSReplayCacheTest extends AbstractTicketGrantingServiceTest
+{
+ private KdcServer kdcServer;
+ private KerberosProtocolHandler handler;
+
+ /**
+ * Shutdown the Kerberos server
+ */
+ @After
+ public void shutDown()
+ {
+ kdcServer.stop();
+ }
+
+ /**
+ * Tests the replay cache is used by default.
+ */
+ @Test
+ public void testDefaultReplayCache() throws Exception
+ {
+ initKdcServer( new KerberosConfig() );
+
+ KdcReq message = createTgsRequest();
+
+ KrbDummySession session = new KrbDummySession();
+ handler.messageReceived( session, message );
+ assertEquals( "session.getMessage() instanceOf", TgsRep.class, session.getMessage().getClass() );
+
+ handler.messageReceived( session, message );
+ Object msg = session.getMessage();
+ assertEquals( "session.getMessage() instanceOf", KrbError.class, msg.getClass() );
+ KrbError error = (KrbError) msg;
+ assertEquals( "Replay not detected", ErrorType.KRB_AP_ERR_REPEAT, error.getErrorCode() );
+ }
+
+ /**
+ * Tests the replay cache is not used if the type is explicitly set to null.
+ */
+ @Test
+ public void testNullReplayCacheType() throws Exception
+ {
+ KerberosConfig config = new KerberosConfig();
+ config.setReplayCacheType( null );
+ initKdcServer( config );
+
+ KdcReq message = createTgsRequest();
+
+ KrbDummySession session = new KrbDummySession();
+ handler.messageReceived( session, message );
+ assertEquals( "session.getMessage() instanceOf", TgsRep.class, session.getMessage().getClass() );
+
+ handler.messageReceived( session, message );
+ assertEquals( "session.getMessage() instanceOf", TgsRep.class, session.getMessage().getClass() );
+ }
+
+ /**
+ * Tests that custom replay cache can be set.
+ */
+ @Test
+ public void testDummyReplayCacheType() throws Exception
+ {
+ KerberosConfig config = new KerberosConfig();
+ config.setReplayCacheType( DisabledReplayCache.class );
+ initKdcServer( config );
+
+ KdcReq message = createTgsRequest();
+
+ KrbDummySession session = new KrbDummySession();
+ handler.messageReceived( session, message );
+ assertEquals( "session.getMessage() instanceOf", TgsRep.class, session.getMessage().getClass() );
+
+ handler.messageReceived( session, message );
+ assertEquals( "session.getMessage() instanceOf", TgsRep.class, session.getMessage().getClass() );
+
+ assertTrue( "Incorrect cache implementation", DisabledReplayCache.replayTested );
+ }
+
+ private KdcReq createTgsRequest() throws KerberosException, ParseException, Exception
+ {
+ // Get the mutable ticket part.
+ KerberosPrincipal clientPrincipal = new KerberosPrincipal( "hnelson@EXAMPLE.COM" );
+ EncTicketPart encTicketPart = getTicketArchetype( clientPrincipal );
+
+ // Seal the ticket for the server.
+ KerberosPrincipal serverPrincipal = new KerberosPrincipal( "krbtgt/EXAMPLE.COM@EXAMPLE.COM" );
+ String passPhrase = "randomKey";
+ EncryptionKey serverKey = getEncryptionKey( serverPrincipal, passPhrase );
+ Ticket tgt = getTicket( encTicketPart, serverPrincipal, serverKey );
+
+ KdcReqBody kdcReqBody = new KdcReqBody();
+ kdcReqBody.setSName( getPrincipalName( "ldap/ldap.example.com@EXAMPLE.COM" ) );
+ kdcReqBody.setRealm( "EXAMPLE.COM" );
+ kdcReqBody.setEType( kdcServer.getConfig().getEncryptionTypes() );
+ kdcReqBody.setNonce( random.nextInt() );
+ kdcReqBody.setKdcOptions( new KdcOptions() );
+
+ long now = System.currentTimeMillis();
+
+ KerberosTime requestedEndTime = new KerberosTime( now + 1 * KerberosTime.DAY );
+ kdcReqBody.setTill( requestedEndTime );
+
+ KdcReq message = getKdcRequest( tgt, kdcReqBody );
+ return message;
+ }
+
+ /**
+ * Creates a new instance of {@link KdcServer}.
+ */
+ private void initKdcServer( KerberosConfig config )
+ {
+ config.setBodyChecksumVerified( false );
+ kdcServer = new KdcServer( config );
+ handler = new KerberosProtocolHandler( kdcServer, new MapPrincipalStoreImpl() );
+ lockBox = new CipherTextHandler();
+ }
+
+ public static class DisabledReplayCache implements ReplayCache
+ {
+
+ public static volatile boolean replayTested = false;
+
+ @Override
+ public boolean isReplay(KerberosPrincipal serverPrincipal, KerberosPrincipal clientPrincipal, KerberosTime clientTime,
+ int clientMicroSeconds)
+ {
+ replayTested = true;
+ return false;
+ }
+
+ @Override
+ public void save(KerberosPrincipal serverPrincipal, KerberosPrincipal clientPrincipal, KerberosTime clientTime,
+ int clientMicroSeconds)
+ {
+ }
+
+ @Override
+ public void clear()
+ {
+ }
+
+ }
+
+}
diff --git a/server-annotations/src/main/java/org/apache/directory/server/annotations/CreateKdcServer.java b/server-annotations/src/main/java/org/apache/directory/server/annotations/CreateKdcServer.java
index 86c6fb7..eb40d63 100644
--- a/server-annotations/src/main/java/org/apache/directory/server/annotations/CreateKdcServer.java
+++ b/server-annotations/src/main/java/org/apache/directory/server/annotations/CreateKdcServer.java
@@ -28,6 +28,8 @@
import java.lang.annotation.Target;
import org.apache.directory.server.constants.ServerDNConstants;
+import org.apache.directory.server.kerberos.shared.replay.ReplayCache;
+import org.apache.directory.server.kerberos.shared.replay.ReplayCacheImpl;
/**
@@ -83,4 +85,7 @@
/** @return the DN of the search base for finding users and services */
String searchBaseDn() default ServerDNConstants.USER_EXAMPLE_COM_DN;
+
+ /** @return the replay cache implementing class */
+ Class<? extends ReplayCache> replayCacheType() default ReplayCacheImpl.class;
}
\ No newline at end of file
diff --git a/server-annotations/src/main/java/org/apache/directory/server/factory/ServerAnnotationProcessor.java b/server-annotations/src/main/java/org/apache/directory/server/factory/ServerAnnotationProcessor.java
index be226c6..70f736e 100644
--- a/server-annotations/src/main/java/org/apache/directory/server/factory/ServerAnnotationProcessor.java
+++ b/server-annotations/src/main/java/org/apache/directory/server/factory/ServerAnnotationProcessor.java
@@ -408,6 +408,7 @@
kdcConfig.setPrimaryRealm( createKdcServer.primaryRealm() );
kdcConfig.setMaximumTicketLifetime( createKdcServer.maxTicketLifetime() );
kdcConfig.setMaximumRenewableLifetime( createKdcServer.maxRenewableLifetime() );
+ kdcConfig.setReplayCacheType( createKdcServer.replayCacheType() );
KdcServer kdcServer = new KdcServer( kdcConfig );
diff --git a/server-annotations/src/test/java/org/apache/directory/server/factory/CreateKdcServerAnnotationTest.java b/server-annotations/src/test/java/org/apache/directory/server/factory/CreateKdcServerAnnotationTest.java
index fbc4610..dbb6b80 100644
--- a/server-annotations/src/test/java/org/apache/directory/server/factory/CreateKdcServerAnnotationTest.java
+++ b/server-annotations/src/test/java/org/apache/directory/server/factory/CreateKdcServerAnnotationTest.java
@@ -23,6 +23,8 @@
import static org.junit.Assert.assertEquals;
+import javax.security.auth.kerberos.KerberosPrincipal;
+
import org.apache.directory.api.util.FileUtils;
import org.apache.directory.server.annotations.CreateKdcServer;
import org.apache.directory.server.annotations.CreateTransport;
@@ -31,6 +33,8 @@
import org.apache.directory.server.core.factory.DSAnnotationProcessor;
import org.apache.directory.server.kerberos.KerberosConfig;
import org.apache.directory.server.kerberos.kdc.KdcServer;
+import org.apache.directory.server.kerberos.shared.replay.ReplayCache;
+import org.apache.directory.shared.kerberos.KerberosTime;
import org.apache.mina.util.AvailablePortFinder;
import org.junit.Test;
@@ -47,6 +51,7 @@
kdcPrincipal = "krbtgt/apache.org@apache.org",
maxTicketLifetime = 1000,
maxRenewableLifetime = 2000,
+ replayCacheType = DisabledReplayCache.class,
transports =
{
@CreateTransport(protocol = "TCP"),
@@ -69,6 +74,7 @@
assertEquals( "krbtgt/apache.org@apache.org", config.getServicePrincipal().getName() );
assertEquals( 1000, config.getMaximumTicketLifetime() );
assertEquals( 2000, config.getMaximumRenewableLifetime() );
+ assertEquals( DisabledReplayCache.class, config.getReplayCacheType() );
server.stop();
directoryService.shutdown();
@@ -101,11 +107,38 @@
assertEquals( "krbtgt/apache.org@apache.org", config.getServicePrincipal().getName() );
assertEquals( 1000, config.getMaximumTicketLifetime() );
assertEquals( 2000, config.getMaximumRenewableLifetime() );
+ assertEquals( KerberosConfig.DEFAULT_REPLAY_CACHE_TYPE, config.getReplayCacheType() );
server.stop();
directoryService.shutdown();
FileUtils.deleteDirectory( directoryService.getInstanceLayout().getInstanceDirectory() );
}
-
+
+ /**
+ * Empty {@link ReplayCache} implementation which doesn't cache.
+ */
+ public static class DisabledReplayCache implements ReplayCache
+ {
+
+ @Override
+ public boolean isReplay(KerberosPrincipal serverPrincipal, KerberosPrincipal clientPrincipal, KerberosTime clientTime,
+ int clientMicroSeconds)
+ {
+ return false;
+ }
+
+ @Override
+ public void save(KerberosPrincipal serverPrincipal, KerberosPrincipal clientPrincipal, KerberosTime clientTime,
+ int clientMicroSeconds)
+ {
+ }
+
+ @Override
+ public void clear()
+ {
+ }
+
+ }
+
}
diff --git a/service/pom.xml b/service/pom.xml
index 856b264..c438aaf 100644
--- a/service/pom.xml
+++ b/service/pom.xml
@@ -108,10 +108,11 @@
<configuration>
<filters>
<filter>
- <artifact>org.bouncycastle:bcprov-jdk15on</artifact>
+ <artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
+ <exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
diff --git a/service/src/test/java/org/apache/directory/server/UberJarMainTest.java b/service/src/test/java/org/apache/directory/server/UberJarMainTest.java
index 5c1c3af..0cb2210 100644
--- a/service/src/test/java/org/apache/directory/server/UberJarMainTest.java
+++ b/service/src/test/java/org/apache/directory/server/UberJarMainTest.java
@@ -35,6 +35,8 @@
import java.util.Locale;
import java.util.TimeZone;
+import javax.security.auth.x500.X500Principal;
+
import org.apache.directory.api.ldap.codec.api.SchemaBinaryAttributeDetector;
import org.apache.directory.api.ldap.model.cursor.EntryCursor;
import org.apache.directory.api.ldap.model.entry.DefaultEntry;
@@ -44,8 +46,6 @@
import org.apache.directory.api.ldap.model.exception.LdapException;
import org.apache.directory.api.ldap.model.message.SearchScope;
import org.apache.directory.api.ldap.model.name.Dn;
-import org.apache.directory.api.ldap.model.schema.ObjectClass;
-import org.apache.directory.api.ldap.model.schema.registries.Schema;
import org.apache.directory.api.util.Network;
import org.apache.directory.ldap.client.api.LdapConnection;
import org.apache.directory.ldap.client.api.LdapConnectionConfig;
@@ -57,11 +57,7 @@
import org.junit.Before;
import org.junit.Test;
-import sun.security.x509.X500Name;
-
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
/**
@@ -76,10 +72,10 @@
/** The instance directory */
private File instanceDirectory;
-
+
/** The UberjarMain */
private UberjarMain uberjarMain;
-
+
private KeyStore keyStore;
@Before
@@ -98,17 +94,16 @@
// Creating the UberjarMain
uberjarMain = new UberjarMain();
-
+
try
{
// Create a temporary keystore, be sure to remove it when exiting the test
File keyStoreFile = File.createTempFile( "testStore", "ks" );
keyStoreFile.deleteOnExit();
-
keyStore = KeyStore.getInstance( KeyStore.getDefaultType() );
char[] keyStorePassword = "secret".toCharArray();
-
+
try ( InputStream keyStoreData = new FileInputStream( keyStoreFile ) )
{
keyStore.load( null, keyStorePassword );
@@ -117,16 +112,17 @@
// Generate the asymmetric keys, using EC algorithm
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( "EC" );
KeyPair keyPair = keyPairGenerator.generateKeyPair();
-
+
// Generate the subject's name
- @SuppressWarnings("restriction")
- X500Name owner = new X500Name( "apacheds", "directory", "apache", "US" );
+ 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 } );
-
+ 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 );
@@ -134,12 +130,12 @@
}
catch ( Exception e )
{
-
+
}
}
-
+
@After
public void delete() throws Exception
{
@@ -148,8 +144,8 @@
uberjarMain.stop();
}
}
-
-
+
+
private LdapConnection createConnection() throws LdapException, UnknownHostException
{
LdapConnectionConfig configuration = new LdapConnectionConfig();
@@ -164,11 +160,11 @@
// Binding on the connection
connection.bind();
-
+
return connection;
}
-
-
+
+
private Thread createServer()
{
// First start the server to initialize the example partition
@@ -180,7 +176,7 @@
public void run()
{
LdapConnection connection = null;
-
+
try
{
// Creating a connection on the created server
@@ -188,7 +184,7 @@
// Looking for the Root DSE entry
Entry rootDseEntry = connection.lookup( Dn.ROOT_DSE );
-
+
if ( rootDseEntry == null )
{
// This isn't good
@@ -226,51 +222,35 @@
*/
@Test
public void nisTest() throws Exception
- {
+ {
// First start the server to initialize the example partition
uberjarMain.start( instanceDirectory.toString() );
-
+
// Creating a separate thread for the connection verification
Thread connectionVerificationThread = new Thread()
{
public void run()
{
LdapConnection connection = null;
-
+
try
{
// Creating a connection on the created server
connection = createConnection();
- connection.setTimeOut( 0L );
-
- connection.modify( "cn=nis,ou=schema",
- new DefaultModification(
+
+ connection.modify( "cn=nis,ou=schema",
+ new DefaultModification(
ModificationOperation.REPLACE_ATTRIBUTE, "m-disabled", "FALSE" ) );
-
- // Ok, now try to fetch the NIS schema elements
- Entry nisSchema = connection.lookup( "cn=nis,ou=schema" );
-
- assertEquals( "FALSE", nisSchema.get( "m-disabled" ).getString() );
-
- Entry posixAccount = connection.lookup( "m-oid=1.3.6.1.1.1.2.0,ou=objectClasses,cn=nis,ou=schema" );
-
- Throwable exception = connection.exceptionCaught();
- assertNotNull( exception );
-
- if ( exception != null )
- {
- System.out.println( exception.getMessage() );
- }
-
// Reload the schema in order to be able to deal with NIS elements
connection.loadSchema();
-
- posixAccount = connection.lookup( "m-oid=1.3.6.1.1.1.2.0,ou=objectClasses,cn=nis,ou=schema" );
-
- exception = connection.exceptionCaught();
-
- assertNull( exception );
+
+ // Ok, now try to fetch the NIS schema elements
+ Entry nisSchema = connection.lookup( "cn=nis,ou=schema" );
+
+ assertEquals( "FALSE", nisSchema.get( "m-disabled" ).getString() );
+
+ Entry posixAccount = connection.lookup( "m-oid=1.3.6.1.1.1.2.0,ou=objectClasses,cn=nis,ou=schema" );
if ( posixAccount == null )
{
@@ -316,9 +296,9 @@
*/
@Test
public void serviceInstanceTest() throws Exception
- {
+ {
Thread connectionVerificationThread = createServer();
-
+
// Starting the connection verification thread
// and waiting for the termination of it
connectionVerificationThread.start();
@@ -329,15 +309,15 @@
{
fail();
}
-
+
// Stop the server
uberjarMain.stop();
// Restart the server
uberjarMain.start( instanceDirectory.toString() );
-
+
LdapConnection connection = null;
-
+
try
{
// Creating a connection on the created server
@@ -345,18 +325,18 @@
// Looking for the Root DSE entry
Entry rootDseEntry = connection.lookup( Dn.ROOT_DSE );
-
+
Entry nisSchema = connection.lookup( "cn=nis,ou=schema" );
-
+
System.out.println( "Before nis anabling" );
System.out.println( nisSchema );
Entry nisObjectClass = connection.lookup( "ou=objectClasses,cn=nis,ou=schema" );
System.out.println( nisObjectClass );
-
+
Entry posixAccount = connection.lookup( "m-oid=1.3.6.1.1.1.2.0,ou=objectClasses,cn=nis,ou=schema" );
-
+
System.out.println( "posixAccount : " + posixAccount );
if ( rootDseEntry == null )
@@ -392,10 +372,10 @@
*/
@Test
public void repairTest() throws Exception
- {
+ {
// First start the server to initialize the example partition
Thread connectionVerificationThread = createServer();
-
+
// Starting the connection verification thread
// and waiting for the termination of it
connectionVerificationThread.start();
@@ -406,7 +386,7 @@
{
fail();
}
-
+
// Add a few entries to create a more complex hierarchy
// We will have :
// dc=example,dc=com
@@ -423,137 +403,125 @@
// ou=groups
// cn=users
LdapConnection connection = createConnection();
-
+
// First level
- Entry people = new DefaultEntry(
+ Entry people = new DefaultEntry(
"ou=People,dc=example,dc=com",
"objectClass: organizationalUnit",
"objectClass: top",
- "ou: People"
- );
-
+ "ou: People" );
+
connection.add( people );
-
- Entry groups = new DefaultEntry(
+
+ Entry groups = new DefaultEntry(
"ou=Groups,dc=example,dc=com",
"objectClass: organizationalUnit",
"objectClass: top",
- "ou: Groups"
- );
-
+ "ou: Groups" );
+
connection.add( groups );
-
+
// Second level
- Entry committers = new DefaultEntry(
+ Entry committers = new DefaultEntry(
"ou=Committers,ou=people,dc=example,dc=com",
"objectClass: organizationalUnit",
"objectClass: top",
- "ou: Committers"
- );
+ "ou: Committers" );
connection.add( committers );
- Entry pmcs = new DefaultEntry(
+ Entry pmcs = new DefaultEntry(
"ou=Pmcs,ou=people,dc=example,dc=com",
"objectClass: organizationalUnit",
"objectClass: top",
- "ou: Pmcs"
- );
+ "ou: Pmcs" );
connection.add( pmcs );
- Entry users = new DefaultEntry(
+ Entry users = new DefaultEntry(
"ou=Users,ou=people,dc=example,dc=com",
"objectClass: organizationalUnit",
"objectClass: top",
- "ou: Users"
- );
+ "ou: Users" );
connection.add( users );
// Third level, committers
- Entry emmanuelCommitter = new DefaultEntry(
+ Entry emmanuelCommitter = new DefaultEntry(
"cn=emmanuel,ou=Committers,ou=people,dc=example,dc=com",
"objectClass: person",
"objectClass: top",
"cn: emmanuel",
- "sn: Emmanuel Lecharny"
- );
+ "sn: Emmanuel Lecharny" );
connection.add( emmanuelCommitter );
- Entry kiranCommitter = new DefaultEntry(
+ Entry kiranCommitter = new DefaultEntry(
"cn=kiran,ou=Committers,ou=people,dc=example,dc=com",
"objectClass: person",
"objectClass: top",
"cn: kiran",
- "sn: Kiran Ayyagari"
- );
+ "sn: Kiran Ayyagari" );
connection.add( kiranCommitter );
- Entry stefanCommitter = new DefaultEntry(
+ Entry stefanCommitter = new DefaultEntry(
"cn=stefan,ou=Committers,ou=people,dc=example,dc=com",
"objectClass: person",
"objectClass: top",
"cn: stefan",
- "sn: Stefan Seelmann"
- );
+ "sn: Stefan Seelmann" );
connection.add( stefanCommitter );
-
- Entry radovanCommitter = new DefaultEntry(
+
+ Entry radovanCommitter = new DefaultEntry(
"cn=radovan,ou=Committers,ou=people,dc=example,dc=com",
"objectClass: person",
"objectClass: top",
"cn: radovan",
- "sn: Radovan Semancik"
- );
+ "sn: Radovan Semancik" );
connection.add( radovanCommitter );
// Third level, PMCs
- Entry emmanuelPmc = new DefaultEntry(
+ Entry emmanuelPmc = new DefaultEntry(
"cn=emmanuel,ou=Pmcs,ou=people,dc=example,dc=com",
"objectClass: person",
"objectClass: top",
"cn: emmanuel",
- "sn: Emmanuel Lecharny"
- );
+ "sn: Emmanuel Lecharny" );
connection.add( emmanuelPmc );
- Entry kiranPmc = new DefaultEntry(
+ Entry kiranPmc = new DefaultEntry(
"cn=kiran,ou=Pmcs,ou=people,dc=example,dc=com",
"objectClass: person",
"objectClass: top",
"cn: kiran",
- "sn: Kiran Ayyagari"
- );
+ "sn: Kiran Ayyagari" );
connection.add( kiranPmc );
- Entry stefanPmc = new DefaultEntry(
+ Entry stefanPmc = new DefaultEntry(
"cn=stefan,ou=Pmcs,ou=people,dc=example,dc=com",
"objectClass: person",
"objectClass: top",
"cn: stefan",
- "sn: Stefan Seelmann"
- );
+ "sn: Stefan Seelmann" );
connection.add( stefanPmc );
-
+
// Now, check that we have 13 entries
int entryCount = 0;
-
- EntryCursor cursor = connection.search( "dc=example, dc=com","(ObjectClass=*)", SearchScope.SUBTREE, "*" );
-
+
+ EntryCursor cursor = connection.search( "dc=example, dc=com", "(ObjectClass=*)", SearchScope.SUBTREE, "*" );
+
while ( cursor.next() )
{
cursor.get();
entryCount++;
}
-
+
assertEquals( 13, entryCount );
// Stop the server
@@ -564,7 +532,7 @@
// And restart it
connectionVerificationThread = createServer();
-
+
// Starting the connection verification thread
// and waiting for the termination of it
connectionVerificationThread.start();
@@ -580,15 +548,15 @@
connection = createConnection();
entryCount = 0;
-
- cursor = connection.search( "dc=example, dc=com","(ObjectClass=*)", SearchScope.SUBTREE, "*" );
-
+
+ cursor = connection.search( "dc=example, dc=com", "(ObjectClass=*)", SearchScope.SUBTREE, "*" );
+
while ( cursor.next() )
{
cursor.get();
entryCount++;
}
-
+
assertEquals( 13, entryCount );
}
}
diff --git a/test-framework/src/main/java/org/apache/directory/server/core/integ/AbstractLdapTestUnit.java b/test-framework/src/main/java/org/apache/directory/server/core/integ/AbstractLdapTestUnit.java
index 9d290c6..b869e8c 100644
--- a/test-framework/src/main/java/org/apache/directory/server/core/integ/AbstractLdapTestUnit.java
+++ b/test-framework/src/main/java/org/apache/directory/server/core/integ/AbstractLdapTestUnit.java
@@ -30,20 +30,19 @@
import java.security.KeyStore;
import java.security.cert.X509Certificate;
+import javax.security.auth.x500.X500Principal;
+
import org.apache.directory.server.core.api.DirectoryService;
import org.apache.directory.server.core.security.CertificateUtil;
import org.apache.directory.server.kerberos.kdc.KdcServer;
import org.apache.directory.server.ldap.LdapServer;
-import sun.security.x509.X500Name;
-
/**
* An abstract class created to hold common elements.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
-@SuppressWarnings("restriction")
public abstract class AbstractLdapTestUnit
{
/** The used DirectoryService instance */
@@ -106,10 +105,10 @@
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// Generate the subject's name
- X500Name subject = new X500Name( subjectDn, "directory", "apache", "US" );
+ X500Principal subject = new X500Principal( "CN=" + subjectDn + ",OU=directory,O=apache,C=US" );
// Generate the issuer's name
- X500Name issuer = new X500Name( issuerDn, "directory", "apache", "US" );
+ X500Principal issuer = new X500Principal( "CN=" + issuerDn + ",OU=directory,O=apache,C=US" );
// Create the self-signed certificate
X509Certificate certificate = CertificateUtil.generateCertificate( subject, issuer, keyPair, days, algorithm );