You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by sm...@apache.org on 2014/10/22 17:44:53 UTC

[34/51] [partial] Rename packages from org.openldap.fortress to org.apache.directory.fortress.core. Change default suffix to org.apache. Switch default ldap api from unbound to apache ldap.

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/687ee1ad/src/main/java/org/apache/directory/fortress/core/ldap/container/OrganizationalUnitDAO.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/ldap/container/OrganizationalUnitDAO.java b/src/main/java/org/apache/directory/fortress/core/ldap/container/OrganizationalUnitDAO.java
new file mode 100755
index 0000000..f2e05cd
--- /dev/null
+++ b/src/main/java/org/apache/directory/fortress/core/ldap/container/OrganizationalUnitDAO.java
@@ -0,0 +1,162 @@
+/*
+ *   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.fortress.core.ldap.container;
+
+
+import org.apache.directory.api.ldap.model.cursor.CursorException;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.fortress.core.CreateException;
+import org.apache.directory.fortress.core.RemoveException;
+import org.apache.directory.ldap.client.api.LdapConnection;
+import org.apache.directory.fortress.core.ldap.ApacheDsDataProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.directory.fortress.core.GlobalErrIds;
+import org.apache.directory.fortress.core.GlobalIds;
+import org.apache.directory.fortress.core.util.attr.VUtil;
+
+
+/**
+ * This class provides data access for the standard ldap object class Organizational Unit.  This
+ * entity is used to provide containers in DIT for organization of related nodes..
+ * A container node is used to group other related nodes, i.e. 'ou=People' or 'ou'Roles'.
+ * <br />The organizational unit object class is 'organizationalUnit' <br />
+ * <p/>
+ * The OrganizationalUnitDAO maintains the following structural object class:
+ * <p/>
+ * organizationalUnit Structural Object Class is used to store basic attributes like ou and description.
+ * <ul>
+ * <li>  ------------------------------------------
+ * <li> <code>objectclass ( 2.5.6.5 NAME 'organizationalUnit'</code>
+ * <li> <code>DESC 'RFC2256: an organizational unit'</code>
+ * <li> <code>SUP top STRUCTURAL</code>
+ * <li> <code>MUST ou</code>
+ * <li> <code>MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $</code>
+ * <li> <code>x121Address $ registeredAddress $ destinationIndicator $</code>
+ * <li> <code>preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $</code>
+ * <li> <code>telephoneNumber $ internationaliSDNNumber $</code>
+ * <li> <code>facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $</code>
+ * <li> <code>postalAddress $ physicalDeliveryOfficeName $ st $ l $ description ) )</code>
+ * <li>  ------------------------------------------
+ * </ul>
+ * <p/>
+ * This class is thread safe.
+ *
+ * @author Shawn McKinney
+ */
+final class OrganizationalUnitDAO extends ApacheDsDataProvider
+{
+    private static final String CLS_NM = OrganizationalUnitDAO.class.getName();
+    private static final Logger LOG = LoggerFactory.getLogger( CLS_NM );
+    private static final String ORGUNIT_CLASS = "organizationalunit";
+    private static final String[] ORGUNIT_OBJ_CLASS =
+        {
+            ORGUNIT_CLASS
+    };
+
+
+    /**
+     * Package private default constructor.
+     */
+    OrganizationalUnitDAO()
+    {
+    }
+
+
+    private String getSdRoot( String contextId )
+    {
+        return getRootDn( contextId, GlobalIds.SUFFIX );
+    }
+
+
+    /**
+     * @param oe
+     * @throws org.apache.directory.fortress.core.CreateException
+     */
+    final void create( OrganizationalUnit oe )
+        throws CreateException
+    {
+        LdapConnection ld = null;
+        String nodeDn = GlobalIds.OU + "=" + oe.getName() + ",";
+        if ( VUtil.isNotNullOrEmpty( oe.getParent() ) )
+            nodeDn += GlobalIds.OU + "=" + oe.getParent() + ",";
+        nodeDn += getRootDn( oe.getContextId() );
+        try
+        {
+            LOG.info( "create container dn [" + nodeDn + "]" );
+            Entry myEntry = new DefaultEntry( nodeDn );
+            myEntry.add( GlobalIds.OBJECT_CLASS, ORGUNIT_OBJ_CLASS );
+            myEntry.add( GlobalIds.OU, oe.getName() );
+            myEntry.add( GlobalIds.DESC, oe.getDescription() );
+            ld = getAdminConnection();
+            add( ld, myEntry );
+        }
+        catch ( LdapException e )
+        {
+            String error = "create container node dn [" + nodeDn + "] caught LDAPException="
+                + e.getMessage();
+            throw new CreateException( GlobalErrIds.CNTR_CREATE_FAILED, error, e );
+        }
+        finally
+        {
+            closeAdminConnection( ld );
+        }
+    }
+
+
+    /**
+     * @param oe
+     * @throws org.apache.directory.fortress.core.RemoveException
+     */
+    final void remove( OrganizationalUnit oe )
+        throws RemoveException
+    {
+        LdapConnection ld = null;
+        String nodeDn = GlobalIds.OU + "=" + oe.getName() + ",";
+        if ( VUtil.isNotNullOrEmpty( oe.getParent() ) )
+            nodeDn += GlobalIds.OU + "=" + oe.getParent() + ",";
+        nodeDn += getRootDn( oe.getContextId(), GlobalIds.SUFFIX );
+
+        LOG.info( "remove container dn [" + nodeDn + "]" );
+        try
+        {
+            ld = getAdminConnection();
+            deleteRecursive( ld, nodeDn );
+        }
+        catch ( CursorException e )
+        {
+            String error = "remove container node dn [" + nodeDn + "] caught CursorException="
+                + e.getMessage();
+            throw new RemoveException( GlobalErrIds.CNTR_DELETE_FAILED, error, e );
+        }
+        catch ( LdapException e )
+        {
+            String error = "remove container node dn [" + nodeDn + "] caught LDAPException="
+                + e.getMessage();
+            throw new RemoveException( GlobalErrIds.CNTR_DELETE_FAILED, error, e );
+        }
+        finally
+        {
+            closeAdminConnection( ld );
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/687ee1ad/src/main/java/org/apache/directory/fortress/core/ldap/container/OrganizationalUnitP.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/ldap/container/OrganizationalUnitP.java b/src/main/java/org/apache/directory/fortress/core/ldap/container/OrganizationalUnitP.java
new file mode 100755
index 0000000..7ce72d8
--- /dev/null
+++ b/src/main/java/org/apache/directory/fortress/core/ldap/container/OrganizationalUnitP.java
@@ -0,0 +1,147 @@
+/*
+ *   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.fortress.core.ldap.container;
+
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.directory.fortress.core.GlobalErrIds;
+import org.apache.directory.fortress.core.GlobalIds;
+import org.apache.directory.fortress.core.SecurityException;
+import org.apache.directory.fortress.core.ValidationException;
+import org.apache.directory.fortress.core.util.attr.VUtil;
+
+
+/**
+ * Process module for the container node used for grouping  related nodes within Fortress directory structure. The organizational unit represents
+ * the middle nodes that act as containers for other nodes, i.e. ou=People container which groups Users.
+ * The organizational unit data is passed using {@link OrganizationalUnit} class.  This class does perform simple data validations.
+ * The {@link org.apache.directory.fortress.core.ant.FortressAntTask#addContainers()} method calls the {@link #add} from this class during initial base loads.
+ * Removal {@link org.apache.directory.fortress.core.ant.FortressAntTask#deleteContainers()} is performed during regression tests and should never
+ * be executed targeting enabled production directory system datasets.<BR>
+ * This class will accept {@link OrganizationalUnit}, and forward on to it's corresponding DAO class {@link OrganizationalUnitDAO} for add/delete of container.
+ * <p>
+ * Class will throw {@link SecurityException} to caller in the event of security policy, data constraint violation or system
+ * error internal to DAO object. This class will forward DAO exceptions (
+ * {@link org.apache.directory.fortress.core.CreateException},,{@link org.apache.directory.fortress.core.RemoveException}),
+ *  or {@link org.apache.directory.fortress.core.ValidationException} as {@link org.apache.directory.fortress.core.SecurityException}s with appropriate
+ *  error id from {@link org.apache.directory.fortress.core.GlobalErrIds}.
+ * <p>
+ * <font size="3" color="red">
+ * The {@link #delete} method in this class is destructive as it will remove all nodes below the container using recursive delete function.<BR>
+ * Extreme care should be taken during execution to ensure target dn is correct and permanent removal of data is intended.  There is no
+ * 'undo' for this operation.
+ * </font>
+ * <p/>
+ * Simple error mapping is performed in {@link #validate} class.
+ * <p/>
+ * This class is thread safe.
+ *
+ * @author Shawn McKinney
+ */
+public class OrganizationalUnitP
+{
+    private static final String CLS_NM = OrganizationalUnitP.class.getName();
+    private static final Logger LOG = LoggerFactory.getLogger( CLS_NM );
+
+
+    /**
+     * Add a new container to the Directory Information Tree (DIT).  After added the
+     * node will be inserted after suffix, i.e. ou=NewContainerName, dc=companyName, dc=com.
+     *
+     * @param orgUnit contains the ou name and description for target node.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event node already present, {@link GlobalErrIds#CNTR_CREATE_FAILED}, validation, {@link GlobalErrIds#CNTR_NAME_NULL}, {@link org.apache.directory.fortress.core.GlobalErrIds#CNTR_NAME_INVLD} or system error.
+     */
+    public final void add( OrganizationalUnit orgUnit )
+        throws SecurityException
+    {
+        OrganizationalUnitDAO oDao = new OrganizationalUnitDAO();
+        oDao.create( orgUnit );
+    }
+
+
+    /**
+     * Remove a container from the Directory Information Tree (DIT).  After this operation the
+     * node will be removed after suffix.
+     *
+     * <p>
+     * <font size="4" color="red">
+     * The {@link #delete} method in this class is destructive as it will remove all nodes below the container using recursive delete function.<BR>
+     * Extreme care should be taken during execution to ensure target dn is correct and permanent removal of data is intended.  There is no
+     * 'undo' for this operation.
+     * </font>
+     * <p/>
+     *
+     * @param orgUnit contains the ou name of container targeted for removal.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event node not present, {@link org.apache.directory.fortress.core.GlobalErrIds#CNTR_DELETE_FAILED}, validation, {@link org.apache.directory.fortress.core.GlobalErrIds#CNTR_NAME_NULL}, {@link org.apache.directory.fortress.core.GlobalErrIds#CNTR_NAME_INVLD} or system error.
+     */
+    public final void delete( OrganizationalUnit orgUnit )
+        throws SecurityException
+    {
+        OrganizationalUnitDAO oDao = new OrganizationalUnitDAO();
+        oDao.remove( orgUnit );
+    }
+
+
+    /**
+     * Method will perform simple validations to ensure the integrity of the {@link OrganizationalUnit} entity targeted for insertion
+     * or deletion in directory.
+     *
+     * @param entity contains the enum type to validate
+     * @throws SecurityException thrown in the event the attribute is null.
+     */
+    private void validate( OrganizationalUnit entity )
+        throws SecurityException
+    {
+        if ( entity.getName().length() > GlobalIds.OU_LEN )
+        {
+            String name = entity.getName();
+            String error = "validate name [" + name + "] invalid length [" + entity.getName().length() + "]";
+            LOG.warn( error );
+            throw new ValidationException( GlobalErrIds.CNTR_NAME_INVLD, error );
+        }
+        if ( !VUtil.isNotNullOrEmpty( entity.getName() ) )
+        {
+            String error = "validate name validation failed, null or empty value";
+            LOG.warn( error );
+            throw new ValidationException( GlobalErrIds.CNTR_NAME_NULL, error );
+        }
+        if ( entity.getParent().length() > GlobalIds.OU_LEN )
+        {
+            String name = entity.getName();
+            String error = "validate parent [" + name + "] invalid length [" + entity.getName().length()
+                + "]";
+            LOG.warn( error );
+            throw new ValidationException( GlobalErrIds.CNTR_PARENT_INVLD, error );
+        }
+        if ( !VUtil.isNotNullOrEmpty( entity.getParent() ) )
+        {
+            String error = "validate parent validation failed, null or empty value";
+            LOG.warn( error );
+            throw new ValidationException( GlobalErrIds.CNTR_PARENT_NULL, error );
+        }
+        VUtil.safeText( entity.getDescription(), GlobalIds.DESC_LEN );
+        if ( VUtil.isNotNullOrEmpty( entity.getDescription() ) )
+        {
+            VUtil.description( entity.getDescription() );
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/687ee1ad/src/main/java/org/apache/directory/fortress/core/ldap/container/package.html
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/ldap/container/package.html b/src/main/java/org/apache/directory/fortress/core/ldap/container/package.html
new file mode 100755
index 0000000..3f386af
--- /dev/null
+++ b/src/main/java/org/apache/directory/fortress/core/ldap/container/package.html
@@ -0,0 +1,36 @@
+<!--
+ *   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.
+ *
+-->
+<html>
+   <head>
+      <title>Package Documentation for org.apache.directory.fortress.ldap.container</title>
+   </head>
+   <body>
+      <p>
+         This package contains APIs to perform CRUD on fortress container objects in ldap.
+      </p>
+      <p>
+         The <b>org.apache.directory.fortress.ldap.container</b> package provides apis to add and
+          remove ldap <b>OrganizationalUnit</b> entries.  These entries are called 'containers'
+          and are used to organize related fortress nodes.  An example container is <b>ou=People</b> which will be placed as a
+          child node of the directory's ldap suffix, i.e. <b>dc=example,dc=com</b>.  The container is used to store subentries, i.e. <b>inetOrgPerson</b>.
+          These container APIs are used by buildup/teardown processes.
+      </p>
+   </body>
+</html>

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/687ee1ad/src/main/java/org/apache/directory/fortress/core/ldap/group/Group.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/ldap/group/Group.java b/src/main/java/org/apache/directory/fortress/core/ldap/group/Group.java
new file mode 100755
index 0000000..2488205
--- /dev/null
+++ b/src/main/java/org/apache/directory/fortress/core/ldap/group/Group.java
@@ -0,0 +1,421 @@
+/*
+ *   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.fortress.core.ldap.group;
+
+
+import org.apache.directory.fortress.core.rbac.FortEntity;
+import org.apache.directory.fortress.core.rbac.Props;
+import org.apache.directory.fortress.core.util.attr.AttrHelper;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+@XmlRootElement(name = "fortGroup")
+@XmlAccessorType( XmlAccessType.FIELD)
+@XmlType(name = "group", propOrder =
+    {
+        "name",
+        "description",
+        "protocol",
+        "members",
+        "props",
+    })
+public class Group extends FortEntity implements Serializable
+{
+    private String name;
+    private String description;
+    private String protocol;
+    private List<String> members;
+    private Props props = new Props();
+    boolean memberDn;
+
+    /**
+     * Default constructor used by {@link org.apache.directory.fortress.core.ant.FortressAntTask}
+     */
+    public Group()
+    {
+    }
+
+    /**
+     * Generate instance of group to be loaded as ldap object.
+     *
+     * @param name        maps to 'cn' attribute in group object class.
+     */
+    public Group( String name )
+    {
+        this.name = name;
+    }
+
+    /**
+     * Generate instance of group to be loaded as ldap object.
+     *
+     * @param name        maps to 'cn' attribute in group object class.
+     * @param description maps to 'description' attribute in group object class.
+     */
+    public Group( String name, String description )
+    {
+        this.name = name;
+        this.description = description;
+    }
+
+    /**
+     * Get the second level qualifier on the domain component.  This attribute is required.
+     *
+     * @return name maps to 'dcObject' object class.
+     */
+    public String getName()
+    {
+        return name;
+    }
+
+    /**
+     * Set the second level qualifier on the domain component.  This attribute is required.
+     *
+     * @param name maps to 'dcObject' object class.
+     */
+    public void setName(String name)
+    {
+        this.name = name;
+    }
+
+    /**
+     * Get the description for the domain component.  This value is not required or constrained
+     * but is validated on reasonability.
+     *
+     * @return field maps to 'o' attribute on 'dcObject'.
+     */
+    public String getDescription()
+    {
+        return description;
+    }
+
+    /**
+     * Set the description for the domain component.  This value is not required or constrained
+     * but is validated on reasonability.
+     *
+     * @param description maps to 'o' attribute on 'dcObject'.
+     */
+    public void setDescription(String description)
+    {
+        this.description = description;
+    }
+
+    /**
+     * Get protocol qualifier for this entity.
+     *
+     * @return protocol.
+     */
+    public String getProtocol()
+    {
+        return protocol;
+    }
+
+    /**
+     * Set the protocol qualifier for this entity.
+     *
+     * @param protocol contains protocol qualifier for this entity.
+     */
+    public void setProtocol( String protocol )
+    {
+        this.protocol = protocol;
+    }
+
+    /**
+     * Add a single userId as member of this entity.
+     *
+     * @param userId
+     */
+    public void setMember( String userId )
+    {
+        if ( members == null )
+        {
+            members = new ArrayList<>();
+        }
+        members.add( userId );
+    }
+
+    /**
+     * Return the members
+     *
+     * @return List of type String containing userIds.
+     */
+    public List<String> getMembers()
+    {
+        return members;
+    }
+
+    /**
+     * Set a member on this entity using a comma delimited String.
+     *
+     * @param members String contains one or more userids in comma delimited format.
+     */
+    public void setMembers( String members )
+    {
+        if (members != null)
+        {
+            StringTokenizer tkn = new StringTokenizer(members, ",");
+            if (tkn.countTokens() > 0)
+            {
+                while (tkn.hasMoreTokens())
+                {
+                    String member = tkn.nextToken();
+                    setMember( member );
+                }
+            }
+        }
+    }
+
+    /**
+     * Set members onto this entity using a List of userIds.
+     *
+     * @param members List of type String contains userIds to be associated as members of this group.
+     */
+    public void setMembers( List<String> members )
+    {
+        this.members = members;
+    }
+
+    /**
+     * Add name/value pair to list of properties associated with PermObj.  These values are not constrained by Fortress.
+     * Properties are optional.
+     *
+     * @param key   contains property name and maps to 'ftProps' attribute in 'ftProperties' aux object class.
+     * @param value
+     */
+    public void addProperty( String key, String value )
+    {
+        Props.Entry entry = new Props.Entry();
+        entry.setKey( key );
+        entry.setValue( value );
+        this.props.getEntry().add( entry );
+    }
+
+    /**
+     * Get a name/value pair attribute from list of properties associated with PermObj.  These values are not constrained by Fortress.
+     * Properties are optional.
+     *
+     * @param key contains property name and maps to 'ftProps' attribute in 'ftProperties' aux object class.
+     * @return value containing name/value pair that maps to 'ftProps' attribute in 'ftProperties' aux object class.
+     */
+    public String getProperty( String key )
+    {
+        List<Props.Entry> props = this.props.getEntry();
+        Props.Entry keyObj = new Props.Entry();
+        keyObj.setKey( key );
+
+        String value = null;
+        int indx = props.indexOf( keyObj );
+        if ( indx != -1 )
+        {
+            Props.Entry entry = props.get( props.indexOf( keyObj ) );
+            value = entry.getValue();
+        }
+
+        return value;
+    }
+
+    /**
+     * Replace teh collection of name/value pairs to attributes associated with Group entity.  These values are not constrained by Fortress.
+     * Properties are optional.
+     *
+     * @param properties contains collection of name/value pairs and maps to 'ftProps' attribute in 'ftProperties' aux object class.
+     */
+    public void setProperties( Properties properties )
+    {
+        if ( properties != null )
+        {
+            // reset the existing properties stored in this entity.
+            props = new Props();
+            for ( Enumeration e = properties.propertyNames(); e.hasMoreElements(); )
+            {
+                // This LDAP attr is stored as a name-value pair separated by a ':'.
+                String key = ( String ) e.nextElement();
+                String val = properties.getProperty( key );
+                addProperty( key, val );
+            }
+        }
+    }
+
+    /**
+     * Add new collection of name=value pairs to attributes associated with Group.  These values are not constrained by Fortress.
+     * Properties are optional.
+     *
+     * @param properties contains name=value pairs that are comma delmited.
+     */
+    public void setProperties( String properties )
+    {
+        setProperties( AttrHelper.getProperties( properties, '=', "," ) );
+    }
+
+    /**
+     * Return the collection of name/value pairs to attributes associated with PermObj.  These values are not constrained by Fortress.
+     * Properties are optional.
+     *
+     * @return Properties contains collection of name/value pairs and maps to 'ftProps' attribute in 'ftProperties' aux object class.
+     */
+    public Properties getProperties()
+    {
+        Properties properties = null;
+        List<Props.Entry> props = this.props.getEntry();
+        if ( props.size() > 0 )
+        {
+            properties = new Properties();
+            //int size = props.size();
+            for ( Props.Entry entry : props )
+            {
+                String key = entry.getKey();
+                String val = entry.getValue();
+                properties.setProperty( key, val );
+            }
+        }
+        return properties;
+    }
+
+    public List<String> getPropList()
+    {
+        List<Props.Entry> props = this.props.getEntry();
+        List<String> propList = null;
+        if ( props.size() > 0 )
+        {
+            propList = new ArrayList<>(  );
+            for ( Props.Entry entry : props )
+            {
+                String key = entry.getKey();
+                String val = entry.getValue();
+                String prop = key + "=" + val;
+                propList.add( prop );
+            }
+        }
+        return propList;
+    }
+
+    /**
+     * Gets the value of the Props property.  This method is used by Fortress and En Masse and should not be called by external programs.
+     *
+     * @return {@link Props }
+     *
+     */
+    public Props getProps()
+    {
+        return props;
+    }
+
+    /**
+     * Sets the value of the Props property.  This method is used by Fortress and En Masse and should not be called by external programs.
+     *
+     * @param props
+     *     allowed object is
+     *     {@link Props }
+     *
+     */
+    public void setProps( Props props )
+    {
+        this.props = props;
+    }
+
+    /**
+     * Set if userDn's are loaded in dn format.
+     *
+     * @return true indicates members are in dn format.
+     */
+    public boolean isMemberDn()
+    {
+        return memberDn;
+    }
+
+    /**
+     * Set to 'true' if members are in dn format.
+     *
+     * @param memberDn boolean value, set to 'true' if distinguished name (dn) format, 'false' if relative distinguished name (rdn) format.
+     */
+    public void setMemberDn( boolean memberDn )
+    {
+        this.memberDn = memberDn;
+    }
+
+    @Override
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+        if ( o == null || getClass() != o.getClass() )
+        {
+            return false;
+        }
+
+        Group group = ( Group ) o;
+
+/*
+        if ( description != null ? !description.equals( group.description ) : group.description != null )
+        {
+            return false;
+        }
+        if ( members != null ? !members.equals( group.members ) : group.members != null )
+        {
+            return false;
+        }
+*/
+        if(name == null)
+            return false;
+
+        if ( !name.equals( group.name ) )
+        {
+            return false;
+        }
+/*
+        if ( protocol != null ? !protocol.equals( group.protocol ) : group.protocol != null )
+        {
+            return false;
+        }
+*/
+
+        return true;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        int result = name.hashCode();
+        result = 31 * result + ( description != null ? description.hashCode() : 0 );
+        result = 31 * result + ( protocol != null ? protocol.hashCode() : 0 );
+        result = 31 * result + ( members != null ? members.hashCode() : 0 );
+        result = 31 * result + ( props != null ? props.hashCode() : 0 );
+        return result;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Group{" +
+            "name='" + name + '\'' +
+            ", description='" + description + '\'' +
+            '}';
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/687ee1ad/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupDAO.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupDAO.java b/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupDAO.java
new file mode 100755
index 0000000..fc906ee
--- /dev/null
+++ b/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupDAO.java
@@ -0,0 +1,463 @@
+/*
+ *   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.fortress.core.ldap.group;
+
+
+import org.apache.directory.api.ldap.model.cursor.CursorException;
+import org.apache.directory.api.ldap.model.cursor.SearchCursor;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.DefaultModification;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Modification;
+import org.apache.directory.api.ldap.model.entry.ModificationOperation;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.exception.LdapNoSuchObjectException;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.ldap.client.api.LdapConnection;
+import org.apache.directory.fortress.core.FinderException;
+import org.apache.directory.fortress.core.ObjectFactory;
+import org.apache.directory.fortress.core.UpdateException;
+import org.apache.directory.fortress.core.cfg.Config;
+import org.apache.directory.fortress.core.ldap.ApacheDsDataProvider;
+import org.apache.directory.fortress.core.rbac.User;
+import org.apache.directory.fortress.core.util.attr.AttrHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.directory.fortress.core.CreateException;
+import org.apache.directory.fortress.core.GlobalErrIds;
+import org.apache.directory.fortress.core.GlobalIds;
+import org.apache.directory.fortress.core.RemoveException;
+import org.apache.directory.fortress.core.util.attr.VUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Contains the Group node for LDAP Directory Information Tree.
+ * This class is thread safe.
+ *
+ * @author Shawn McKinney
+ */
+final class GroupDAO extends ApacheDsDataProvider
+{
+    private static final String CLS_NM = GroupDAO.class.getName();
+    private static final Logger LOG = LoggerFactory.getLogger( CLS_NM );
+    private static final String GROUP_OBJECT_CLASS = "group.objectclass";
+    private static final String GROUP_OBJECT_CLASS_IMPL = Config.getProperty( GROUP_OBJECT_CLASS );
+    private static final String GROUP_PROTOCOL_ATTR = "group.protocol";
+    private static final String GROUP_PROTOCOL_ATTR_IMPL = Config.getProperty( GROUP_PROTOCOL_ATTR );
+    private static final String GROUP_PROPERTY_ATTR = "group.properties";
+    private static final String GROUP_PROPERTY_ATTR_IMPL = Config.getProperty( GROUP_PROPERTY_ATTR );
+    private static final String GROUP_OBJ_CLASS[] = {GlobalIds.TOP, GROUP_OBJECT_CLASS_IMPL};
+    private static final String MEMBER = "member";
+    private static final String[] GROUP_ATRS = {GlobalIds.CN, GlobalIds.DESC, GROUP_PROTOCOL_ATTR_IMPL, GROUP_PROPERTY_ATTR_IMPL, MEMBER};
+
+    /**
+     * Package private default constructor.
+     */
+    GroupDAO()
+    {
+    }
+
+    /**
+     * @param group
+     * @throws org.apache.directory.fortress.core.CreateException
+     *
+     */
+    final Group create( Group group ) throws CreateException
+    {
+        LdapConnection ld = null;
+        String nodeDn = getDn( group.getName(), group.getContextId() );
+        try
+        {
+            LOG.debug( "create group dn {[]}", nodeDn );
+            Entry myEntry = new DefaultEntry( nodeDn );
+            myEntry.add( GlobalIds.OBJECT_CLASS, GROUP_OBJ_CLASS );
+            myEntry.add( GlobalIds.CN , group.getName() );
+            myEntry.add( GROUP_PROTOCOL_ATTR_IMPL, group.getProtocol() );
+            loadAttrs( group.getMembers(), myEntry, MEMBER );
+            loadProperties( group.getProperties(), myEntry, GROUP_PROPERTY_ATTR_IMPL, '=' );
+            if ( VUtil.isNotNullOrEmpty( group.getDescription() ) )
+            {
+                myEntry.add( GlobalIds.DESC, group.getDescription() );
+            }
+            ld = getAdminConnection();
+            add( ld, myEntry );
+        }
+        catch ( LdapException e )
+        {
+            String error = "create group node dn [" + nodeDn + "] caught LDAPException=" + e.getMessage();
+            throw new CreateException( GlobalErrIds.GROUP_ADD_FAILED, error, e );
+        }
+        finally
+        {
+            closeAdminConnection( ld );
+        }
+        return group;
+    }
+
+    /**
+     * @param group
+     * @return
+     * @throws org.apache.directory.fortress.core.CreateException
+     *
+     */
+    final Group update( Group group ) throws FinderException, UpdateException
+    {
+        LdapConnection ld = null;
+        String nodeDn = getDn( group.getName(), group.getContextId() );
+        try
+        {
+            LOG.debug( "update group dn {[]}", nodeDn );
+            List<Modification> mods = new ArrayList<Modification>();
+            if ( VUtil.isNotNullOrEmpty( group.getDescription() ) )
+            {
+                mods.add( new DefaultModification(
+                    ModificationOperation.REPLACE_ATTRIBUTE, GlobalIds.DESC, group.getDescription() ) );
+            }
+            if ( VUtil.isNotNullOrEmpty( group.getProtocol() ) )
+            {
+                mods.add( new DefaultModification(
+                    ModificationOperation.REPLACE_ATTRIBUTE, GROUP_PROTOCOL_ATTR_IMPL, group.getProtocol() ) );
+            }
+            loadAttrs( group.getMembers(), mods, MEMBER );
+            loadProperties( group.getProperties(), mods, GROUP_PROPERTY_ATTR_IMPL, true, '=' );
+            if ( mods.size() > 0 )
+            {
+                ld = getAdminConnection();
+                modify( ld, nodeDn, mods, group );
+            }
+        }
+        catch ( LdapException e )
+        {
+            String error = "update group node dn [" + nodeDn + "] caught LDAPException=" + e.getMessage();
+            throw new UpdateException( GlobalErrIds.GROUP_UPDATE_FAILED, error, e );
+        }
+        finally
+        {
+            closeAdminConnection( ld );
+        }
+        return get( group );
+    }
+
+    final Group add( Group group, String key, String value ) throws FinderException, CreateException
+    {
+        LdapConnection ld = null;
+        String nodeDn = getDn( group.getName(), group.getContextId() );
+        try
+        {
+            LOG.debug( "add group property dn {[]}, key {[]}, value {[]}", nodeDn, key, value );
+            List<Modification> mods = new ArrayList<Modification>();
+            mods.add( new DefaultModification(
+                ModificationOperation.ADD_ATTRIBUTE, GROUP_PROPERTY_ATTR_IMPL, key + "=" + value ) );
+            ld = getAdminConnection();
+            modify( ld, nodeDn, mods, group );
+        }
+        catch ( LdapException e )
+        {
+            String error = "update group property node dn [" + nodeDn + "] caught LDAPException=" + e.getMessage();
+            throw new CreateException( GlobalErrIds.GROUP_ADD_PROPERTY_FAILED, error, e );
+        }
+        finally
+        {
+            closeAdminConnection( ld );
+        }
+        return get( group );
+    }
+
+    final Group delete( Group group, String key, String value ) throws FinderException, RemoveException
+    {
+        LdapConnection ld = null;
+        String nodeDn = getDn( group.getName(), group.getContextId() );
+        try
+        {
+            LOG.debug( "delete group property dn {[]}, key {[]}, value {[]}", nodeDn, key, value );
+            List<Modification> mods = new ArrayList<Modification>();
+            mods.add( new DefaultModification(
+                ModificationOperation.REMOVE_ATTRIBUTE, GROUP_PROPERTY_ATTR_IMPL, key + "=" + value ) );
+            ld = getAdminConnection();
+            modify( ld, nodeDn, mods, group );
+        }
+        catch ( LdapException e )
+        {
+            String error = "delete group property node dn [" + nodeDn + "] caught LDAPException=" + e.getMessage();
+            throw new RemoveException( GlobalErrIds.GROUP_DELETE_PROPERTY_FAILED, error, e );
+        }
+        finally
+        {
+            closeAdminConnection( ld );
+        }
+        return get( group );
+    }
+
+    /**
+     * This method will remove group node from diretory.
+     *
+     * @param group
+     * @throws org.apache.directory.fortress.core.RemoveException
+     *
+     */
+    final Group remove( Group group ) throws RemoveException
+    {
+        LdapConnection ld = null;
+        String nodeDn = getDn( group.getName(), group.getContextId() );
+        LOG.debug( "remove group dn {[]}", nodeDn );
+        try
+        {
+            ld = getAdminConnection();
+            deleteRecursive( ld, nodeDn );
+        }
+        catch ( CursorException e )
+        {
+            String error = "remove group node dn [" + nodeDn + "] caught CursorException="
+                + e.getMessage();
+            throw new RemoveException( GlobalErrIds.GROUP_DELETE_FAILED, error, e );
+        }
+        catch ( LdapException e )
+        {
+            String error = "remove group node dn [" + nodeDn + "] caught LDAPException=" + e.getMessage();
+            throw new RemoveException( GlobalErrIds.GROUP_DELETE_FAILED, error, e );
+        }
+        finally
+        {
+            closeAdminConnection( ld );
+        }
+        return group;
+    }
+
+    /**
+     * @param entity
+     * @param userDn
+     * @return
+     * @throws org.apache.directory.fortress.core.UpdateException
+     *
+     */
+    final Group assign( Group entity, String userDn ) throws FinderException, UpdateException
+    {
+        LdapConnection ld = null;
+        String dn = getDn( entity.getName(), entity.getContextId() );
+        LOG.debug( "assign group property dn {[]}, member dn {[]}", dn, userDn );
+        try
+        {
+            List<Modification> mods = new ArrayList<Modification>();
+            mods.add( new DefaultModification(
+                ModificationOperation.ADD_ATTRIBUTE, MEMBER, userDn ) );
+            ld = getAdminConnection();
+            modify( ld, dn, mods, entity );
+        }
+        catch ( LdapException e )
+        {
+            String error = "assign group name [" + entity.getName() + "] user dn [" + userDn + "] caught " +
+                "LDAPException=" + e.getMessage();
+            throw new UpdateException( GlobalErrIds.GROUP_USER_ASSIGN_FAILED, error, e );
+        }
+        finally
+        {
+            closeAdminConnection( ld );
+        }
+        return get( entity );
+    }
+
+    /**
+     * @param entity
+     * @param userDn
+     * @return
+     * @throws org.apache.directory.fortress.core.UpdateException
+     *
+     */
+    final Group deassign( Group entity, String userDn ) throws FinderException, UpdateException
+    {
+        LdapConnection ld = null;
+        String dn = getDn( entity.getName(), entity.getContextId() );
+        LOG.debug( "deassign group property dn {[]}, member dn {[]}", dn, userDn );
+        try
+        {
+            List<Modification> mods = new ArrayList<Modification>();
+            mods.add( new DefaultModification(
+                ModificationOperation.REMOVE_ATTRIBUTE, MEMBER, userDn ) );
+
+            ld = getAdminConnection();
+            modify( ld, dn, mods, entity );
+        }
+        catch ( LdapException e )
+        {
+            String error = "deassign group name [" + entity.getName() + "] user dn [" + userDn + "] caught " +
+                "LDAPException=" + e.getMessage();
+            throw new UpdateException( GlobalErrIds.GROUP_USER_DEASSIGN_FAILED, error, e );
+        }
+        finally
+        {
+            closeAdminConnection( ld );
+        }
+        return get( entity );
+    }
+
+    /**
+     * @param group
+     * @return
+     * @throws org.apache.directory.fortress.core.FinderException
+     *
+     */
+    final Group get( Group group ) throws FinderException
+    {
+        Group entity = null;
+        LdapConnection ld = null;
+        String dn = getDn( group.getName(), group.getContextId() );
+        try
+        {
+            ld = getAdminConnection();
+            Entry findEntry = read( ld, dn, GROUP_ATRS );
+            entity = unloadLdapEntry( findEntry, 0 );
+            if ( entity == null )
+            {
+                String warning = "read no entry found dn [" + dn + "]";
+                throw new FinderException( GlobalErrIds.GROUP_NOT_FOUND, warning );
+            }
+        }
+        catch ( LdapNoSuchObjectException e )
+        {
+            String warning = "read Obj COULD NOT FIND ENTRY for dn [" + dn + "]";
+            throw new FinderException( GlobalErrIds.GROUP_NOT_FOUND, warning );
+        }
+        catch ( LdapException e )
+        {
+            String error = "read dn [" + dn + "] LdapException=" + e.getMessage();
+            throw new FinderException( GlobalErrIds.GROUP_READ_FAILED, error, e );
+        }
+        finally
+        {
+            closeAdminConnection( ld );
+        }
+        return entity;
+    }
+
+    /**
+     * @param group
+     * @return
+     * @throws org.apache.directory.fortress.core.FinderException
+     *
+     */
+    final List<Group> find( Group group ) throws FinderException
+    {
+        List<Group> groupList = new ArrayList<>();
+        LdapConnection ld = null;
+        SearchCursor searchResults;
+        String groupRoot = getRootDn( group.getContextId(), GlobalIds.GROUP_ROOT );
+        String filter = null;
+        try
+        {
+            String searchVal = encodeSafeText( group.getName(), GlobalIds.ROLE_LEN );
+            filter = GlobalIds.FILTER_PREFIX + GROUP_OBJECT_CLASS_IMPL + ")(" + GlobalIds.CN + "=" + searchVal + "*))";
+            ld = getAdminConnection();
+            searchResults = search( ld, groupRoot, SearchScope.ONELEVEL, filter, GROUP_ATRS, false,
+                GlobalIds.BATCH_SIZE );
+            long sequence = 0;
+            while ( searchResults.next() )
+            {
+                groupList.add( unloadLdapEntry( searchResults.getEntry(), sequence++ ) );
+            }
+        }
+        catch ( CursorException e )
+        {
+            String error = "find filter [" + filter + "] caught CursorException=" + e.getMessage();
+            throw new FinderException( GlobalErrIds.GROUP_SEARCH_FAILED, error, e );
+        }
+        catch ( LdapException e )
+        {
+            String error = "find filter [" + filter + "] caught LDAPException=" + e.getMessage();
+            throw new FinderException( GlobalErrIds.GROUP_SEARCH_FAILED, error, e );
+        }
+        finally
+        {
+            closeAdminConnection( ld );
+        }
+        return groupList;
+    }
+
+    /**
+     * @param user
+     * @return
+     * @throws org.apache.directory.fortress.core.FinderException
+     *
+     */
+    final List<Group> find( User user ) throws FinderException
+    {
+        List<Group> groupList = new ArrayList<>();
+        LdapConnection ld = null;
+        SearchCursor searchResults;
+        String groupRoot = getRootDn( user.getContextId(), GlobalIds.GROUP_ROOT );
+        String filter = null;
+        try
+        {
+            String searchVal = encodeSafeText( user.getUserId(), GlobalIds.USERID_LEN );
+            filter = GlobalIds.FILTER_PREFIX + GROUP_OBJECT_CLASS_IMPL + ")(" + MEMBER + "=" + user.getDn() + "))";
+            ld = getAdminConnection();
+            searchResults = search( ld, groupRoot, SearchScope.ONELEVEL, filter, GROUP_ATRS, false,
+                GlobalIds.BATCH_SIZE );
+            long sequence = 0;
+            while ( searchResults.next() )
+            {
+                groupList.add( unloadLdapEntry( searchResults.getEntry(), sequence++ ) );
+            }
+        }
+        catch ( CursorException e )
+        {
+            String error = "find filter [" + filter + "] caught CursorException=" + e.getMessage();
+            throw new FinderException( GlobalErrIds.GROUP_SEARCH_FAILED, error, e );
+        }
+        catch ( LdapException e )
+        {
+            String error = "find filter [" + filter + "] caught LDAPException=" + e.getMessage();
+            throw new FinderException( GlobalErrIds.GROUP_SEARCH_FAILED, error, e );
+        }
+        finally
+        {
+            closeAdminConnection( ld );
+        }
+        return groupList;
+    }
+
+    /**
+     * @param le
+     * @param sequence
+     * @return
+     * @throws LdapException
+     */
+    private Group unloadLdapEntry( Entry le, long sequence )
+        throws LdapInvalidAttributeValueException
+    {
+        Group entity = new ObjectFactory().createGroup();
+        entity.setName( getAttribute( le, GlobalIds.CN ) );
+        entity.setDescription( getAttribute( le, GlobalIds.DESC ) );
+        entity.setProtocol( getAttribute( le, GROUP_PROTOCOL_ATTR_IMPL ) );
+        entity.setMembers( getAttributes( le, MEMBER ) );
+        entity.setMemberDn( true );
+        entity.setProperties( AttrHelper.getProperties( getAttributes( le, GROUP_PROPERTY_ATTR_IMPL ), '=' ) );
+        entity.setSequenceId( sequence );
+        return entity;
+    }
+
+    private String getDn( String name, String contextId )
+    {
+        return GlobalIds.CN + "=" + name + "," + getRootDn( contextId, GlobalIds.GROUP_ROOT );
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/687ee1ad/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupMgr.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupMgr.java b/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupMgr.java
new file mode 100755
index 0000000..2316de9
--- /dev/null
+++ b/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupMgr.java
@@ -0,0 +1,135 @@
+/*
+ *   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.fortress.core.ldap.group;
+
+import org.apache.directory.fortress.core.*;
+import org.apache.directory.fortress.core.SecurityException;
+import org.apache.directory.fortress.core.rbac.User;
+
+import java.util.List;
+
+/**
+ * This interface prescribes CRUD methods used to manage groups stored within the ldap directory.
+ * <p/>
+ * This class is thread safe.
+ * <p/>
+ *
+ * @author Shawn McKinney
+ */
+public interface GroupMgr extends Manageable
+{
+    /**
+     * Create a new group node.,
+     *
+     * @param group contains {@link Group}.
+     * @return {@link Group} containing entity just added.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event system error.
+     */
+    public Group add( Group group ) throws org.apache.directory.fortress.core.SecurityException;
+
+    /**
+     * Modify existing group node.  The name is required.  Does not update members or properties.
+     * Use {@link GroupMgr#add( Group group, String key, String value )}, {@link GroupMgr#delete( Group group, String key, String value )},
+     * {@link GroupMgr#assign( Group group, String member) }, or {@link GroupMgr#deassign( Group group, String member) } for multi-occurring attributes.
+     *
+     * @param group contains {@link Group}.
+     * @return {@link Group} containing entity just modified.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event system error.
+     */
+    public Group update( Group group ) throws SecurityException;
+
+    /**
+     * Delete existing group node.  The name is required.
+     *
+     * @param group contains {@link Group}.
+     * @return {@link Group} containing entity just removed.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event system error.
+     */
+    public Group delete( Group group ) throws SecurityException;
+
+    /**
+     * Add a property to an existing group node. Must have a name and at least one member.
+     *
+     * @param group contains {@link Group}.
+     * @param key contains the property key.
+     * @param value contains contains the property value.
+     * @return {@link Group} containing entity just modified.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event system error.
+     */
+    public Group add( Group group, String key, String value ) throws SecurityException;
+
+    /**
+     * Delete existing group node.  The name is required.
+     *
+     * @param group contains {@link Group}.
+     * @param key contains the property key.
+     * @param value contains contains the property value.
+     * @return {@link Group} containing entity just modified.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event system error.
+     */
+    public Group delete( Group group, String key, String value ) throws SecurityException;
+
+    /**
+     * Read an existing group node.  The name is required.
+     *
+     * @param group contains {@link Group} with name field set with an existing group name.
+     * @return {@link Group} containing entity found.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event system error.
+     */
+    public Group read( Group group ) throws SecurityException;
+
+    /**
+     * Search using a full or partial group node.  The name is required.
+     *
+     * @param group contains {@link Group}.
+     * @return List of type {@link Group} containing entities found.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event system error.
+     */
+    public List<Group> find( Group group ) throws SecurityException;
+
+    /**
+     * Search for groups by userId.  Member (maps to userId) and is required.
+     *
+     * @param user contains userId that maps to Group member attribute.
+     * @return {@link Group} containing entity just added.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event system error.
+     */
+    public List<Group> find( User user ) throws SecurityException;
+
+    /**
+     * Assign a user to an existing group node.  The group name and member are required.
+     *
+     * @param group contains {@link Group}.
+     * @param member is the relative distinguished name (rdn) of an existing user in ldap.
+     * @return {@link Group} containing entity to assign.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event entry already present or other system error.
+     */
+    public Group assign( Group group, String member ) throws SecurityException;
+
+    /**
+     * Deassign a member from an existing group node. The group name and member are required.
+     *
+     * @param group contains {@link Group}.
+     * @param member is the relative distinguished name (rdn) of an existing user in ldap.
+     * @return {@link Group} containing entity to deassign
+     * @throws org.apache.directory.fortress.core.SecurityException in the event entry already present or other system error.
+     */
+    public Group deassign( Group group, String member ) throws SecurityException;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/687ee1ad/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupMgrFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupMgrFactory.java b/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupMgrFactory.java
new file mode 100755
index 0000000..102587c
--- /dev/null
+++ b/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupMgrFactory.java
@@ -0,0 +1,107 @@
+/*
+ *   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.fortress.core.ldap.group;
+
+import org.apache.directory.fortress.core.GlobalErrIds;
+import org.apache.directory.fortress.core.GlobalIds;
+import org.apache.directory.fortress.core.cfg.Config;
+import org.apache.directory.fortress.core.rbac.ClassUtil;
+import org.apache.directory.fortress.core.SecurityException;
+import org.apache.directory.fortress.core.rbac.Session;
+import org.apache.directory.fortress.core.util.attr.VUtil;
+
+/**
+ * Creates an instance of the ConfigMgr object.
+ * <p/>
+ * The default implementation class is specified as {@link GroupMgrImpl} but can be overridden by
+ * adding the {@link org.apache.directory.fortress.core.GlobalIds#GROUP_IMPLEMENTATION} config property.
+ * <p/>
+
+ *
+ * @author Shawn McKinney
+ */
+public class GroupMgrFactory
+{
+    private static String groupClassName = Config.getProperty( GlobalIds.GROUP_IMPLEMENTATION );
+    private static final String CLS_NM = GroupMgrFactory.class.getName();
+
+    /**
+     * Create and return a reference to {@link GroupMgr} object using HOME context.
+     *
+     * @return instance of {@link org.apache.directory.fortress.core.AdminMgr}.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event of failure during instantiation.
+     */
+    public static GroupMgr createInstance()
+        throws SecurityException
+    {
+        return createInstance( GlobalIds.HOME );
+    }
+
+    /**
+     * Create and return a reference to {@link GroupMgr} object.
+     *
+     * @param contextId maps to sub-tree in DIT, for example ou=contextId, dc=jts, dc = com.
+     * @return instance of {@link GroupMgr}.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event of failure during instantiation.
+     */
+    public static GroupMgr createInstance(String contextId)
+        throws SecurityException
+    {
+        VUtil.assertNotNull( contextId, GlobalErrIds.CONTEXT_NULL, CLS_NM + ".createInstance" );
+        if (!VUtil.isNotNullOrEmpty(groupClassName))
+        {
+            groupClassName = GroupMgrImpl.class.getName();
+        }
+
+        GroupMgr groupMgr = (GroupMgr) ClassUtil.createInstance(groupClassName);
+        groupMgr.setContextId(contextId);
+        return groupMgr;
+    }
+
+
+    /**
+     * Create and return a reference to {@link GroupMgr} object using HOME context.
+     *
+     * @param adminSess contains a valid Fortress A/RBAC Session object.
+     * @return instance of {@link org.apache.directory.fortress.core.AdminMgr}.
+     * @throws SecurityException in the event of failure during instantiation.
+     */
+    public static GroupMgr createInstance(Session adminSess)
+        throws SecurityException
+    {
+        return createInstance( GlobalIds.HOME, adminSess );
+    }
+
+    /**
+     * Create and return a reference to {@link GroupMgr} object.
+     *
+     * @param contextId maps to sub-tree in DIT, for example ou=contextId, dc=jts, dc = com.
+     * @param adminSess contains a valid Fortress A/RBAC Session object.
+     * @return instance of {@link org.apache.directory.fortress.core.AdminMgr}.
+     * @throws SecurityException in the event of failure during instantiation.
+     */
+    public static GroupMgr createInstance(String contextId, Session adminSess)
+        throws SecurityException
+    {
+        GroupMgr groupMgr = createInstance(contextId);
+        groupMgr.setAdmin(adminSess);
+        return groupMgr;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/687ee1ad/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupMgrImpl.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupMgrImpl.java b/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupMgrImpl.java
new file mode 100755
index 0000000..8c5722a
--- /dev/null
+++ b/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupMgrImpl.java
@@ -0,0 +1,244 @@
+/*
+ *   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.fortress.core.ldap.group;
+
+import org.apache.directory.fortress.core.*;
+import org.apache.directory.fortress.core.SecurityException;
+import org.apache.directory.fortress.core.rbac.Manageable;
+import org.apache.directory.fortress.core.rbac.User;
+import org.apache.directory.fortress.core.util.attr.VUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * This Manager impl supplies CRUD methods used to manage groups stored within the ldap directory.
+ * LDAP group nodes are used for utility and security functions within various systems and apps.
+ * <p/>
+ * This class is thread safe.
+ * <p/>
+
+ *
+ * @author Shawn McKinney
+ */
+public class GroupMgrImpl extends Manageable implements GroupMgr
+{
+    private static final String CLS_NM = GroupMgrImpl.class.getName();
+    private static final GroupP groupP = new GroupP();
+
+    /**
+     * Create a new group node.  Must have a name and at least one member.
+     *
+     * @param group contains {@link Group}.
+     * @return {@link Group} containing entity just added.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event system error.
+     */
+    @Override
+    public Group add( Group group ) throws org.apache.directory.fortress.core.SecurityException
+    {
+        String methodName = "add";
+        assertContext(CLS_NM, methodName, group, GlobalErrIds.GROUP_NULL);
+        checkAccess(CLS_NM, methodName);
+        if(!group.isMemberDn())
+        {
+            loadUserDns( group );
+        }
+
+        return groupP.add( group );
+    }
+
+    /**
+     * Modify existing group node.  The name is required.  Does not update members or properties.
+     * Use {@link GroupMgr#add( Group group, String key, String value )}, {@link GroupMgr#delete( Group group, String key, String value )},
+     * {@link GroupMgr#assign( Group group, String member) }, or {@link GroupMgr#deassign( Group group, String member) } for multi-occurring attributes.
+     *
+     * @param group contains {@link Group}.
+     * @return {@link Group} containing entity just modified.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event system error.
+     */
+    @Override
+    public Group update( Group group ) throws SecurityException
+    {
+        String methodName = "update";
+        assertContext(CLS_NM, methodName, group, GlobalErrIds.GROUP_NULL);
+        checkAccess(CLS_NM, methodName);
+        return groupP.update( group );
+    }
+
+    /**
+     * Delete existing group node.  The name is required.
+     *
+     * @param group contains {@link Group}.
+     * @return {@link Group} containing entity just removed.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event system error.
+     */
+    @Override
+    public Group delete( Group group ) throws SecurityException
+    {
+        String methodName = "delete";
+        assertContext(CLS_NM, methodName, group, GlobalErrIds.GROUP_NULL);
+        checkAccess(CLS_NM, methodName);
+        return groupP.delete( group );
+    }
+
+    /**
+     * Add a property to an existing group node.  The name is required.
+     *
+     * @param group contains {@link Group}.
+     * @param key contains the property key.
+     * @param value contains contains the property value.
+     * @return {@link Group} containing entity just modified.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event system error.
+     */
+    public Group add( Group group, String key, String value ) throws SecurityException
+    {
+        String methodName = "addProperty";
+        assertContext(CLS_NM, methodName, group, GlobalErrIds.GROUP_NULL);
+        checkAccess(CLS_NM, methodName);
+        return groupP.add( group, key, value );
+    }
+
+    /**
+     * Delete existing group node.  The name is required.
+     *
+     * @param group contains {@link Group}.
+     * @param key contains the property key.
+     * @param value contains contains the property value.
+     * @return {@link Group} containing entity just modified.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event system error.
+     */
+    public Group delete( Group group, String key, String value ) throws SecurityException
+    {
+        String methodName = "deleteProperty";
+        assertContext(CLS_NM, methodName, group, GlobalErrIds.GROUP_NULL);
+        checkAccess(CLS_NM, methodName);
+        return groupP.delete( group, key, value );
+    }
+
+    /**
+     * Read an existing group node.  The name is required.
+     *
+     * @param group contains {@link Group} with name field set with an existing group name.
+     * @return {@link Group} containing entity found.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event system error.
+     */
+    @Override
+    public Group read( Group group ) throws SecurityException
+    {
+        String methodName = "read";
+        assertContext(CLS_NM, methodName, group, GlobalErrIds.GROUP_NULL);
+        checkAccess(CLS_NM, methodName);
+        return groupP.read( group );
+    }
+
+    /**
+     * Search using a full or partial group node.  The name is required.
+     *
+     * @param group contains {@link Group}.
+     * @return List of type {@link Group} containing entities found.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event system error.
+     */
+    @Override
+    public List<Group> find( Group group ) throws SecurityException
+    {
+        String methodName = "find";
+        assertContext(CLS_NM, methodName, group, GlobalErrIds.GROUP_NULL);
+        checkAccess(CLS_NM, methodName);
+        return groupP.search( group );
+    }
+
+    /**
+     * Search for groups by userId.  Member (maps to userId) and is required.
+     *
+     * @param user contains userId that maps to Group member attribute.
+     * @return {@link Group} containing entity just added.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event system error.
+     */
+    public List<Group> find( User user ) throws SecurityException
+    {
+        String methodName = "findWithUsers";
+        assertContext(CLS_NM, methodName, user, GlobalErrIds.USER_NULL);
+        checkAccess(CLS_NM, methodName);
+        loadUserDn( user );
+        return groupP.search( user );
+    }
+
+    /**
+     * Assign a user to an existing group node.  The name is required and userDn are required.
+     *
+     * @param group contains {@link Group}.
+     * @param member is the relative distinguished name (rdn) of an existing user in ldap.
+     * @return {@link Group} containing entity to assign.
+     * @throws org.apache.directory.fortress.core.SecurityException in the event entry already present or other system error.
+     */
+    @Override
+    public Group assign( Group group, String member ) throws SecurityException
+    {
+        String methodName = "assign";
+        assertContext(CLS_NM, methodName, group, GlobalErrIds.GROUP_NULL);
+        checkAccess(CLS_NM, methodName);
+        ReviewMgr reviewMgr = ReviewMgrFactory.createInstance();
+        User user = reviewMgr.readUser( new User( member ) );
+        return groupP.assign( group, user.getDn() );
+    }
+
+    /**
+     * Deassign a user from an existing group node.  The name is required and userDn are required.
+     *
+     * @param group contains {@link Group}.
+     * @param member is the relative distinguished name (rdn) of an existing user in ldap.
+     * @return {@link Group} containing entity to deassign
+     * @throws org.apache.directory.fortress.core.SecurityException in the event entry already present or other system error.
+     */
+    @Override
+    public Group deassign( Group group, String member ) throws SecurityException
+    {
+        String methodName = "deassign";
+        assertContext(CLS_NM, methodName, group, GlobalErrIds.GROUP_NULL);
+        checkAccess(CLS_NM, methodName);
+        ReviewMgr reviewMgr = ReviewMgrFactory.createInstance();
+        User user = reviewMgr.readUser( new User( member ) );
+        return groupP.deassign( group, user.getDn() );
+    }
+
+    private void loadUserDns( Group group ) throws SecurityException
+    {
+        if( VUtil.isNotNullOrEmpty( group.getMembers() ))
+        {
+            ReviewMgr reviewMgr = ReviewMgrFactory.createInstance();
+            List<String> userDns = new ArrayList<>();
+            for( String member : group.getMembers() )
+            {
+                User user = reviewMgr.readUser( new User( member ) );
+                userDns.add( user.getDn() );
+            }
+            group.setMembers( userDns );
+        }
+    }
+
+    private void loadUserDn( User inUser ) throws SecurityException
+    {
+        ReviewMgr reviewMgr = ReviewMgrFactory.createInstance();
+        String userDns;
+        User outUser = reviewMgr.readUser( inUser );
+        inUser.setDn( outUser.getDn() );
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/687ee1ad/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupP.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupP.java b/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupP.java
new file mode 100755
index 0000000..c311443
--- /dev/null
+++ b/src/main/java/org/apache/directory/fortress/core/ldap/group/GroupP.java
@@ -0,0 +1,213 @@
+/*
+ *   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.fortress.core.ldap.group;
+
+
+import org.apache.directory.fortress.core.ValidationException;
+import org.apache.directory.fortress.core.rbac.User;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.directory.fortress.core.GlobalErrIds;
+import org.apache.directory.fortress.core.GlobalIds;
+import org.apache.directory.fortress.core.SecurityException;
+import org.apache.directory.fortress.core.util.attr.VUtil;
+
+import java.util.List;
+
+
+/**
+ * Process module for the group node of Fortress directory structure.
+ * This class is thread safe.
+ *
+ * @author Shawn McKinney
+ */
+final class GroupP
+{
+    private static final String CLS_NM = GroupP.class.getName();
+    private static final Logger LOG = LoggerFactory.getLogger( CLS_NM );
+    private static GroupDAO gDao = new GroupDAO();
+
+    /**
+     * Add a group node to the Directory Information Tree (DIT).
+     *
+     * @param group contains the group entity for target node.
+     * @throws org.apache.directory.fortress.core.SecurityException
+     *          in event of validation or system error.
+     */
+    final Group add( Group group ) throws SecurityException
+    {
+        validate( group );
+        return gDao.create( group );
+    }
+
+    /**
+     * Modify a group node within the Directory Information Tree (DIT).
+     *
+     * @param group contains the group entity for target node.
+     * @throws org.apache.directory.fortress.core.SecurityException
+     *          in event of validation or system error.
+     */
+    final Group update( Group group ) throws SecurityException
+    {
+        validate( group );
+        return gDao.update( group );
+    }
+
+    /**
+     * Remove the group node.
+     *
+     * @param group contains the group entity for target node.
+     * @throws SecurityException in event of validation or system error.
+     */
+    final Group delete( Group group ) throws SecurityException
+    {
+        return gDao.remove( group );
+    }
+
+    /**
+     * Add a new property to an existing Group
+     *
+     * @param group
+     * @param key
+     * @param value
+     * @return
+     * @throws org.apache.directory.fortress.core.SecurityException
+     *
+     */
+    final Group add( Group group, String key, String value ) throws SecurityException
+    {
+        return gDao.add( group, key, value );
+    }
+
+    /**
+     * Remove an existing property value from an existing Group
+     *
+     * @param group
+     * @param key
+     * @param value
+     * @return
+     * @throws org.apache.directory.fortress.core.SecurityException
+     *
+     */
+    final Group delete( Group group, String key, String value ) throws SecurityException
+    {
+        return gDao.delete( group, key, value );
+    }
+
+    /**
+     * Method will add the "member" attribute on LDAP entry which represents a Group assignment.
+     *
+     * @param entity contains the group name targeted.
+     * @param userDn String contains the dn for the user entry that is being assigned the RBAC Role.
+     * @return Group containing copy of input data.
+     * @throws SecurityException in the event of data validation or DAO system error.
+     */
+    final Group assign( Group entity, String userDn ) throws SecurityException
+    {
+        return gDao.assign( entity, userDn );
+    }
+
+    /**
+     * Method will remove the "member" attribute on LDAP entry which represents a Group assignment.
+     *
+     * @param entity contains the role name targeted.
+     * @param userDn String contains the dn for the user entry that is being assigned the RBAC Role.
+     * @return Role containing copy of input data.
+     * @throws SecurityException in the event of data validation or DAO system error.
+     */
+    final Group deassign( Group entity, String userDn ) throws SecurityException
+    {
+        return gDao.deassign( entity, userDn );
+    }
+
+    /**
+     * Return a fully populated Group entity for a given name.  If matching record not found a
+     * SecurityException will be thrown.
+     *
+     * @param group contains full group name for entry in directory.
+     * @return Group entity containing all attributes associated.
+     * @throws SecurityException in the event not found or DAO search error.
+     */
+    final Group read( Group group ) throws SecurityException
+    {
+        return gDao.get( group );
+    }
+
+    /**
+     * Takes a search string that contains full or partial Group name in directory.
+     *
+     * @param group contains full or partial name.
+     * @return List of type Group containing fully populated matching entities.  If no records found this will be empty.
+     * @throws SecurityException in the event of DAO search error.
+     */
+    final List<Group> search( Group group ) throws SecurityException
+    {
+        return gDao.find( group );
+    }
+
+    /**
+     * Takes a search string that contains full or partial Group name in directory.
+     *
+     * @param user contains full dn for existing user.
+     * @return List of type Group containing fully populated matching entities.  If no records found this will be empty.
+     * @throws SecurityException in the event of DAO search error.
+     */
+    final List<Group> search( User user ) throws SecurityException
+    {
+        return gDao.find( user );
+    }
+
+    /**
+     * Method will perform simple validations to ensure the integrity of the {@link Group} entity targeted for insertion
+     * or deletion in directory.
+     *
+     * @param entity contains the enum type to validate
+     * @throws org.apache.directory.fortress.core.SecurityException
+     *          thrown in the event the attribute is null.
+     */
+    private void validate( Group entity ) throws SecurityException
+    {
+        if ( !VUtil.isNotNullOrEmpty( entity.getName() ) )
+        {
+            String error = "validate name validation failed, null or empty value";
+            LOG.warn( error );
+            throw new ValidationException( GlobalErrIds.GROUP_NAME_NULL, error );
+        }
+        if ( entity.getName().length() > GlobalIds.OU_LEN )
+        {
+            String name = entity.getName();
+            String error = "validate name [" + name + "] invalid length [" + entity.getName().length() + "]";
+            LOG.warn( error );
+            throw new ValidationException( GlobalErrIds.GROUP_NAME_INVLD, error );
+        }
+        if ( entity.getProtocol().length() > GlobalIds.OU_LEN )
+        {
+            String error = "validate protocol [" + entity.getProtocol() + "] invalid length [" + entity.getProtocol()
+                .length() + "]";
+            LOG.warn( error );
+            throw new ValidationException( GlobalErrIds.GROUP_PROTOCOL_INVLD, error );
+        }
+        if ( VUtil.isNotNullOrEmpty( entity.getDescription() ) )
+        {
+            VUtil.description( entity.getDescription() );
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-fortress-core/blob/687ee1ad/src/main/java/org/apache/directory/fortress/core/ldap/group/package.html
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/directory/fortress/core/ldap/group/package.html b/src/main/java/org/apache/directory/fortress/core/ldap/group/package.html
new file mode 100755
index 0000000..28db54b
--- /dev/null
+++ b/src/main/java/org/apache/directory/fortress/core/ldap/group/package.html
@@ -0,0 +1,33 @@
+<!--
+ *   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.
+ *
+-->
+<html>
+   <head>
+      <title>Package Documentation for org.apache.directory.fortress.ldap.group</title>
+   </head>
+   <body>
+      <p>
+         This package contains APIs to perform create and teardown the ldap group node.
+      </p>
+      <p>
+          The <b>org.apache.directory.fortress.ldap.group</b> package provides apis to add and remove group node, <b>dcObject</b>.
+          The group node is common throughout ldap operartions and is commonly used to define sets of users or other data types.
+      </p>
+   </body>
+</html>