//Warning: This code has been marked up for HTML

/**************************************************************************
*  Novell Software Developer Kit
*
*  Copyright (C) 2002-2003 Novell, Inc. All Rights Reserved.
*
*  THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
*  USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE AGREEMENT
*  ACCOMPANYING THE SOFTWARE DEVELOPER KIT (SDK) THAT CONTAINS THIS WORK.
*  PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS TO DEVELOPER A
*  ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S SAMPLE CODE IN ITS
*  PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION RIGHTS TO MARKET,
*  DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT OF DEVELOPER'S
*  PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR DEVELOPER'S
*  CUSTOMERS WITH RESPECT TO THIS CODE.
*
* $name:         ModifyACL.java
* $description:  ModifyACL.java first modifies the acl values of the entry
*                difined by the testEntryDN to grant the read, write, and
*                delete entry rights to the entry specified by the trusteeDN.
*                It then dispalys the acl values of the test entry. Finaly it
*                removes the modified acl value of the test entry.
*
*                acl is a multivalued attribute. each of acl values is in the
*                form of "privileges#scope#subjectname#protectedattrname".
*
*                modify() will throw exception if the object specified by
*                entryDN or trusteeDN is non-existing.
*
*                acl: access control list.
******************************************************************************/
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.Attributes;
import javax.naming.directory.Attribute;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.ModificationItem;

class ModifyACL 
    implements com.novell.service.ndssdk.jndi.ldap.ext.LDAPDSConstants {

    public static void main(String[] args) {

        String attrName;
        String attrValue;
        int    privileges = 0;

        if (args.length != 5) {
            usage();
        }

        String hostURL   = args[0];
        String loginDN   = args[1];
        String password  = args[2];
        String entryDN   = args[3];
        String trusteeDN = args[4];

       // encode acl value

        privileges |= LDAP_DS_ENTRY_BROWSE;
        privileges |= LDAP_DS_ENTRY_ADD;
        privileges |= LDAP_DS_ENTRY_DELETE;
        String aclValue = Integer.toString(privileges)+ "#" + "entry" + "#"
                                  + trusteeDN + "#" + "[Entry Rights]";

        try {
            Hashtable env = new Hashtable();
            env.put(Context.INITIAL_CONTEXT_FACTORY,
                                       "com.sun.jndi.ldap.LdapCtxFactory");
            env.put(Context.PROVIDER_URL, hostURL);
            env.put( Context.SECURITY_PRINCIPAL, loginDN );
            env.put( Context.SECURITY_CREDENTIALS, password );

           // create the initial directory context

            DirContext ctx = new InitialDirContext(env);

           // modify ENTRYDN's ACL attribute

            System.out.println( "\n    Entry DN: " + entryDN );
            System.out.println( "    Trustee DN: " + trusteeDN );
            System.out.println( "\n    Modifying entry DN's ACL value...");

           // construct the ModificationItem

            ModificationItem[] mod = new ModificationItem[1];

           // Add new value to ACL attribute

            Attribute modACL = new BasicAttribute("acl", aclValue);
            mod[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, modACL);

           // modify ACL

            ctx.modifyAttributes(entryDN, mod);
            System.out.println( "    Modification was successful." );

           // return entry DN's ACL attribute

            String returnAttrs[] = { "acl"};

           // get ENTRYDN's ACL attributes

            Attributes attrs = ctx.getAttributes( entryDN, returnAttrs );

           // get Enumeration of returned attributes (only ACL)

            NamingEnumeration ae = attrs.getAll();

           // print out ACL attributes

            while ( ae.hasMore() ) {
                Attribute attr = (Attribute)ae.next();
                NamingEnumeration attrValues = attr.getAll();
                System.out.println();
                System.out.println("    ====================================");
                System.out.println("    Entry DN's ACL values:");
                System.out.println("    ====================================");

                while ( attrValues.hasMore() &&
                        ( attrValue = (String)attrValues.next() ) != null )
                    PrintACLValue( attrValue );
            }

           // remove the modified ACL value

            System.out.println( "\n    Removing newly added ACL value..." );
            mod[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, modACL);
            ctx.modifyAttributes(entryDN, mod);
            System.out.println( "    Removed the newly added ACL value." );

           // close the context

            ctx.close();

        }
        catch (NamingException e) {
            System.err.println("ModifyACL example failed.");
            e.printStackTrace();
        }
        finally {
            System.exit(0);
        }
    }

   // PrintACLValue() parses and prints the entry DN's ACL values

    public static void PrintACLValue( String ACLValue ) {

        int    privileges;
        String scope, trusteeName, protName;

       // ACL value format: "privileges#scope#subjectname#protectedattrname".

        privileges = Integer.parseInt(
                         ACLValue.substring( 0, ACLValue.indexOf((int)'#')) );
        protName = ACLValue.substring(
                       ACLValue.lastIndexOf((int)'#') + 1, ACLValue.length());
       // truncate ACL value to "scope#subjectname"

        ACLValue = ACLValue.substring(
             ACLValue.indexOf((int)'#') + 1, ACLValue.lastIndexOf((int)'#') );
        scope = ACLValue.substring( 0, ACLValue.indexOf((int)'#') );
        trusteeName = ACLValue.substring(
                          ACLValue.indexOf((int)'#') + 1, ACLValue.length() );

        StringBuffer privs = new StringBuffer();
        if ( protName.equalsIgnoreCase("[Entry Rights]")) {
           // decode [Entry Rights]

            if ( (privileges & LDAP_DS_ENTRY_BROWSE) != 0 )
                privs.append("BrowseEntry ");
            if ( (privileges & LDAP_DS_ENTRY_ADD) != 0 )
                privs.append("AddEntry ");
            if ( (privileges & LDAP_DS_ENTRY_DELETE) != 0 )
                privs.append("DeleteEntry ");
            if ( (privileges & LDAP_DS_ENTRY_RENAME) != 0 )
                privs.append("RenameEntry ");
            if ( (privileges & LDAP_DS_ENTRY_SUPERVISOR) != 0 )
                privs.append("Supervisor");
         }
         else {
           // decode [All Attributes rights] attribute rights

            if ( (privileges & LDAP_DS_ATTR_COMPARE) != 0 )
                privs.append("CompareAttributes ");
            if ( (privileges & LDAP_DS_ATTR_READ) != 0 )
                privs.append("ReadAttributes ");
            if ( (privileges & LDAP_DS_ATTR_WRITE) != 0 )
                privs.append("Write/Add/DeleteAttributes ");
            if ( (privileges & LDAP_DS_ATTR_SELF) != 0 )
                privs.append("Add/DeleteSelf ");
            if ( (privileges & LDAP_DS_ATTR_SUPERVISOR) != 0 )
                privs.append("Supervisor");
         }

        System.out.println("    Trustee name: " + trusteeName + "\n    scope:"
                               + scope + "\n    Protected attribute name: "
                               + protName + "\n    Privileges: " + privs);
        System.out.println("    --------------------------------------------");
    }

    public static void usage() {
        System.err.println("\n Usage:   java ModifyACL <host URL> <login dn>"
                          +" <password> <entry dn>\n          <trustee dn>");
        System.err.println("\n Example: java ModifyACL ldap://Acme.com:389 "
                          + " \"cn=Admin,o=Acme\" secret"
                          + "\n          \"cn=test,ou=Sales,o=Acme\" "
                          + "\"cn=trustee,o=Acme\"");
        System.exit(1);
    }
}