You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by tb...@apache.org on 2006/12/12 16:24:14 UTC
svn commit: r486187 [24/49] - in /directory/trunks/triplesec: ./ admin-api/
admin-api/src/ admin-api/src/main/ admin-api/src/main/java/
admin-api/src/main/java/org/ admin-api/src/main/java/org/safehaus/
admin-api/src/main/java/org/safehaus/triplesec/ a...
Added: directory/trunks/triplesec/store/src/main/java/org/safehaus/triplesec/store/interceptor/PolicyProtectionInterceptor.java
URL: http://svn.apache.org/viewvc/directory/trunks/triplesec/store/src/main/java/org/safehaus/triplesec/store/interceptor/PolicyProtectionInterceptor.java?view=auto&rev=486187
==============================================================================
--- directory/trunks/triplesec/store/src/main/java/org/safehaus/triplesec/store/interceptor/PolicyProtectionInterceptor.java (added)
+++ directory/trunks/triplesec/store/src/main/java/org/safehaus/triplesec/store/interceptor/PolicyProtectionInterceptor.java Tue Dec 12 07:23:31 2006
@@ -0,0 +1,774 @@
+/*
+ * 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.safehaus.triplesec.store.interceptor;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SchemaViolationException;
+import javax.naming.directory.SearchControls;
+
+import org.apache.directory.shared.ldap.filter.ExprNode;
+import org.apache.directory.shared.ldap.filter.FilterParserImpl;
+import org.apache.directory.shared.ldap.util.NamespaceTools;
+import org.apache.directory.shared.ldap.name.LdapDN;
+import org.apache.directory.server.core.configuration.InterceptorConfiguration;
+import org.apache.directory.server.core.interceptor.BaseInterceptor;
+import org.apache.directory.server.core.interceptor.Interceptor;
+import org.apache.directory.server.core.interceptor.NextInterceptor;
+import org.apache.directory.server.core.DirectoryServiceConfiguration;
+import org.apache.directory.server.core.invocation.InvocationStack;
+import org.apache.directory.server.core.partition.PartitionNexusProxy;
+
+
+/**
+ * An ApacheDS {@link Interceptor} that prevents users from deleting
+ * (or renaming) policy entries (permissions and roles) used by roles and profiles.
+ *
+ * @author Trustin Lee
+ * @version $Rev: 956 $, $Date: 2006-09-21 10:10:21 -0400 (Thu, 21 Sep 2006) $
+ */
+public class PolicyProtectionInterceptor extends BaseInterceptor
+{
+ private DirectoryServiceConfiguration factoryConfiguration;
+ private ApplicationAciManager aciManager = null;
+
+
+ public PolicyProtectionInterceptor()
+ {
+ }
+
+
+ public void init( DirectoryServiceConfiguration factoryCfg, InterceptorConfiguration cfg ) throws NamingException
+ {
+ factoryConfiguration = factoryCfg;
+ aciManager = new ApplicationAciManager( factoryCfg.getGlobalRegistries().getAttributeTypeRegistry() );
+ }
+
+
+ public void add( NextInterceptor next, LdapDN name, Attributes attrs ) throws NamingException
+ {
+ boolean policyEntry = false;
+ boolean isApplication = false;
+
+ Attribute attr = getObjectClass( attrs );
+ NamingEnumeration ocList = attr.getAll();
+ try
+ {
+ while( ocList.hasMore() )
+ {
+ String value = String.valueOf( ocList.next() );
+ if( "policyPermission".equalsIgnoreCase( value ) )
+ {
+ checkNewPolicyEntry( next, name, "2.5.4.11=permissions" );
+ policyEntry = true;
+ }
+ else if( "policyRole".equalsIgnoreCase( value ) )
+ {
+ checkNewPolicyEntry( next, name, "2.5.4.11=roles" );
+ policyEntry = true;
+ }
+ else if( "policyProfile".equalsIgnoreCase( value ) )
+ {
+ checkNewPolicyEntry( next, name, "2.5.4.11=profiles" );
+ policyEntry = true;
+ }
+ else if( "policyApplication".equalsIgnoreCase( value ) )
+ {
+ isApplication = true;
+ }
+ }
+ }
+ finally
+ {
+ ocList.close();
+ }
+
+ if( !policyEntry )
+ {
+ checkNewNonPolicyEntry( next, name );
+ }
+ else
+ {
+ // Check if all grants, denials, and roles are valid.
+ LdapDN baseName = ( LdapDN ) name.clone();
+ baseName.remove( baseName.size() -1 );
+ baseName.remove( baseName.size() -1 );
+ NamingEnumeration attrList = attrs.getAll();
+ try
+ {
+ while( attrList.hasMore() )
+ {
+ attr = ( Attribute ) attrList.next();
+ checkAttributeAddition( next, baseName, attr );
+ }
+ }
+ finally
+ {
+ ocList.close();
+ }
+ }
+
+ next.add( name, attrs );
+
+ if( isApplication )
+ {
+ aciManager.appAdded( name );
+ }
+ }
+
+
+ public void delete( NextInterceptor next, LdapDN name ) throws NamingException
+ {
+ boolean isApplication = isPolicyApplication( name );
+
+ LdapDN baseName = getBaseName( next, name );
+ if( baseName == null )
+ {
+ next.delete( name );
+
+ if ( isApplication )
+ {
+ aciManager.appRemoved( name );
+ }
+ return;
+ }
+
+ checkNotInUse( next, baseName, name );
+ next.delete( name );
+ if ( isApplication )
+ {
+ aciManager.appRemoved( name );
+ }
+ }
+
+
+ public void modify( NextInterceptor next, LdapDN name, int modOp, Attributes attrs ) throws NamingException
+ {
+ LdapDN baseName = getBaseName( next, name );
+ if( baseName == null )
+ {
+ next.modify( name, modOp, attrs );
+ return;
+ }
+
+ NamingEnumeration e = attrs.getAll();
+ try
+ {
+ while( e.hasMore() )
+ {
+ Attribute attr = ( Attribute ) e.next();
+ if( attr != null )
+ {
+ switch( modOp )
+ {
+ case DirContext.ADD_ATTRIBUTE:
+ case DirContext.REPLACE_ATTRIBUTE:
+ checkAttributeAddition( next, baseName, attr );
+ break;
+ case DirContext.REMOVE_ATTRIBUTE:
+ checkAttributeRemoval( attr );
+ break;
+ }
+ }
+ }
+ }
+ finally
+ {
+ e.close();
+ }
+
+ next.modify( name, modOp, attrs );
+ }
+
+
+ public void modify( NextInterceptor next, LdapDN name, ModificationItem[] modItems ) throws NamingException
+ {
+ LdapDN baseName = getBaseName( next, name );
+ if( baseName == null )
+ {
+ next.modify( name, modItems );
+ return;
+ }
+
+ for( int i = modItems.length - 1; i >= 0; i-- )
+ {
+ Attribute attr = modItems[ i ].getAttribute();
+ switch( modItems[ i ].getModificationOp() ) {
+ case DirContext.ADD_ATTRIBUTE:
+ case DirContext.REPLACE_ATTRIBUTE:
+ checkAttributeAddition( next, baseName, attr );
+ break;
+ case DirContext.REMOVE_ATTRIBUTE:
+ checkAttributeRemoval( attr );
+ break;
+ }
+ }
+
+ next.modify( name, modItems );
+ }
+
+
+ public void modifyRn( NextInterceptor next, LdapDN name, String newRN, boolean deleteOldRN ) throws NamingException
+ {
+ PartitionNexusProxy proxy = InvocationStack.getInstance().peek().getProxy();
+ Attributes entry = proxy.lookup( name, ApplicationAciManager.LOOKUP_BYPASS );
+ Attribute oc = entry.get( "objectClass" );
+ boolean isApplication = false;
+
+ for ( int ii = 0; ii < oc.size(); ii++ )
+ {
+ String item = ( String ) oc.get( ii );
+ if ( item.equalsIgnoreCase( "policyApplication" ) )
+ {
+ isApplication = true;
+ }
+ }
+
+ // calculate the new name
+ LdapDN newNameUpDn = ( LdapDN ) name.clone();
+ newNameUpDn.remove( name.size() - 1 );
+ newNameUpDn.add( newRN );
+ LdapDN rdn = new LdapDN( newRN );
+ LdapDN newDn = ( LdapDN ) name.clone();
+ newDn.remove( name.size() - 1 );
+ newDn.add( rdn.get( 0 ) );
+
+ LdapDN baseName = getBaseName( next, name );
+ if( baseName == null )
+ {
+ if ( isApplication )
+ {
+ // we don't need to mess around with deleting and adding the admin group (don't want to loose info either)
+ aciManager.removeApplicationSubentry( proxy, name );
+ }
+ next.modifyRn( name, newRN, deleteOldRN );
+ if ( isApplication )
+ {
+ aciManager.addApplicationSubentry( proxy, newDn );
+ }
+
+ return;
+ }
+
+ checkModification( next, baseName, name );
+
+ if ( isApplication )
+ {
+ // we don't need to mess around with deleting and adding the admin group (don't want to loose info either)
+ aciManager.removeApplicationSubentry( proxy, name );
+ }
+ next.modifyRn( name, newRN, deleteOldRN );
+ if ( isApplication )
+ {
+ aciManager.addApplicationSubentry( proxy, newDn );
+ }
+ }
+
+ public void move( NextInterceptor next, LdapDN name, LdapDN newParentName, String newRN, boolean deleteOldRN ) throws NamingException
+ {
+ PartitionNexusProxy proxy = InvocationStack.getInstance().peek().getProxy();
+ Attributes entry = proxy.lookup( name, ApplicationAciManager.LOOKUP_BYPASS );
+ Attribute oc = entry.get( "objectClass" );
+ boolean isApplication = false;
+
+ for ( int ii = 0; ii < oc.size(); ii++ )
+ {
+ String item = ( String ) oc.get( ii );
+ if ( item.equalsIgnoreCase( "policyApplication" ) )
+ {
+ isApplication = true;
+ }
+ }
+
+ // calculate the new name
+ LdapDN newNameUpDn = ( LdapDN ) newParentName.clone();
+ newNameUpDn.add( newRN );
+ LdapDN rdn = new LdapDN( newRN );
+ LdapDN newDn = ( LdapDN ) newParentName.clone();
+ newDn.add( rdn.get( 0 ) );
+
+ LdapDN baseName = getBaseName( next, name );
+ if( baseName == null )
+ {
+ if ( isApplication )
+ {
+ // we don't need to mess around with deleting and adding the admin group (don't want to loose info either)
+ aciManager.removeApplicationSubentry( proxy, name );
+ }
+ next.move( name, newParentName, newRN, deleteOldRN );
+ if ( isApplication )
+ {
+ aciManager.addApplicationSubentry( proxy, newDn );
+ }
+ return;
+ }
+
+ checkModification( next, baseName, name );
+ if ( isApplication )
+ {
+ // we don't need to mess around with deleting and adding the admin group (don't want to loose info either)
+ aciManager.removeApplicationSubentry( proxy, name );
+ }
+ next.move( name, newParentName, newRN, deleteOldRN );
+ if ( isApplication )
+ {
+ aciManager.addApplicationSubentry( proxy, newDn );
+ }
+ }
+
+ public void move( NextInterceptor next, LdapDN name, LdapDN newParentName ) throws NamingException
+ {
+ PartitionNexusProxy proxy = InvocationStack.getInstance().peek().getProxy();
+ Attributes entry = proxy.lookup( name, ApplicationAciManager.LOOKUP_BYPASS );
+ Attribute oc = entry.get( "objectClass" );
+ boolean isApplication = false;
+
+ for ( int ii = 0; ii < oc.size(); ii++ )
+ {
+ String item = ( String ) oc.get( ii );
+ if ( item.equalsIgnoreCase( "policyApplication" ) )
+ {
+ isApplication = true;
+ }
+ }
+
+ // calculate the new name
+ LdapDN newDn = ( LdapDN ) newParentName.clone();
+ newDn.add( name.get( name.size() - 1 ) );
+
+ LdapDN baseName = getBaseName( next, name );
+ if( baseName == null )
+ {
+ if ( isApplication )
+ {
+ // we don't need to mess around with deleting and adding the admin group (don't want to loose info either)
+ aciManager.removeApplicationSubentry( proxy, name );
+ }
+ next.move( name, newParentName );
+ if ( isApplication )
+ {
+ aciManager.addApplicationSubentry( proxy, newDn );
+ }
+ return;
+ }
+
+ checkModification( next, baseName, name );
+ if ( isApplication )
+ {
+ // we don't need to mess around with deleting and adding the admin group (don't want to loose info either)
+ aciManager.removeApplicationSubentry( proxy, name );
+ }
+ next.move( name, newParentName );
+ if ( isApplication )
+ {
+ aciManager.addApplicationSubentry( proxy, newDn );
+ }
+ }
+
+ private LdapDN getBaseName( NextInterceptor next, LdapDN name ) throws NamingException
+ {
+ if( name.size() >= 3 )
+ {
+ Attributes attrs = next.lookup( name );
+ Attribute attr = getObjectClass( attrs );
+ NamingEnumeration e = attr.getAll();
+ try
+ {
+ while( e.hasMore() )
+ {
+ String value = String.valueOf( e.next() );
+ if( "policyPermission".equalsIgnoreCase( value ) ||
+ "policyProfile".equalsIgnoreCase( value ) ||
+ "policyRole".equalsIgnoreCase( value ) )
+ {
+ LdapDN retVal = ( LdapDN ) name.clone();
+ retVal.remove( retVal.size() -1 );
+ retVal.remove( retVal.size() -1 );
+
+ return retVal;
+ }
+ if( "policyApplication".equalsIgnoreCase( value ) )
+ {
+ return name;
+ }
+ }
+ }
+ finally
+ {
+ e.close();
+ }
+ }
+
+ if( name.size() >= 2 )
+ {
+ // Try the parent node in case we add group entries.
+ try
+ {
+ name = ( LdapDN ) name.clone();
+ name.remove( name.size() - 1 );
+ Attributes attrs = next.lookup( name );
+ Attribute attr = getObjectClass( attrs );
+ NamingEnumeration e = attr.getAll();
+ try
+ {
+ while( e.hasMore() )
+ {
+ String value = String.valueOf( e.next() );
+ if( "policyApplication".equalsIgnoreCase( value ) )
+ {
+ return name;
+ }
+ }
+ }
+ finally
+ {
+ e.close();
+ }
+ }
+ catch( NamingException e )
+ {
+ // Ignore silently
+ }
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Checks to see if a policy entry should be added under a parent.
+ *
+ * @param next
+ * @param name
+ * @param parentName
+ * @throws NamingException
+ */
+ private void checkNewPolicyEntry( NextInterceptor next, LdapDN name, String parentName ) throws NamingException
+ {
+ LdapDN parentDn = ( LdapDN ) name.clone();
+ parentDn.remove( parentDn.size() -1 );
+
+ if( name.size() < 3 )
+ {
+ throw new SchemaViolationException( "Name is too short: " + name );
+ }
+
+
+ if( !parentName.equalsIgnoreCase( parentDn.getRdn().toString() ) )
+ {
+ throw new SchemaViolationException( "Parent entry for policyPermissions must be '" +
+ parentName + "': " + name );
+ }
+
+ parentDn.remove( parentDn.size() -1 );
+ if( !isPolicyApplication( parentDn ) )
+ {
+ throw new SchemaViolationException( "Grandparent must be a policyApplication." );
+ }
+ }
+
+
+ private static final String[] OBJECT_CLASS_ATTRS = { "objectClass" };
+ private boolean isPolicyApplication( LdapDN dn ) throws NamingException
+ {
+ PartitionNexusProxy proxy = InvocationStack.getInstance().peek().getProxy();
+ Attributes entry = proxy.lookup( dn, OBJECT_CLASS_ATTRS, PartitionNexusProxy.LOOKUP_BYPASS );
+ Attribute oc = getObjectClass( entry );
+
+ NamingEnumeration list = oc.getAll();
+ try
+ {
+ while( list.hasMore() )
+ {
+ if( "policyApplication".equalsIgnoreCase( String.valueOf( list.next() ) ) )
+ {
+ return true;
+ }
+ }
+ }
+ finally {
+ list.close();
+ }
+
+ return false;
+ }
+
+
+ private void checkNewNonPolicyEntry( NextInterceptor next, LdapDN name ) throws NamingException
+ {
+ if( name.size() < 3 )
+ {
+ return;
+ }
+
+ if( isEntityGroup( name ) )
+ {
+ // Strip the name once more; this will prevent this method
+ // from throwing an exception when these entries are added
+ // just beneath policyApplication entry.
+ name = ( LdapDN ) name.getPrefix( 1 );
+ }
+
+ name = ( LdapDN ) name.clone();
+ do
+ {
+ name.remove( name.size() - 1 );
+ try
+ {
+ Attributes entry = next.lookup( name );
+ Attribute attr = getObjectClass( entry );
+ NamingEnumeration e = attr.getAll();
+ try
+ {
+ while( e.hasMore() )
+ {
+ if( "policyApplication".equalsIgnoreCase( String.valueOf( e.next() ) ) )
+ {
+ throw new SchemaViolationException( "Non-policy entries cannot reside under policyApplication." );
+ }
+ }
+ }
+ finally
+ {
+ e.close();
+ }
+ }
+ catch( SchemaViolationException e )
+ {
+ throw e;
+ }
+ catch( Exception e )
+ {
+ // Ignore silently.
+ }
+ }
+ while( name.size() > 1 );
+ }
+
+
+ private void checkAttributeAddition( NextInterceptor next, LdapDN baseName, Attribute attr )
+ throws NamingException, SchemaViolationException
+ {
+
+ // If the attribute is a permission
+ if( "grants".equalsIgnoreCase( attr.getID() ) ||
+ "denials".equalsIgnoreCase( attr.getID() ) )
+ {
+ NamingEnumeration e = attr.getAll();
+ try
+ {
+ while( e.hasMore() )
+ {
+ String value = String.valueOf( e.next() );
+ LdapDN name = ( LdapDN ) baseName.clone();
+
+ // ou=permissions
+ name.add( "2.5.4.11=permissions" );
+ // permName=
+ name.add( "1.2.6.1.4.1.22555.1.1.1.3.201=" + value );
+ if( !next.hasEntry( name ) ) {
+ throw new SchemaViolationException( "No such permission: " + value );
+ }
+ }
+ }
+ finally {
+ e.close();
+ }
+ }
+
+ // If the attribute is a role
+ if( "roles".equalsIgnoreCase( attr.getID() ) ) {
+ NamingEnumeration e = attr.getAll();
+ try
+ {
+ while( e.hasMore() )
+ {
+ String value = String.valueOf( e.next() );
+ LdapDN name = ( LdapDN ) baseName.clone();
+
+ // ou = roles
+ name.add( "2.5.4.11=roles" );
+
+ // roleName=
+ name.add( "1.2.6.1.4.1.22555.1.1.1.3.204=" + value );
+ if( !next.hasEntry( name ) ) {
+ throw new SchemaViolationException( "No such role: " + value );
+ }
+ }
+ }
+ finally {
+ e.close();
+ }
+ }
+ }
+
+
+ private void checkAttributeRemoval( Attribute attr ) throws NamingException, SchemaViolationException
+ {
+ if( !"objectClass".equalsIgnoreCase( attr.getID() ) )
+ {
+ return;
+ }
+
+ NamingEnumeration e = attr.getAll();
+ try
+ {
+ while( e.hasMore() )
+ {
+ String value = String.valueOf( e.next() );
+ if( "policyPermission".equalsIgnoreCase( value ) ||
+ "policyRole".equalsIgnoreCase( value ) ||
+ "policyProfile".equalsIgnoreCase( value ) )
+ {
+ throw new SchemaViolationException( "Removing policy objectClasses are not allowed." );
+ }
+ }
+ }
+ finally
+ {
+ e.close();
+ }
+ }
+
+
+ private static final String PERMNAME_ATTR_OID = "1.2.6.1.4.1.22555.1.1.1.3.201";
+ private static final String ROLENAME_ATTR_OID = "1.2.6.1.4.1.22555.1.1.1.3.204";
+
+ private void checkNotInUse( NextInterceptor next, LdapDN baseName, LdapDN name )
+ throws NamingException, SchemaViolationException
+ {
+ String nameType = NamespaceTools.getRdnAttribute( name.get( name.size() - 1 ) );
+ String nameValue = NamespaceTools.getRdnValue( name.get( name.size() - 1 ) );
+
+ // Prepare a search control.
+ SearchControls ctrl = new SearchControls();
+ ctrl.setSearchScope( SearchControls.SUBTREE_SCOPE );
+ ctrl.setReturningAttributes( new String[]
+ {
+ "roles", "grants", "denials"
+ } );
+
+ // Get an appropriate filter.
+ ExprNode filter = null;
+ if( PERMNAME_ATTR_OID.equals( nameType ) )
+ {
+ try
+ {
+ filter = new FilterParserImpl().parse(
+ "(|" +
+ "(grants=" + nameValue + ")" +
+ "(denials=" + nameValue + ")" +
+ ")" );
+ }
+ catch( Exception e )
+ {
+ throw ( NamingException ) new NamingException().initCause( e );
+ }
+ }
+ else if( ROLENAME_ATTR_OID.equals( nameType ) )
+ {
+ try
+ {
+ filter = new FilterParserImpl().parse(
+ "(roles=" + nameValue + ")" );
+ }
+ catch( Exception e )
+ {
+ throw ( NamingException ) new NamingException().initCause( e );
+ }
+ }
+
+ // If it is able to find an appropriate filter,
+ if( filter != null )
+ {
+ // execute search
+ NamingEnumeration e = next.search( baseName, factoryConfiguration.getEnvironment(),
+ filter, ctrl );
+
+ // throw an exception if search returned more than 0 usage.
+ try
+ {
+ if( e.hasMore() )
+ {
+ throw new SchemaViolationException( "Policy entry in use: " + name );
+ }
+ }
+ finally
+ {
+ e.close();
+ }
+ }
+ }
+
+
+ private void checkModification( NextInterceptor next, LdapDN baseName, LdapDN name )
+ throws SchemaViolationException, NamingException
+ {
+ if( isEntityGroup( name ) )
+ {
+ throw new SchemaViolationException( "Entity groups are not allowed to move: " + name );
+ }
+ checkNotInUse( next, baseName, name );
+ }
+
+
+ private static final String OU_ATTR_OID = "2.5.4.11";
+ private static boolean isEntityGroup( LdapDN name )
+ {
+ String rn = name.get( name.size() - 1 );
+ if( ! OU_ATTR_OID.equalsIgnoreCase( NamespaceTools.getRdnAttribute( rn ).trim() ) )
+ {
+ return false;
+ }
+
+ rn = NamespaceTools.getRdnValue( rn ).trim();
+
+ return ( rn.equalsIgnoreCase( "permissions" ) ||
+ rn.equalsIgnoreCase( "roles" ) ||
+ rn.equalsIgnoreCase( "profiles" ) );
+ }
+
+
+ private static Attribute getObjectClass( Attributes attrs ) throws NamingException
+ {
+ NamingEnumeration e = attrs.getAll();
+ try
+ {
+ while( e.hasMore() )
+ {
+ Attribute attr = ( Attribute ) e.next();
+ if( "objectClass".equalsIgnoreCase( attr.getID() ) )
+ {
+ return attr;
+ }
+ }
+ }
+ finally
+ {
+ e.close();
+ }
+
+ return null;
+ }
+}
Added: directory/trunks/triplesec/store/src/main/schema/safehaus.schema
URL: http://svn.apache.org/viewvc/directory/trunks/triplesec/store/src/main/schema/safehaus.schema?view=auto&rev=486187
==============================================================================
--- directory/trunks/triplesec/store/src/main/schema/safehaus.schema (added)
+++ directory/trunks/triplesec/store/src/main/schema/safehaus.schema Tue Dec 12 07:23:31 2006
@@ -0,0 +1,210 @@
+# -----------------------------------------------------------------------------
+# Safehaus LDAP Schema
+# -----------------------------------------------------------------------------
+#
+# Author: $author$
+# Author: Alex Karasulu
+# Revision: $rev$
+# Nag-to: dev@safehaus.org
+# Dependencies: system, core
+#
+# -----------------------------------------------------------------------------
+
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.100
+ NAME 'safehausUid'
+ DESC 'A safehaus user id'
+ SUP uid SINGLE-VALUE )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.101
+ NAME 'safehausRealm'
+ DESC 'The domain/realm name of the safehaus user account'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.102
+ NAME 'safehausSecret'
+ DESC 'The shared secret for the Safehaus user'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.103
+ NAME 'safehausFactor'
+ DESC 'The shared moving factor for the Safehaus user'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.104
+ NAME 'safehausInfo'
+ DESC 'Additional information about a Safehaus account'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.105
+ NAME 'safehausLabel'
+ DESC 'Additional information about a Safehaus account'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.106
+ NAME 'safehausResynchCount'
+ DESC 'The number of successful resync attempts so far'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.107
+ NAME 'safehausFailuresInEpoch'
+ DESC 'The number of authentication failures within an epoch used for lockouts'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.108
+ NAME 'safehausDeleted'
+ DESC 'An operational marker attribute for labelling an entry as deleted'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ SINGLE-VALUE
+ NO-USER-MODIFICATION
+ USAGE directoryOperation )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.109
+ NAME 'safehausActivationKey'
+ DESC 'Activation key for safehaus accounts which if present means the account is not active'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.110
+ NAME 'safehausMidletName'
+ DESC 'Optional name override for the hauskeys midlet'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.111
+ NAME 'safehausNotifyBy'
+ DESC 'Mechanism used to notify the user'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.112
+ NAME 'safehausMobileCarrier'
+ DESC 'The mobile carrier for the cell phone of the user'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.113
+ NAME 'safehausTokenPin'
+ DESC 'The mobile token pin for the hauskeys application'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.114
+ NAME 'safehausDisabled'
+ DESC 'Used to disable user accounts and policyProfiles'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseIgnoreIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
+
+objectclass ( 1.2.6.1.4.1.22555.1.1.1.4.100 NAME 'safehausProfile'
+ SUP top
+ AUXILIARY
+ MUST ( safehausUid $ safehausRealm $ safehausLabel $ safehausSecret $
+ safehausFactor $ safehausResynchCount $ safehausFailuresInEpoch $ safehausNotifyBy )
+ MAY ( safehausInfo $ safehausActivationKey $ safehausMidletName $ safehausDisabled ) )
+
+
+# -----------------------------------------------------------------------------
+# Safehaus Policy Entities
+# -----------------------------------------------------------------------------
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.200
+ NAME 'appName'
+ DESC 'the name of an application whose policy is managed by triplesec'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+objectclass ( 1.2.6.1.4.1.22555.1.1.1.4.200 NAME 'policyApplication'
+ SUP top
+ STRUCTURAL
+ MUST ( appName )
+ MAY ( userPassword $ description ) )
+
+objectclass ( 1.2.6.1.4.1.22555.1.1.1.4.201 NAME 'policyUser'
+ SUP top
+ AUXILIARY
+ MUST ( uid )
+ MAY ( userPassword $ description $ safehausDisabled ) )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.201
+ NAME 'permName'
+ DESC 'the case sensitive name of a permission within the system'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+objectclass ( 1.2.6.1.4.1.22555.1.1.1.4.202 NAME 'policyPermission'
+ SUP top
+ AUXILIARY
+ MUST ( permName )
+ MAY ( description )
+ )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.202
+ NAME 'grants'
+ DESC 'the permissions granted to a role or a profile'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.203
+ NAME 'denials'
+ DESC 'the permissions denied for a profile'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.204
+ NAME 'roleName'
+ DESC 'the name of a role'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.205
+ NAME 'roles'
+ DESC 'the roles assigned to a profile'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.206
+ NAME 'profileId'
+ DESC 'a profile identifier'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+attributetype ( 1.2.6.1.4.1.22555.1.1.1.3.207
+ NAME 'user'
+ DESC 'the name of a user defined in the policy store'
+ EQUALITY caseExactMatch
+ SUBSTR caseExactSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+objectclass ( 1.2.6.1.4.1.22555.1.1.1.4.203 NAME 'policyRole'
+ SUP top
+ AUXILIARY
+ MUST ( roleName )
+ MAY ( grants $ description ) )
+
+objectclass ( 1.2.6.1.4.1.22555.1.1.1.4.204 NAME 'policyProfile'
+ SUP top
+ AUXILIARY
+ MUST ( profileId $ user )
+ MAY ( grants $ denials $ roles $ userPassword $ description $ safehausDisabled ) )
+
Added: directory/trunks/triplesec/store/src/test/java/org/safehaus/triplesec/store/ProfileFactoryITest.java
URL: http://svn.apache.org/viewvc/directory/trunks/triplesec/store/src/test/java/org/safehaus/triplesec/store/ProfileFactoryITest.java?view=auto&rev=486187
==============================================================================
--- directory/trunks/triplesec/store/src/test/java/org/safehaus/triplesec/store/ProfileFactoryITest.java (added)
+++ directory/trunks/triplesec/store/src/test/java/org/safehaus/triplesec/store/ProfileFactoryITest.java Tue Dec 12 07:23:31 2006
@@ -0,0 +1,155 @@
+/*
+ * 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.safehaus.triplesec.store;
+
+
+import javax.naming.directory.Attributes;
+import javax.naming.NamingException;
+import javax.naming.Context;
+
+import org.apache.directory.server.core.unit.AbstractAdminTestCase;
+import org.apache.directory.server.core.schema.bootstrap.*;
+import org.apache.directory.server.core.configuration.MutableStartupConfiguration;
+
+import org.apache.directory.shared.ldap.ldif.Entry;
+import org.apache.directory.shared.ldap.ldif.LdifReader;
+import org.safehaus.profile.ServerProfile;
+import org.safehaus.profile.BaseServerProfileModifier;
+import org.safehaus.triplesec.store.schema.SafehausSchema;
+
+import java.util.Set;
+import java.util.HashSet;
+
+
+/**
+ * Tests the ProfileObjectFactory and ProfileStateFactory classes.
+ *
+ * @author <a href="mailto:akarasulu@safehaus.org">Alex Karasulu</a>
+ * @version $Rev$
+ */
+public class ProfileFactoryITest extends AbstractAdminTestCase
+{
+ public ProfileFactoryITest()
+ {
+ MutableStartupConfiguration cfg = super.configuration;
+ Set schemas = new HashSet();
+ schemas.add( new SystemSchema() );
+ schemas.add( new SafehausSchema() );
+ schemas.add( new ApacheSchema() );
+ schemas.add( new CoreSchema() );
+ schemas.add( new CosineSchema() );
+ schemas.add( new InetorgpersonSchema() );
+ schemas.add( new Krb5kdcSchema() );
+ cfg.setBootstrapSchemas( schemas );
+ cfg.setShutdownHookEnabled( false );
+ super.overrideEnvironment( Context.OBJECT_FACTORIES, ProfileObjectFactory.class.getName() );
+ super.overrideEnvironment( Context.STATE_FACTORIES, ProfileStateFactory.class.getName() );
+ }
+
+
+ public void testObjectFactory() throws Exception
+ {
+ String ldif = "dn: cn=bogus\n"
+ + "cn: Alex Karasulu\n" + "sn: Karasulu\n" + "givenname: Alex\n" + "objectClass: top\n"
+ + "objectClass: person\n" + "objectClass: organizationalPerson\n" + "objectClass: inetOrgPerson\n"
+ + "objectClass: krb5Principal\n" + "objectClass: krb5KDCEntry\n" + "objectClass: safehausProfile\n"
+ + "ou: Directory\n" + "ou: Users\n" + "l: Jacksonville\n" + "uid: akarasulu2\n"
+ + "krb5PrincipalName: akarasulu@EXAMPLE.COM\n" + "krb5KeyVersionNumber: 0\n"
+ + "mail: akarasulu@example.com\n" + "telephonenumber: +1 904 982 6882\n"
+ + "facsimiletelephonenumber: +1 904 982 6883\n" + "roomnumber: 666\n" + "userPassword: maxwell\n"
+ + "safehausUid: akarasulu2\n" + "safehausRealm: example.com\n" + "safehausLabel: example realm\n"
+ + "safehausFactor: 34258723456\n" + "safehausSecret:: d$U*E&*^dss%$(345j\n"
+ + "safehausFailuresInEpoch: 7\n" + "safehausResynchCount: -1\n" + "safehausTokenPin: 1234\n"
+ + "safehausNotifyBy: sms\n"
+ + "safehausInfo: for testcases\n";
+
+ LdifReader parser = new LdifReader();
+ Entry entry = ( Entry ) parser.parseLdif( ldif ).get( 0 );
+ Attributes attributes = entry.getAttributes();
+
+ attributes.remove( "dn" );
+
+ sysRoot.bind( "uid=akarasulu2", null, attributes );
+ ServerProfile p = ( ServerProfile ) sysRoot.lookup( "uid=akarasulu2" );
+
+ assertNotNull( p );
+ assertEquals( 34258723456L, p.getFactor() );
+ assertEquals( 7, p.getFailuresInEpoch() );
+ assertEquals( -1, p.getResynchCount() );
+ assertEquals( "for testcases", p.getInfo() );
+ assertEquals( "example realm", p.getLabel() );
+ assertEquals( "example.com", p.getRealm() );
+ assertEquals( "akarasulu2", p.getUserId() );
+ }
+
+
+ public void testStateFactory() throws NamingException
+ {
+ String ldif = "dn: uid=akarasulu,ou=users,dc=example,dc=com\n" +
+ "cn: Alex Karasulu\n" + "sn: Karasulu\n" +
+ "givenname: Alex\n" +
+ "objectClass: top\n" +
+ "objectClass: person\n" +
+ "objectClass: organizationalPerson\n" +
+ "objectClass: inetOrgPerson\n" +
+ "objectClass: krb5Principal\n" +
+ "objectClass: krb5KDCEntry\n" +
+ "objectClass: safehausProfile\n" +
+ "ou: Directory\n" +
+ "ou: Users\n" +
+ "l: Jacksonville\n" +
+ "uid: akarasulu2\n" +
+ "krb5PrincipalName: akarasulu@EXAMPLE.COM\n" +
+ "krb5KeyVersionNumber: 0\n" +
+ "mail: akarasulu@example.com\n" +
+ "telephonenumber: +1 904 982 6882\n" +
+ "facsimiletelephonenumber: +1 904 982 6883\n" +
+ "safehausNotifyBy: sms\n" +
+ "roomnumber: 666\n" +
+ "userPassword: maxwell\n";
+
+ LdifReader parser = new LdifReader();
+ Entry entry = ( Entry ) parser.parseLdif( ldif ).get( 0 );
+ Attributes attributes = ( Attributes ) entry.getAttributes();
+ attributes.remove( "dn" );
+
+ BaseServerProfileModifier modifier = new BaseServerProfileModifier();
+ modifier.setFactor( 56902748234756L );
+ modifier.setFailuresInEpoch( 234 );
+ modifier.setLabel( "test domain" );
+ modifier.setInfo( "just some info" );
+ modifier.setSecret( new byte[]
+ { 'a', 's', 'd', 'f', 'a', 'd', 's', 'f', 'a', 'd', 'f', 'a', 'd', 'f', 'a', 'f', 's', 'f', 'd', 'f' } );
+ modifier.setUserId( "akarasulu2" );
+ modifier.setRealm( "example.com" );
+ modifier.setResynchCount( 2 );
+
+ sysRoot.bind( "uid=akarasulu2", modifier.getServerProfile(), attributes );
+ Attributes reload = sysRoot.getAttributes( "uid=akarasulu2" );
+ assertNotNull( reload );
+ assertEquals( 56902748234756L, Long.parseLong( ( String ) reload.get( "safehausFactor" ).get() ) );
+ assertEquals( 234, Integer.parseInt( ( String ) reload.get( "safehausFailuresInEpoch" ).get() ) );
+ assertEquals( 2, Integer.parseInt( ( String ) reload.get( "safehausResynchCount" ).get() ) );
+ assertEquals( "akarasulu2", reload.get( "safehausUid" ).get() );
+ assertEquals( "example.com", reload.get( "safehausRealm" ).get() );
+ assertEquals( "test domain", reload.get( "safehausLabel" ).get() );
+ assertEquals( "just some info", reload.get( "safehausInfo" ).get() );
+ }
+}
Added: directory/trunks/triplesec/store/src/test/java/org/safehaus/triplesec/store/ServerProfileStoreITest.java
URL: http://svn.apache.org/viewvc/directory/trunks/triplesec/store/src/test/java/org/safehaus/triplesec/store/ServerProfileStoreITest.java?view=auto&rev=486187
==============================================================================
--- directory/trunks/triplesec/store/src/test/java/org/safehaus/triplesec/store/ServerProfileStoreITest.java (added)
+++ directory/trunks/triplesec/store/src/test/java/org/safehaus/triplesec/store/ServerProfileStoreITest.java Tue Dec 12 07:23:31 2006
@@ -0,0 +1,253 @@
+/*
+ * 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.safehaus.triplesec.store;
+
+
+import java.io.File;
+import java.util.*;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttributes;
+import javax.security.auth.kerberos.KerberosPrincipal;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.directory.shared.ldap.message.LockableAttributeImpl;
+import org.apache.directory.shared.ldap.message.LockableAttributesImpl;
+import org.apache.directory.server.core.configuration.Configuration;
+import org.apache.directory.server.core.configuration.MutablePartitionConfiguration;
+import org.apache.directory.server.core.configuration.MutableStartupConfiguration;
+import org.apache.directory.server.core.configuration.ShutdownConfiguration;
+import org.apache.directory.server.core.schema.bootstrap.ApacheSchema;
+import org.apache.directory.server.core.schema.bootstrap.CoreSchema;
+import org.apache.directory.server.core.schema.bootstrap.CosineSchema;
+import org.apache.directory.server.core.schema.bootstrap.InetorgpersonSchema;
+import org.apache.directory.server.core.schema.bootstrap.Krb5kdcSchema;
+import org.apache.directory.server.core.schema.bootstrap.SystemSchema;
+import org.apache.directory.server.protocol.shared.store.Krb5KdcEntryFilter;
+import org.apache.directory.server.protocol.shared.store.LdifFileLoader;
+import org.safehaus.profile.BaseServerProfileModifier;
+import org.safehaus.profile.ProfileTestData;
+import org.safehaus.profile.ServerProfile;
+import org.safehaus.triplesec.store.schema.SafehausSchema;
+import junit.framework.TestCase;
+
+
+/**
+ * A set of testcases for a profile store implementation.
+ *
+ * @author <a href="mailto:akarasulu@safehaus.org">Alex Karasulu</a>
+ * @version $Rev$
+ */
+public class ServerProfileStoreITest extends TestCase
+{
+ /** the server side store for profiles */
+ ServerProfileStore store = null;
+ DirContext userContext = null;
+
+ public ServerProfileStoreITest() throws Exception
+ {
+ super();
+ }
+
+
+ protected void setUp() throws Exception
+ {
+ File workingDirectory = File.createTempFile( "ServerProfileStoreITest", "test" );
+ if ( ! workingDirectory.exists() )
+ {
+ workingDirectory.mkdirs();
+ }
+ FileUtils.forceDelete( workingDirectory );
+
+ MutableStartupConfiguration config = new MutableStartupConfiguration();
+ config.setWorkingDirectory( workingDirectory );
+ MutablePartitionConfiguration partConfig = new MutablePartitionConfiguration();
+ partConfig.setName( "example" );
+
+ HashSet indices = new HashSet();
+ indices.add( "dc" );
+ indices.add( "ou" );
+ indices.add( "objectClass" );
+ indices.add( "cn" );
+ indices.add( "uid" );
+ partConfig.setIndexedAttributes( indices );
+
+ partConfig.setSuffix( "dc=example,dc=com" );
+
+ LockableAttributesImpl attrs = new LockableAttributesImpl();
+ LockableAttributeImpl attr = new LockableAttributeImpl( "objectClass" );
+ attr.add( "top" );
+ attr.add( "domain" );
+ attrs.put( attr );
+ attrs.put( "dc", "example" );
+ partConfig.setContextEntry( attrs );
+
+ Set schemas = new HashSet();
+ schemas.add( new SystemSchema() );
+ schemas.add( new SafehausSchema() );
+ schemas.add( new ApacheSchema() );
+ schemas.add( new CoreSchema() );
+ schemas.add( new CosineSchema() );
+ schemas.add( new InetorgpersonSchema() );
+ schemas.add( new Krb5kdcSchema() );
+ config.setBootstrapSchemas( schemas );
+ config.setContextPartitionConfigurations( Collections.singleton( partConfig ) );
+ config.setShutdownHookEnabled( false );
+
+ Hashtable env = new Hashtable();
+ 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_AUTHENTICATION, "simple" );
+ env.put( Context.SECURITY_CREDENTIALS, "secret" );
+ env.put( Configuration.JNDI_KEY, config );
+ env.put( Context.STATE_FACTORIES, ProfileStateFactory.class.getName() );
+ env.put( Context.OBJECT_FACTORIES, ProfileObjectFactory.class.getName() );
+
+ userContext = new InitialDirContext( env );
+ try
+ {
+ userContext = ( DirContext ) userContext.lookup( "ou=users" );
+ }
+ catch ( NamingException e )
+ {
+ Attributes users = new BasicAttributes( "objectClass", "top", true );
+ users.get( "objectClass" ).add( "organizationalUnit" );
+ attrs.put( "ou", "users" );
+ userContext = userContext.createSubcontext( "ou=users", attrs );
+ }
+
+ store = new DefaultServerProfileStore( userContext );
+ store.init();
+
+ List filters = Collections.singletonList( new Krb5KdcEntryFilter() );
+ LdifFileLoader loader = new LdifFileLoader( userContext, new File( "safehaus.ldif" ), filters, getClass().getClassLoader() );
+ loader.execute();
+
+ assertNotNull( store );
+ }
+
+
+ protected void tearDown() throws Exception
+ {
+ userContext.close();
+ ShutdownConfiguration config = new ShutdownConfiguration();
+ Hashtable env = new Hashtable();
+ 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_AUTHENTICATION, "simple" );
+ env.put( Context.SECURITY_CREDENTIALS, "secret" );
+ env.put( Configuration.JNDI_KEY, config );
+ env.put( Context.STATE_FACTORIES, ProfileStateFactory.class.getName() );
+ env.put( Context.OBJECT_FACTORIES, ProfileObjectFactory.class.getName() );
+ new InitialDirContext( env );
+
+ userContext = null;
+ store = null;
+ }
+
+
+ /**
+ * Tests getting a profile.
+ *
+ * @throws Exception if it fails
+ */
+ public void testGetProfile() throws Exception
+ {
+ KerberosPrincipal principal = new KerberosPrincipal( "akarasulu@EXAMPLE.COM" );
+ ServerProfile p = store.getProfile( principal );
+ assertNotNull( p );
+ assertEquals( "akarasulu", p.getUserId() );
+ assertEquals( "EXAMPLE.COM", p.getRealm() );
+ assertEquals( "example realm", p.getLabel() );
+ assertEquals( 27304238, p.getFactor() );
+ assertEquals( 0, p.getFailuresInEpoch() );
+ assertEquals( -1, p.getResynchCount() );
+ assertEquals( "test account", p.getInfo() );
+ }
+
+
+ /**
+ * Tests updating a profile.
+ *
+ * @throws Exception if it fails
+ */
+ public void testUpdate() throws Exception
+ {
+ KerberosPrincipal principal = new KerberosPrincipal( "akarasulu@EXAMPLE.COM" );
+ ServerProfile p = store.getProfile( principal );
+ assertNotNull( p );
+ assertEquals( "akarasulu", p.getUserId() );
+ assertEquals( "EXAMPLE.COM", p.getRealm() );
+ assertEquals( "example realm", p.getLabel() );
+ assertEquals( 27304238, p.getFactor() );
+ assertEquals( 0, p.getFailuresInEpoch() );
+ assertEquals( -1, p.getResynchCount() );
+ assertEquals( "test account", p.getInfo() );
+
+ BaseServerProfileModifier modifier = new BaseServerProfileModifier( p );
+ modifier.setFailuresInEpoch( 123 );
+ modifier.setResynchCount( 0 );
+ modifier.setFactor( 27304238 + 1 );
+ store.update( principal, modifier.getServerProfile() );
+
+ ServerProfile updated = store.getProfile( principal );
+ assertEquals( 123, updated.getFailuresInEpoch() );
+ assertEquals( 0, updated.getResynchCount() );
+ assertEquals( 27304239, updated.getFactor() );
+ }
+
+
+ /**
+ * Tests adding a profile.
+ *
+ * @throws Exception if it fails
+ */
+ public void testAddProfile() throws Exception
+ {
+ for ( int ii = 0; ii < ProfileTestData.PROFILES.length; ii++ )
+ {
+ ServerProfile profile = ProfileTestData.PROFILES[ii];
+ String name = profile.getUserId() + "@" + profile.getRealm();
+ KerberosPrincipal principal = new KerberosPrincipal( name );
+
+ if ( ! store.hasProfile( principal ) )
+ {
+ store.add( profile );
+ }
+
+ profile = store.getProfile( principal );
+ assertNotNull( profile );
+ assertEquals( profile.getFactor(), profile.getFactor() );
+ assertEquals( profile.getUserId(), profile.getUserId() );
+ assertEquals( profile.getFailuresInEpoch(), profile.getFailuresInEpoch() );
+ assertEquals( profile.getInfo(), profile.getInfo() );
+ assertEquals( profile.getLabel(), profile.getLabel() );
+ assertEquals( profile.getRealm(), profile.getRealm() );
+ assertEquals( profile.getResynchCount(), profile.getResynchCount() );
+ assertEquals( profile.getSecret(), profile.getSecret() );
+ }
+ }
+}
Added: directory/trunks/triplesec/store/src/test/java/org/safehaus/triplesec/store/interceptor/ApplicationACIManagerITest.java
URL: http://svn.apache.org/viewvc/directory/trunks/triplesec/store/src/test/java/org/safehaus/triplesec/store/interceptor/ApplicationACIManagerITest.java?view=auto&rev=486187
==============================================================================
--- directory/trunks/triplesec/store/src/test/java/org/safehaus/triplesec/store/interceptor/ApplicationACIManagerITest.java (added)
+++ directory/trunks/triplesec/store/src/test/java/org/safehaus/triplesec/store/interceptor/ApplicationACIManagerITest.java Tue Dec 12 07:23:31 2006
@@ -0,0 +1,366 @@
+/*
+ * 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.safehaus.triplesec.store.interceptor;
+
+
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Set;
+
+import javax.naming.Context;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
+import javax.naming.NoPermissionException;
+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.unit.AbstractAdminTestCase;
+import org.apache.directory.server.core.schema.bootstrap.SystemSchema;
+import org.apache.directory.server.core.schema.bootstrap.CoreSchema;
+import org.apache.directory.server.core.schema.bootstrap.Krb5kdcSchema;
+import org.apache.directory.server.core.configuration.Configuration;
+import org.apache.directory.server.core.configuration.MutablePartitionConfiguration;
+import org.apache.directory.server.core.configuration.MutableInterceptorConfiguration;
+import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition;
+import org.apache.directory.shared.ldap.message.LockableAttributeImpl;
+import org.apache.directory.shared.ldap.message.LockableAttributesImpl;
+import org.apache.directory.shared.ldap.name.LdapDN;
+import org.safehaus.triplesec.store.ProfileObjectFactory;
+import org.safehaus.triplesec.store.ProfileStateFactory;
+import org.safehaus.triplesec.store.schema.SafehausSchema;
+
+
+/**
+ * Test case for the PolicyProtectionInterceptor.
+ *
+ * @author Trustin Lee
+ * @version $Rev: 946 $, $Date: 2006-09-18 22:59:56 -0400 (Mon, 18 Sep 2006) $
+ */
+public class ApplicationACIManagerITest extends AbstractAdminTestCase
+{
+ private DirContext ctx;
+
+
+ public void setUp() throws Exception
+ {
+ Set schemas = super.configuration.getBootstrapSchemas();
+ schemas.add( new CoreSchema() );
+ schemas.add( new SystemSchema() );
+ schemas.add( new Krb5kdcSchema() );
+ schemas.add( new SafehausSchema() );
+ super.configuration.setBootstrapSchemas( schemas );
+ super.configuration.setShutdownHookEnabled( false );
+
+ MutablePartitionConfiguration partitionCfg = new MutablePartitionConfiguration();
+ partitionCfg.setName( "example" );
+ partitionCfg.setSuffix( "dc=example,dc=com" );
+ Attributes ctxEntry = new LockableAttributesImpl();
+ ctxEntry.put( "objectClass", "top" );
+ ctxEntry.put( "dc", "example" );
+ ctxEntry.put( "administrativeRole", "accessControlSpecificArea" );
+ partitionCfg.setContextEntry( ctxEntry );
+ partitionCfg.setContextPartition( new JdbmPartition() );
+
+ Set partitions = super.configuration.getContextPartitionConfigurations();
+ partitions.add( partitionCfg );
+ super.configuration.setContextPartitionConfigurations( partitions );
+
+ List interceptors = super.configuration.getInterceptorConfigurations();
+ MutableInterceptorConfiguration interceptorCfg = new MutableInterceptorConfiguration();
+ interceptorCfg.setName( "protector" );
+ interceptorCfg.setInterceptor( new PolicyProtectionInterceptor() );
+ interceptors.add( interceptorCfg );
+ super.configuration.setInterceptorConfigurations( interceptors );
+ super.configuration.setAccessControlEnabled( true );
+
+ super.overrideEnvironment( Context.OBJECT_FACTORIES, ProfileObjectFactory.class.getName() );
+ super.overrideEnvironment( Context.STATE_FACTORIES, ProfileStateFactory.class.getName() );
+ super.setLdifPath( "/interceptor.ldif", getClass() );
+ super.setUp();
+
+ Hashtable env = new Hashtable();
+ env.put( Context.INITIAL_CONTEXT_FACTORY, "org.apache.directory.server.core.jndi.CoreContextFactory" );
+ env.put( Context.PROVIDER_URL, "" );
+ env.put( Context.SECURITY_PRINCIPAL, "uid=admin,ou=system" );
+ env.put( Context.SECURITY_AUTHENTICATION, "simple" );
+ env.put( Context.SECURITY_CREDENTIALS, "secret" );
+ env.put( Configuration.JNDI_KEY, super.configuration );
+ env.put( Context.STATE_FACTORIES, ProfileStateFactory.class.getName() );
+ env.put( Context.OBJECT_FACTORIES, ProfileObjectFactory.class.getName() );
+
+ ctx = new InitialDirContext( env );
+ }
+
+
+ public void tearDown() throws Exception
+ {
+ super.tearDown();
+ }
+
+
+ private void assertNoAccessToAdminGroupByApp( String appName, String userPassword ) throws Exception
+ {
+ if ( userPassword == null )
+ {
+ userPassword = "secret";
+ }
+
+ LdapDN dn = new LdapDN( "appName="+appName+",ou=Applications,dc=example,dc=com" );
+
+ Hashtable env = new Hashtable();
+ 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, dn.getUpName() );
+ env.put( Context.SECURITY_AUTHENTICATION, "simple" );
+ env.put( Context.SECURITY_CREDENTIALS, userPassword );
+ env.put( Configuration.JNDI_KEY, super.configuration );
+ env.put( Context.STATE_FACTORIES, ProfileStateFactory.class.getName() );
+ env.put( Context.OBJECT_FACTORIES, ProfileObjectFactory.class.getName() );
+
+ InitialDirContext ctx = new InitialDirContext( env );
+
+ try
+ {
+ ctx.lookup( "cn=" + appName + "AdminGroup,ou=Groups" );
+ fail( dn + " should not have access to it's admin group" );
+ }
+ catch( NoPermissionException e )
+ {
+ }
+ }
+
+
+ private boolean aciItemsExist( String appName ) throws Exception
+ {
+ // check for the Aci just for the application's access
+ LdapDN dn = new LdapDN( "cn="+appName+"Aci,dc=example,dc=com" );
+
+ try
+ {
+ Attributes attrs = ctx.getAttributes( dn, new String[] { "cn", "objectClass",
+ "subtreeSpecification", "prescriptiveACI" } );
+
+ if ( attrs == null )
+ {
+ return false;
+ }
+
+ Attribute prescriptiveACI = attrs.get( "prescriptiveACI" );
+
+ if ( prescriptiveACI == null )
+ {
+ return false;
+ }
+
+ return true;
+ }
+ catch ( NameNotFoundException e )
+ {
+ return false;
+ }
+ }
+
+
+ private boolean adminGroupExists( String appName ) throws Exception
+ {
+ LdapDN dn = new LdapDN( "cn="+appName+"AdminGroup,ou=Groups,dc=example,dc=com" );
+
+ try
+ {
+ Attributes attrs = ctx.getAttributes( dn );
+ if ( attrs == null )
+ {
+ return false;
+ }
+
+ Attribute uniqueMembers = attrs.get( "uniqueMember" );
+
+ if ( uniqueMembers == null )
+ {
+ return false;
+ }
+
+ return true;
+ }
+ catch ( NameNotFoundException e )
+ {
+ return false;
+ }
+ }
+
+
+ private DirContext getAppContextAsApp( String appName ) throws NamingException
+ {
+ return getAppContextAsApp( appName, null );
+ }
+
+
+ private DirContext getAppContextAsApp( String appName, String userPassword ) throws NamingException
+ {
+ if ( userPassword == null )
+ {
+ userPassword = "secret";
+ }
+
+ LdapDN dn = new LdapDN( "appName="+appName+",ou=Applications,dc=example,dc=com" );
+
+ Hashtable env = new Hashtable();
+ env.put( Context.INITIAL_CONTEXT_FACTORY, "org.apache.directory.server.core.jndi.CoreContextFactory" );
+ env.put( Context.PROVIDER_URL, dn.getUpName() );
+ env.put( Context.SECURITY_PRINCIPAL, dn.getUpName() );
+ env.put( Context.SECURITY_AUTHENTICATION, "simple" );
+ env.put( Context.SECURITY_CREDENTIALS, userPassword );
+ env.put( Configuration.JNDI_KEY, super.configuration );
+ env.put( Context.STATE_FACTORIES, ProfileStateFactory.class.getName() );
+ env.put( Context.OBJECT_FACTORIES, ProfileObjectFactory.class.getName() );
+
+ return new InitialDirContext( env );
+ }
+
+
+ private void createApplication( String appName, String userPassword ) throws NamingException
+ {
+ // create the main application entry
+ Attributes attrs = new LockableAttributesImpl();
+ Attribute oc = new LockableAttributeImpl( "objectClass" );
+ oc.add( "top" );
+ oc.add( "policyApplication" );
+ attrs.put( oc );
+ attrs.put( "appName", appName );
+ if ( userPassword != null )
+ {
+ attrs.put( "userPassword", userPassword );
+ }
+ LdapDN dn = new LdapDN( "appName="+appName+",ou=Applications,dc=example,dc=com" );
+ ctx.createSubcontext( dn, attrs );
+
+ // create ou=permissions
+ attrs = new LockableAttributesImpl();
+ oc = new LockableAttributeImpl( "objectClass" );
+ oc.add( "top" );
+ oc.add( "organizationalUnit" );
+ attrs.put( oc );
+ attrs.put( "ou", "permissions" );
+ dn = new LdapDN( "ou=permissions,appName="+appName+",ou=Applications,dc=example,dc=com" );
+ ctx.createSubcontext( dn, attrs );
+
+ // create ou=roles
+ attrs = new LockableAttributesImpl();
+ oc = new LockableAttributeImpl( "objectClass" );
+ oc.add( "top" );
+ oc.add( "organizationalUnit" );
+ attrs.put( oc );
+ attrs.put( "ou", "roles" );
+ dn = new LdapDN( "ou=roles,appName="+appName+",ou=Applications,dc=example,dc=com" );
+ ctx.createSubcontext( dn, attrs );
+
+ // create ou=profiles
+ attrs = new LockableAttributesImpl();
+ oc = new LockableAttributeImpl( "objectClass" );
+ oc.add( "top" );
+ oc.add( "organizationalUnit" );
+ attrs.put( oc );
+ attrs.put( "ou", "profiles" );
+ dn = new LdapDN( "ou=profiles,appName="+appName+",ou=Applications,dc=example,dc=com" );
+ ctx.createSubcontext( dn, attrs );
+ }
+
+
+ public void addAppUserToAdminGroup( String appName ) throws NamingException
+ {
+ LdapDN dn = new LdapDN( "appName="+appName+",ou=Applications,dc=example,dc=com" );
+ Attributes attrs = new LockableAttributesImpl();
+ attrs.put( "uniqueMember", dn.getUpName() );
+
+ ctx.modifyAttributes( "cn=" + appName + "AdminGroup,ou=Groups,dc=example,dc=com",
+ DirContext.ADD_ATTRIBUTE, attrs );
+ }
+
+
+ private boolean canWriteToPermissions( String appName ) throws NamingException
+ {
+ DirContext appUserCtx = getAppContextAsApp( appName );
+ Attributes attrs = new LockableAttributesImpl();
+ attrs.put( "objectClass", "policyPermission" );
+ attrs.put( "permName", "testPerm" );
+
+ try
+ {
+ appUserCtx.createSubcontext( "permName=testPerm,ou=permissions", attrs );
+ return true;
+ }
+ catch ( NoPermissionException e )
+ {
+ return false;
+ }
+ finally
+ {
+ try
+ {
+ appUserCtx.destroySubcontext( "permName=testPerm,ou=permissions" );
+ }
+ catch( Throwable t )
+ {
+ }
+ }
+ }
+
+
+ public void testAddApplication() throws Exception
+ {
+ createApplication( "testApp", "secret" );
+ assertTrue( adminGroupExists( "testApp" ) );
+ assertTrue( aciItemsExist( "testApp" ) );
+ assertNoAccessToAdminGroupByApp( "testApp", "secret" );
+ assertFalse( canWriteToPermissions( "testApp" ) );
+ addAppUserToAdminGroup( "testApp" );
+ assertTrue( canWriteToPermissions( "testApp" ) );
+ }
+
+
+ public void testRemoveApplication() throws Exception
+ {
+ testAddApplication();
+ destroyApplication( "testApp" );
+ assertFalse( adminGroupExists( "testApp" ) );
+ assertFalse( aciItemsExist( "testApp" ) );
+ }
+
+
+ private void destroyApplication( String appName ) throws Exception
+ {
+ DirContext appCtx = ( DirContext ) ctx.lookup( "appName="+appName+",ou=Applications,dc=example,dc=com" );
+ appCtx.destroySubcontext( "ou=permissions" );
+ appCtx.destroySubcontext( "ou=profiles" );
+ appCtx.destroySubcontext( "ou=roles" );
+ appCtx.close();
+
+ ctx.destroySubcontext( "appName="+appName+",ou=Applications,dc=example,dc=com" );
+ }
+
+
+ public static void main( String[] args )
+ {
+ junit.textui.TestRunner.run( ApplicationACIManagerITest.class );
+ }
+}
+