1   /*
2    *   Copyright 2004 The Apache Software Foundation
3    *
4    *   Licensed under the Apache License, Version 2.0 (the "License");
5    *   you may not use this file except in compliance with the License.
6    *   You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *   Unless required by applicable law or agreed to in writing, software
11   *   distributed under the License is distributed on an "AS IS" BASIS,
12   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *   See the License for the specific language governing permissions and
14   *   limitations under the License.
15   *
16   */
17  package org.apache.ldap.server.authz;
18  
19  
20  import org.apache.ldap.common.exception.LdapNoPermissionException;
21  import org.apache.ldap.common.name.LdapName;
22  
23  import javax.naming.NamingException;
24  import javax.naming.directory.*;
25  
26  
27  /***
28   * Tests whether or not authorization around entry addition works properly.
29   *
30   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
31   * @version $Rev$
32   */
33  public class AddAuthorizationTest extends AbstractAuthorizationTest
34  {
35      /***
36       * Checks if a simple entry (organizationalUnit) can be added to the DIT at an
37       * RDN relative to ou=system by a specific non-admin user.  If a permission exception
38       * is encountered it is caught and false is returned, otherwise true is returned
39       * when the entry is created.  The entry is deleted after being created just in case
40       * subsequent calls to this method do not fail: the admin account is used to delete
41       * this test entry so permissions to delete are not required to delete it by the user.
42       *
43       * @param uid the unique identifier for the user (presumed to exist under ou=users,ou=system)
44       * @param password the password of this user
45       * @param entryRdn the relative DN, relative to ou=system where entry creation is tested
46       * @return true if the entry can be created by the user at the specified location, false otherwise
47       * @throws NamingException if there are problems conducting the test
48       */
49      public boolean checkCanAddEntryAs( String uid, String password, String entryRdn ) throws NamingException
50      {
51          Attributes testEntry = new BasicAttributes( "ou", "testou", true );
52          Attribute objectClass = new BasicAttribute( "objectClass" );
53          testEntry.put( objectClass );
54          objectClass.add( "top" );
55          objectClass.add( "organizationalUnit" );
56  
57          try
58          {
59              LdapName userName = new LdapName( "uid="+uid+",ou=users,ou=system" );
60              DirContext userContext = getContextAs( userName, password );
61              userContext.createSubcontext( entryRdn, testEntry );
62  
63              // delete the newly created context as the admin user
64              DirContext adminContext = getContextAsAdmin();
65              adminContext.destroySubcontext( entryRdn );
66  
67              return true;
68          }
69          catch ( LdapNoPermissionException e )
70          {
71              return false;
72          }
73      }
74  
75  
76      /***
77       * Checks to make sure group membership based userClass works for add operations.
78       *
79       * @throws NamingException if the test encounters an error
80       */
81      public void testGrantAddAdministrators() throws NamingException
82      {
83          // create the non-admin user
84          createUser( "billyd", "billyd" );
85  
86          // try an add operation which should fail without any ACI
87          assertFalse( checkCanAddEntryAs( "billyd", "billyd", "ou=testou" ) );
88  
89          // Gives grantAdd perm to all users in the Administrators group for
90          // entries and all attribute types and values
91          createAccessControlSubentry( "administratorAdd", "{ " +
92                  "identificationTag \"addAci\", " +
93                  "precedence 14, " +
94                  "authenticationLevel none, " +
95                  "itemOrUserFirst userFirst: { " +
96                  "userClasses { userGroup { \"cn=Administrators,ou=groups,ou=system\" } }, " +
97                  "userPermissions { { " +
98                  "protectedItems {entry, allUserAttributeTypesAndValues}, " +
99                  "grantsAndDenials { grantAdd, grantBrowse } } } } }" );
100 
101         // see if we can now add that test entry which we could not before
102         // add op should still fail since billd is not in the admin group
103         assertFalse( checkCanAddEntryAs( "billyd", "billyd", "ou=testou" ) );
104 
105         // now add billyd to the Administrator group and try again
106         addUserToGroup( "billyd", "Administrators" );
107 
108         // try an add operation which should succeed with ACI and group membership change
109         assertTrue( checkCanAddEntryAs( "billyd", "billyd", "ou=testou" ) );
110     }
111 
112 
113     /***
114      * Checks to make sure name based userClass works for add operations.
115      *
116      * @throws NamingException if the test encounters an error
117      */
118     public void testGrantAddByName() throws NamingException
119     {
120         // create the non-admin user
121         createUser( "billyd", "billyd" );
122 
123         // try an add operation which should fail without any ACI
124         assertFalse( checkCanAddEntryAs( "billyd", "billyd", "ou=testou" ) );
125 
126         // now add a subentry that enables user billyd to add an entry below ou=system
127         createAccessControlSubentry( "billydAdd", "{ " +
128                 "identificationTag \"addAci\", " +
129                 "precedence 14, " +
130                 "authenticationLevel none, " +
131                 "itemOrUserFirst userFirst: { " +
132                 "userClasses { name { \"uid=billyd,ou=users,ou=system\" } }, " +
133                 "userPermissions { { " +
134                 "protectedItems {entry, allUserAttributeTypesAndValues}, " +
135                 "grantsAndDenials { grantAdd, grantBrowse } } } } }" );
136 
137         // should work now that billyd is authorized by name
138         assertTrue( checkCanAddEntryAs( "billyd", "billyd", "ou=testou" ) );
139     }
140 
141 
142     /***
143      * Checks to make sure subtree based userClass works for add operations.
144      *
145      * @throws NamingException if the test encounters an error
146      */
147     public void testGrantAddBySubtree() throws NamingException
148     {
149         // create the non-admin user
150         createUser( "billyd", "billyd" );
151 
152         // try an add operation which should fail without any ACI
153         assertFalse( checkCanAddEntryAs( "billyd", "billyd", "ou=testou" ) );
154 
155         // now add a subentry that enables user billyd to add an entry below ou=system
156         createAccessControlSubentry( "billyAddBySubtree", "{ " +
157                 "identificationTag \"addAci\", " +
158                 "precedence 14, " +
159                 "authenticationLevel none, " +
160                 "itemOrUserFirst userFirst: { " +
161                 "userClasses { subtree { { base \"ou=users,ou=system\" } } }, " +
162                 "userPermissions { { " +
163                 "protectedItems {entry, allUserAttributeTypesAndValues}, " +
164                 "grantsAndDenials { grantAdd, grantBrowse } } } } }" );
165 
166         // should work now that billyd is authorized by the subtree userClass
167         assertTrue( checkCanAddEntryAs( "billyd", "billyd", "ou=testou" ) );
168     }
169 
170 
171     /***
172      * Checks to make sure <b>allUsers</b> userClass works for add operations.
173      *
174      * @throws NamingException if the test encounters an error
175      */
176     public void testGrantAddAllUsers() throws NamingException
177     {
178         // create the non-admin user
179         createUser( "billyd", "billyd" );
180 
181         // try an add operation which should fail without any ACI
182         assertFalse( checkCanAddEntryAs( "billyd", "billyd", "ou=testou" ) );
183 
184         // now add a subentry that enables anyone to add an entry below ou=system
185         createAccessControlSubentry( "anybodyAdd", "{ " +
186                 "identificationTag \"addAci\", " +
187                 "precedence 14, " +
188                 "authenticationLevel none, " +
189                 "itemOrUserFirst userFirst: { " +
190                 "userClasses { allUsers }, " +
191                 "userPermissions { { " +
192                 "protectedItems {entry, allUserAttributeTypesAndValues}, " +
193                 "grantsAndDenials { grantAdd, grantBrowse } } } } }" );
194 
195         // see if we can now add that test entry which we could not before
196         // should work now with billyd now that all users are authorized
197         assertTrue( checkCanAddEntryAs( "billyd", "billyd", "ou=testou" ) );
198     }
199 }