blob: 7b3bd4eb5dfde0f290cfe7aec09c2c38da7326dc [file] [log] [blame]
/*
* 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;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
import javax.naming.Context;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import org.apache.directory.server.core.configuration.InterceptorConfiguration;
import org.apache.directory.server.core.configuration.MutableInterceptorConfiguration;
import org.apache.directory.server.core.configuration.MutablePartitionConfiguration;
import org.apache.directory.server.core.configuration.PartitionConfiguration;
import org.apache.directory.server.core.kerberos.KeyDerivationService;
import org.apache.directory.server.kerberos.kdc.KdcConfiguration;
import org.apache.directory.server.kerberos.shared.store.KerberosAttribute;
import org.apache.directory.server.ldap.LdapConfiguration;
import org.apache.directory.server.unit.AbstractServerTest;
import org.apache.directory.shared.ldap.message.AttributeImpl;
import org.apache.directory.shared.ldap.message.AttributesImpl;
import org.apache.directory.shared.ldap.message.ModificationItemImpl;
import org.apache.mina.util.AvailablePortFinder;
/**
* An {@link AbstractServerTest} testing SASL GSSAPI authentication
* and security layer negotiation. These tests require both the LDAP
* and the Kerberos protocol. As with any "three-headed" Kerberos
* scenario, there are 3 principals: 1 for the test user, 1 for the
* Kerberos ticket-granting service (TGS), and 1 for the LDAP service.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
* @version $Rev$, $Date$
*/
public class SaslGssapiBindITest extends AbstractServerTest
{
private DirContext ctx = null;
/**
* Creates a new instance of SaslGssapiBindTest and sets JAAS system properties
* for the KDC and realm, so we don't have to rely on external configuration.
*/
public SaslGssapiBindITest()
{
System.setProperty( "java.security.krb5.realm", "EXAMPLE.COM" );
System.setProperty( "java.security.krb5.kdc", "localhost" );
}
/**
* Set up a partition for EXAMPLE.COM and add user and service principals to
* test authentication with.
*/
public void setUp() throws Exception
{
configuration.setAllowAnonymousAccess( false );
LdapConfiguration ldapConfig = configuration.getLdapConfiguration();
ldapConfig.setSaslHost( "localhost" );
ldapConfig.setSaslPrincipal( "ldap/localhost@EXAMPLE.COM" );
KdcConfiguration kdcConfig = configuration.getKdcConfiguration();
kdcConfig.setEnabled( true );
kdcConfig.setSearchBaseDn( "ou=users,dc=example,dc=com" );
kdcConfig.setSecurityAuthentication( "simple" );
kdcConfig.setSecurityCredentials( "secret" );
kdcConfig.setSecurityPrincipal( "uid=admin,ou=system" );
Attributes attrs;
Set<PartitionConfiguration> pcfgs = new HashSet<PartitionConfiguration>();
MutablePartitionConfiguration pcfg;
// Add partition 'example'
pcfg = new MutablePartitionConfiguration();
pcfg.setId( "example" );
pcfg.setSuffix( "dc=example,dc=com" );
Set<Object> indexedAttrs = new HashSet<Object>();
indexedAttrs.add( "ou" );
indexedAttrs.add( "dc" );
indexedAttrs.add( "objectClass" );
pcfg.setIndexedAttributes( indexedAttrs );
attrs = new AttributesImpl( true );
Attribute attr = new AttributeImpl( "objectClass" );
attr.add( "top" );
attr.add( "domain" );
attrs.put( attr );
attr = new AttributeImpl( "dc" );
attr.add( "example" );
attrs.put( attr );
pcfg.setContextEntry( attrs );
pcfgs.add( pcfg );
configuration.setPartitionConfigurations( pcfgs );
MutableInterceptorConfiguration interceptorCfg = new MutableInterceptorConfiguration();
List<InterceptorConfiguration> list = configuration.getInterceptorConfigurations();
interceptorCfg.setName( KeyDerivationService.NAME );
interceptorCfg.setInterceptorClassName( "org.apache.directory.server.core.kerberos.KeyDerivationService" );
list.add( interceptorCfg );
configuration.setInterceptorConfigurations( list );
doDelete( configuration.getWorkingDirectory() );
port = AvailablePortFinder.getNextAvailable( 1024 );
ldapConfig.setIpPort( port );
configuration.setShutdownHookEnabled( false );
setContexts( "uid=admin,ou=system", "secret" );
// -------------------------------------------------------------------
// Enable the krb5kdc schema
// -------------------------------------------------------------------
// check if krb5kdc is disabled
Attributes krb5kdcAttrs = schemaRoot.getAttributes( "cn=Krb5kdc" );
boolean isKrb5KdcDisabled = false;
if ( krb5kdcAttrs.get( "m-disabled" ) != null )
{
isKrb5KdcDisabled = ( ( String ) krb5kdcAttrs.get( "m-disabled" ).get() ).equalsIgnoreCase( "TRUE" );
}
// if krb5kdc is disabled then enable it
if ( isKrb5KdcDisabled )
{
Attribute disabled = new AttributeImpl( "m-disabled" );
ModificationItemImpl[] mods = new ModificationItemImpl[]
{ new ModificationItemImpl( DirContext.REMOVE_ATTRIBUTE, disabled ) };
schemaRoot.modifyAttributes( "cn=Krb5kdc", mods );
}
// Get a context, create the ou=users subcontext, then create the 3 principals.
Hashtable<String, String> env = new Hashtable<String, String>();
env.put( Context.INITIAL_CONTEXT_FACTORY, "org.apache.directory.server.core.jndi.CoreContextFactory" );
env.put( Context.PROVIDER_URL, "dc=example,dc=com" );
env.put( Context.SECURITY_PRINCIPAL, "uid=admin,ou=system" );
env.put( Context.SECURITY_CREDENTIALS, "secret" );
env.put( Context.SECURITY_AUTHENTICATION, "simple" );
ctx = new InitialDirContext( env );
attrs = getOrgUnitAttributes( "users" );
DirContext users = ctx.createSubcontext( "ou=users", attrs );
attrs = getPrincipalAttributes( "Nelson", "Horatio Nelson", "hnelson", "secret", "hnelson@EXAMPLE.COM" );
users.createSubcontext( "uid=hnelson", attrs );
attrs = getPrincipalAttributes( "Service", "KDC Service", "krbtgt", "secret", "krbtgt/EXAMPLE.COM@EXAMPLE.COM" );
users.createSubcontext( "uid=krbtgt", attrs );
attrs = getPrincipalAttributes( "Service", "LDAP Service", "ldap", "randall", "ldap/localhost@EXAMPLE.COM" );
users.createSubcontext( "uid=ldap", attrs );
}
/**
* Convenience method for creating principals.
*/
protected Attributes getPrincipalAttributes( String sn, String cn, String uid, String userPassword, String principal )
{
Attributes attrs = new AttributesImpl();
Attribute ocls = new AttributeImpl( "objectClass" );
ocls.add( "top" );
ocls.add( "person" ); // sn $ cn
ocls.add( "inetOrgPerson" ); // uid
ocls.add( "krb5principal" );
ocls.add( "krb5kdcentry" );
attrs.put( ocls );
attrs.put( "cn", cn );
attrs.put( "sn", sn );
attrs.put( "uid", uid );
attrs.put( "userPassword", userPassword );
attrs.put( KerberosAttribute.PRINCIPAL, principal );
attrs.put( KerberosAttribute.VERSION, "0" );
return attrs;
}
/**
* Convenience method for creating an organizational unit.
*/
protected Attributes getOrgUnitAttributes( String ou )
{
Attributes attrs = new AttributesImpl();
Attribute ocls = new AttributeImpl( "objectClass" );
ocls.add( "top" );
ocls.add( "organizationalUnit" );
attrs.put( ocls );
attrs.put( "ou", ou );
return attrs;
}
/**
* Tests to make sure GSSAPI binds below the RootDSE work.
*/
public void testSaslGssapiBind()
{
assertTrue( true );
return;
/*
// Use our custom configuration to avoid reliance on external config
Configuration.setConfiguration( new Krb5LoginConfiguration() );
// 1. Authenticate to Kerberos.
LoginContext lc = null;
try
{
lc = new LoginContext( SaslGssapiBindITest.class.getName(), new CallbackHandlerBean( "hnelson", "secret" ) );
lc.login();
}
catch ( LoginException le )
{
// Bad username: Client not found in Kerberos database
// Bad password: Integrity check on decrypted field failed
fail( "Authentication failed: " + le.getMessage() );
}
// 2. Perform JNDI work as authenticated Subject.
Subject.doAs( lc.getSubject(), new PrivilegedAction()
{
public Object run()
{
try
{
// Create the initial context
Hashtable<String, String> env = new Hashtable<String, String>();
env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" );
env.put( Context.PROVIDER_URL, "ldap://localhost:" + port );
// Request the use of the "GSSAPI" SASL mechanism
// Authenticate by using already established Kerberos credentials
env.put( Context.SECURITY_AUTHENTICATION, "GSSAPI" );
// Request privacy protection
env.put( "javax.security.sasl.qop", "auth-conf" );
// Request mutual authentication
env.put( "javax.security.sasl.server.authentication", "true" );
// Request high-strength cryptographic protection
env.put( "javax.security.sasl.strength", "high" );
DirContext ctx = new InitialDirContext( env );
String[] attrIDs =
{ "uid" };
Attributes attrs = ctx.getAttributes( "uid=hnelson,ou=users,dc=example,dc=com", attrIDs );
String uid = null;
if ( attrs.get( "uid" ) != null )
{
uid = ( String ) attrs.get( "uid" ).get();
}
assertEquals( uid, "hnelson" );
}
catch ( NamingException e )
{
fail( "Should not have caught exception: " + e.getMessage() );
}
return null;
}
} );
*/
}
/**
* Tear down.
*/
public void tearDown() throws Exception
{
ctx.close();
ctx = null;
super.tearDown();
}
}