You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ka...@apache.org on 2010/09/16 20:46:06 UTC
svn commit: r997874 - in /directory:
apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/bind/SaslBindIT.java
shared/trunk/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java
Author: kayyagari
Date: Thu Sep 16 18:46:06 2010
New Revision: 997874
URL: http://svn.apache.org/viewvc?rev=997874&view=rev
Log:
o added SASL GSSAPI mechanism support
o added a test
o some code cleanup
Modified:
directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/bind/SaslBindIT.java
directory/shared/trunk/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java
Modified: directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/bind/SaslBindIT.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/bind/SaslBindIT.java?rev=997874&r1=997873&r2=997874&view=diff
==============================================================================
--- directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/bind/SaslBindIT.java (original)
+++ directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/operations/bind/SaslBindIT.java Thu Sep 16 18:46:06 2010
@@ -30,6 +30,8 @@ import java.nio.ByteBuffer;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
@@ -37,6 +39,7 @@ import org.apache.commons.lang.ArrayUtil
import org.apache.commons.net.SocketClient;
import org.apache.directory.ldap.client.api.LdapConnection;
import org.apache.directory.ldap.client.api.LdapNetworkConnection;
+import org.apache.directory.server.annotations.CreateKdcServer;
import org.apache.directory.server.annotations.CreateLdapServer;
import org.apache.directory.server.annotations.CreateTransport;
import org.apache.directory.server.annotations.SaslMechanism;
@@ -48,14 +51,18 @@ import org.apache.directory.server.core.
import org.apache.directory.server.core.integ.AbstractLdapTestUnit;
import org.apache.directory.server.core.integ.FrameworkRunner;
import org.apache.directory.server.core.kerberos.KeyDerivationInterceptor;
+import org.apache.directory.server.kerberos.shared.store.KerberosAttribute;
import org.apache.directory.server.ldap.handlers.bind.cramMD5.CramMd5MechanismHandler;
import org.apache.directory.server.ldap.handlers.bind.digestMD5.DigestMd5MechanismHandler;
import org.apache.directory.server.ldap.handlers.bind.gssapi.GssapiMechanismHandler;
import org.apache.directory.server.ldap.handlers.bind.ntlm.NtlmMechanismHandler;
import org.apache.directory.server.ldap.handlers.bind.plain.PlainMechanismHandler;
import org.apache.directory.server.ldap.handlers.extended.StoredProcedureExtendedOperationHandler;
+import org.apache.directory.shared.ldap.constants.SchemaConstants;
import org.apache.directory.shared.ldap.constants.SupportedSaslMechanisms;
+import org.apache.directory.shared.ldap.entry.DefaultEntry;
import org.apache.directory.shared.ldap.entry.Entry;
+import org.apache.directory.shared.ldap.exception.LdapException;
import org.apache.directory.shared.ldap.message.BindRequest;
import org.apache.directory.shared.ldap.message.BindRequestImpl;
import org.apache.directory.shared.ldap.message.BindResponse;
@@ -96,7 +103,38 @@ import org.slf4j.LoggerFactory;
"krb5PrincipalName: hnelson@EXAMPLE.COM",
"krb5KeyVersionNumber: 0",
"cn: Horatio Nelson",
- "sn: Nelson" })
+ "sn: Nelson",
+
+ // krbtgt
+ "dn: uid=krbtgt,ou=users,dc=example,dc=com",
+ "objectClass: inetOrgPerson",
+ "objectClass: organizationalPerson",
+ "objectClass: person",
+ "objectClass: krb5principal",
+ "objectClass: krb5kdcentry",
+ "objectClass: top",
+ "uid: krbtgt",
+ "userPassword: secret",
+ "krb5PrincipalName: krbtgt/EXAMPLE.COM@EXAMPLE.COM",
+ "krb5KeyVersionNumber: 0",
+ "cn: KDC Service",
+ "sn: Service",
+
+ // ldap
+ "dn: uid=ldap,ou=users,dc=example,dc=com",
+ "objectClass: inetOrgPerson",
+ "objectClass: organizationalPerson",
+ "objectClass: person",
+ "objectClass: krb5principal",
+ "objectClass: krb5kdcentry",
+ "objectClass: top",
+ "uid: ldap",
+ "userPassword: randall",
+ "krb5PrincipalName: ldap/localhost@EXAMPLE.COM",
+ "krb5KeyVersionNumber: 0",
+ "cn: LDAP Service",
+ "sn: Service"
+ })
@CreateDS(allowAnonAccess = false, name = "SaslBindIT-class", partitions =
{ @CreatePartition(name = "example", suffix = "dc=example,dc=com", contextEntry = @ContextEntry(entryLdif = "dn: dc=example,dc=com\n"
+ "dc: example\n" + "objectClass: top\n" + "objectClass: domain\n\n"), indexes =
@@ -104,7 +142,7 @@ import org.slf4j.LoggerFactory;
additionalInterceptors = { KeyDerivationInterceptor.class }
)
@CreateLdapServer(transports =
- { @CreateTransport(protocol = "LDAP") }, saslHost = "localhost", saslMechanisms =
+ { @CreateTransport(protocol = "LDAP") }, saslHost = "localhost", saslPrincipal="ldap/localhost@EXAMPLE.COM", saslMechanisms =
{ @SaslMechanism(name = SupportedSaslMechanisms.PLAIN, implClass = PlainMechanismHandler.class),
@SaslMechanism(name = SupportedSaslMechanisms.CRAM_MD5, implClass = CramMd5MechanismHandler.class),
@SaslMechanism(name = SupportedSaslMechanisms.DIGEST_MD5, implClass = DigestMd5MechanismHandler.class),
@@ -112,6 +150,12 @@ additionalInterceptors = { KeyDerivation
@SaslMechanism(name = SupportedSaslMechanisms.NTLM, implClass = NtlmMechanismHandler.class),
@SaslMechanism(name = SupportedSaslMechanisms.GSS_SPNEGO, implClass = NtlmMechanismHandler.class) }, extendedOpHandlers =
{ StoredProcedureExtendedOperationHandler.class }, ntlmProvider = BogusNtlmProvider.class)
+@CreateKdcServer (
+ transports =
+ {
+ @CreateTransport( protocol = "UDP", port = 6088 ),
+ @CreateTransport( protocol = "TCP", port = 6088 )
+ })
public class SaslBindIT extends AbstractLdapTestUnit
{
@@ -267,7 +311,6 @@ public class SaslBindIT extends Abstract
{
DN userDn = new DN( "uid=hnelson,ou=users,dc=example,dc=com" );
LdapNetworkConnection connection = new LdapNetworkConnection( "localhost", ldapServer.getPort() );
- connection.setTimeOut( Integer.MAX_VALUE );
BindResponse resp = connection.bindDigestMd5( userDn.getName(), "secret", null, ldapServer.getSaslRealms()
.get( 0 ) );
@@ -286,6 +329,32 @@ public class SaslBindIT extends Abstract
/**
+ * GSSAPI test
+ */
+ @Test
+ public void testSaslGssApiBind() throws Exception
+ {
+ try
+ {
+ DN userDn = new DN( "uid=hnelson,ou=users,dc=example,dc=com" );
+ LdapNetworkConnection connection = new LdapNetworkConnection( "localhost", ldapServer.getPort() );
+
+ BindResponse resp = connection.bindGssApi( userDn.getName(), "secret", ldapServer.getSaslRealms().get( 0 ).toUpperCase(), "localhost", 6088 );
+ assertEquals( ResultCodeEnum.SUCCESS, resp.getLdapResult().getResultCode() );
+
+ Entry entry = connection.lookup( userDn );
+ assertEquals( "hnelson", entry.get( "uid" ).getString() );
+
+ connection.close();
+ }
+ catch ( Exception e )
+ {
+ fail( "Should not have caught exception." );
+ }
+ }
+
+
+ /**
* Tests to make sure DIGEST-MD5 binds below the RootDSE fail if the realm is bad.
*/
@Test
@@ -295,7 +364,6 @@ public class SaslBindIT extends Abstract
{
DN userDn = new DN( "uid=hnelson,ou=users,dc=example,dc=com" );
LdapNetworkConnection connection = new LdapNetworkConnection( "localhost", ldapServer.getPort() );
- connection.setTimeOut( Integer.MAX_VALUE );
BindResponse resp = connection.bindDigestMd5( userDn.getName(), "secret", null, "badrealm.com" );
assertEquals( ResultCodeEnum.INVALID_CREDENTIALS, resp.getLdapResult().getResultCode() );
@@ -320,7 +388,6 @@ public class SaslBindIT extends Abstract
{
DN userDn = new DN( "uid=hnelson,ou=users,dc=example,dc=com" );
LdapNetworkConnection connection = new LdapNetworkConnection( "localhost", ldapServer.getPort() );
- connection.setTimeOut( Integer.MAX_VALUE );
BindResponse resp = connection.bindDigestMd5( userDn.getName(), "badsecret", null, ldapServer
.getSaslRealms().get( 0 ) );
@@ -518,4 +585,20 @@ public class SaslBindIT extends Abstract
return provider;
}
+
+ ////////////////////////
+ protected Entry getPrincipalAttributes( String dn, String sn, String cn, String uid, String userPassword, String principal ) throws LdapException
+ {
+ Entry entry = new DefaultEntry( new DN( dn ) );
+ entry.add( SchemaConstants.OBJECT_CLASS_AT, "person", "inetOrgPerson", "krb5principal", "krb5kdcentry" );
+ entry.add( SchemaConstants.CN_AT, cn );
+ entry.add( SchemaConstants.SN_AT, sn );
+ entry.add( SchemaConstants.UID_AT, uid );
+ entry.add( SchemaConstants.USER_PASSWORD_AT, userPassword );
+ entry.add( KerberosAttribute.KRB5_PRINCIPAL_NAME_AT, principal );
+ entry.add( KerberosAttribute.KRB5_KEY_VERSION_NUMBER_AT, "0" );
+
+ return entry;
+ }
+
}
Modified: directory/shared/trunk/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java?rev=997874&r1=997873&r2=997874&view=diff
==============================================================================
--- directory/shared/trunk/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java (original)
+++ directory/shared/trunk/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java Thu Sep 16 18:46:06 2010
@@ -21,9 +21,11 @@ package org.apache.directory.ldap.client
import java.io.File;
+import java.io.FileWriter;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
+import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -37,6 +39,9 @@ import java.util.concurrent.atomic.Atomi
import java.util.concurrent.atomic.AtomicInteger;
import javax.net.ssl.SSLContext;
+import javax.security.auth.Subject;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.LoginContext;
import javax.security.sasl.Sasl;
import javax.security.sasl.SaslClient;
@@ -1205,7 +1210,8 @@ public class LdapNetworkConnection exten
throws LdapException,
IOException
{
- BindFuture bindFuture = bindSasl( name, credentials, SupportedSaslMechanisms.DIGEST_MD5, authzId, realmName, ctrls );
+ BindFuture bindFuture = bindSasl( name, credentials, SupportedSaslMechanisms.DIGEST_MD5, authzId, realmName,
+ ctrls );
try
{
@@ -1235,6 +1241,64 @@ public class LdapNetworkConnection exten
/**
+ * @see #bindGssApi(String, byte[], String, String, int, Control...)
+ */
+ public BindResponse bindGssApi( String name, String credentials, String realmName, String kdcHost, int kdcPort, Control... ctrls )
+ throws LdapException, IOException
+ {
+ return bindGssApi( name, StringTools.getBytesUtf8( credentials ), realmName, kdcHost, kdcPort, ctrls );
+ }
+
+
+ /**
+ * bind to the ldap server using GSSAPI sasl mechanism
+ *
+ * @param name the DN of the user entry
+ * @param credentials the credentials of the user
+ * @param realmName name of the kerberos realm in which the given user entry is present
+ * @param kdcHost the host name of the KDC server
+ * @param kdcPort the port of the KDC server
+ * @param ctrls controls to be passed along with the bind request
+ * @return response of this bind operation
+ * @throws LdapException
+ * @throws IOException
+ */
+ public BindResponse bindGssApi( String name, byte[] credentials, String realmName, String kdcHost, int kdcPort, Control... ctrls )
+ throws LdapException, IOException
+ {
+ BindRequest bindReq = createBindRequest( name, credentials, SupportedSaslMechanisms.GSSAPI, ctrls );
+
+ String krbConfPath = createKrbConfFile( realmName, kdcHost, kdcPort );
+ System.setProperty( "java.security.krb5.conf", krbConfPath );
+
+ Configuration.setConfiguration( new Krb5LoginConfiguration() );
+ System.setProperty( "javax.security.auth.useSubjectCredsOnly", "true" );
+
+ final SaslRequest saslReq = new SaslRequest( bindReq );
+
+ try
+ {
+ LoginContext lc = new LoginContext( "ldapnetworkconnection", new SaslCallbackHandler( saslReq ) );
+ lc.login();
+
+ BindFuture future = ( BindFuture ) Subject.doAs( lc.getSubject(), new PrivilegedExceptionAction<Object>()
+ {
+ public Object run() throws Exception
+ {
+ return bindSasl( saslReq );
+ }
+ } );
+
+ return future.get();
+ }
+ catch ( Exception e )
+ {
+ throw new LdapException( e );
+ }
+ }
+
+
+ /**
* {@inheritDoc}
*/
public Cursor<Response> search( DN baseDn, String filter, SearchScope scope, String... attributes )
@@ -3364,10 +3428,7 @@ public class LdapNetworkConnection exten
Control... ctrls )
throws LdapException, IOException
{
- BindRequest bindReq = createBindRequest( name, credentials );
- bindReq.setSaslMechanism( saslMech );
- bindReq.setSimple( false );
- bindReq.addAllControls( ctrls );
+ BindRequest bindReq = createBindRequest( name, credentials, saslMech, ctrls );
SaslRequest saslReq = new SaslRequest( bindReq );
saslReq.setRealmName( realmName );
@@ -3507,4 +3568,59 @@ public class LdapNetworkConnection exten
throw new LdapException( TIME_OUT_ERROR );
}
}
+
+
+ /**
+ * method to write the kerberos config in the standard MIT kerberos format
+ *
+ * This is required cause the JGSS api is not able to recognize the port value set
+ * in the system property java.security.krb5.kdc this issue makes it impossible
+ * to set a kdc running non standard port(other than 88)
+ *
+ * e.g localhost:6088
+ *
+ * [libdefaults]
+ * default_realm = EXAMPLE.COM
+ *
+ * [realms]
+ * EXAMPLE.COM = {
+ * kdc = localhost:6088
+ * }
+ *
+ * @return the full path of the config file
+ */
+ private String createKrbConfFile( String realmName, String kdcHost, int kdcPort ) throws IOException
+ {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append( "[libdefaults]" )
+ .append( "\n\t" );
+ sb.append( "default_realm = " )
+ .append( realmName )
+ .append( "\n" );
+
+ sb.append( "[realms]" )
+ .append( "\n\t" );
+
+ sb.append( realmName )
+ .append( " = {" )
+ .append( "\n\t\t" );
+ sb.append( "kdc = " )
+ .append( kdcHost )
+ .append( ":" )
+ .append( kdcPort )
+ .append( "\n\t}\n" );;
+
+ File krb5Conf = File.createTempFile( "client-api-krb5", ".conf" );
+ krb5Conf.deleteOnExit();
+ FileWriter fw = new FileWriter( krb5Conf );
+ fw.write( sb.toString() );
+ fw.close();
+
+ String krbConfPath = krb5Conf.getAbsolutePath();
+
+ LOG.debug( "krb config file created at {}", krbConfPath );
+
+ return krbConfPath;
+ }
}