Hooks Example - Assign a UNIX ID to Each New Group
Hooks Introduction
Getting started with hooks
Proof of concept (A veto hook)
- Assign a Unix id to each new group
Here is another hooks example. This will assign a Unix id to each new group, by a database auto-increment. Also, the attribute is not editable (by non wheel / root)
- Download and unzip Grouper binary api 1.5 (should work in later version)
- This example is for mysql, make a schema
CREATE DATABASE grouper_v1_5; CREATE USER 'grouper_v1_5'@'localhost' IDENTIFIED BY '*********'; grant all on grouper_v1_5.* to 'grouper_v1_5'@'localhost';
- Configure the grouper.hibernate.properties
hibernate.dialect = org.hibernate.dialect.MySQL5Dialect hibernate.cache.use_query_cache = true hibernate.connection.driver_class = com.mysql.jdbc.Driver hibernate.connection.url = jdbc:mysql://localhost:3306/grouper_v1_5 hibernate.connection.username = grouper_v1_5 hibernate.connection.password = **********
- Initialize the database
C:\temp\grouper.apiBinary-1.5.3\bin> gsh -registry -runscript
- Add a type and an attribute and stem
C:\temp\grouper.apiBinary-1.5.3\bin> gsh gsh 0% grouperSession = GrouperSession.startRootSession(); gsh 1% addRootStem("aStem", "aStem"); gsh 2% typeAdd("posixGroup"); gsh 3% typeAddAttr("posixGroup", "gidNumber", AccessPrivilege.READ, AccessPrivilege.ADMIN, false);
- Create a table to auto-increment an id (note, this is easier with postgres or oracle with sequences)
create table `grouper_v1_5`.`posix_groupids`( `gid` bigint NOT NULL AUTO_INCREMENT, `groupid` varchar(50) NOT NULL, PRIMARY KEY (`gid`) );
- Secure the type/attribute in grouper.properties:
#before Grouper 1.6, you need to set this to true due to jira GRP-451 grouperIncludeExclude.requireGroups.use = true #secure this type/attribute so that non admins cannot edit it once in place security.types.posixGroup.wheelOnly = true
- Write the hook source, and put it in source/test/GroupAddUosHook.java
package test; import java.util.List; import org.apache.commons.lang.StringUtils; import edu.internet2.middleware.grouper.Group; import edu.internet2.middleware.grouper.GroupType; import edu.internet2.middleware.grouper.GroupTypeFinder; import edu.internet2.middleware.grouper.GrouperSession; import edu.internet2.middleware.grouper.exception.GrouperSessionException; import edu.internet2.middleware.grouper.hibernate.HibUtils; import edu.internet2.middleware.grouper.hibernate.HibernateSession; import edu.internet2.middleware.grouper.hooks.beans.HooksContext; import edu.internet2.middleware.grouper.hooks.beans.HooksGroupBean; import edu.internet2.middleware.grouper.misc.GrouperSessionHandler; import edu.internet2.middleware.grouper.util.GrouperUtil; /** * add a type after a group insert */ public class GroupAddUosHook extends edu.internet2.middleware.grouper.hooks.GroupHooks { /** * * @see edu.internet2.middleware.grouper.hooks.GroupHooks#groupPostInsert(edu.internet2.middleware.grouper.hooks.beans.HooksContext, edu.internet2.middleware.grouper.hooks.beans.HooksGroupBean) */ @SuppressWarnings("unchecked") @Override public void groupPostInsert(HooksContext hooksContext, final HooksGroupBean postInsertBean) { super.groupPostInsert(hooksContext, postInsertBean); try { //since we have security on the type/attribute, we need to do this as root GrouperSession.callbackGrouperSession( GrouperSession.staticGrouperSession().internal_getRootSession(), new GrouperSessionHandler() { @Override public Object callback(GrouperSession grouperSession) throws GrouperSessionException { Group group = postInsertBean.getGroup(); GroupType posixGroup = GroupTypeFinder.find("posixGroup", true); group.addType(posixGroup); //its possible this is already there (e.g. from import or something) //select by list since if not by list it must be there List<String> gidList = HibernateSession.bySqlStatic().listSelect(String.class, "select gid from posix_groupids where groupid = ?", HibUtils.listObject(group.getId())); if (GrouperUtil.length(gidList) == 0) { HibernateSession.bySqlStatic().executeSql("insert into posix_groupids (groupid) values (?)", HibUtils.listObject(group.getId())); gidList = HibernateSession.bySqlStatic().listSelect(String.class, "select gid from posix_groupids where groupid = ?", HibUtils.listObject(group.getId())); } String gid = gidList.get(0); if (StringUtils.isBlank(gid)) { throw new RuntimeException("Why is gid blank??? " + group); } group.setAttribute("gidNumber", gid); return null; } }); } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } } }
- Put this build.xml in the base dir:
<project name="grouperHooks" default="build" basedir="."> <path id="theClasspath"> <fileset dir="lib"> <include name="**/*.jar"/> </fileset> <fileset dir="dist"> <include name="**/*.jar"/> </fileset> <pathelement location="classes"/> </path> <target name="build"> <mkdir dir="classes"/> <delete dir="classes"/> <mkdir dir="classes"/> <mkdir dir="distHooks"/> <delete dir="distHooks"/> <mkdir dir="distHooks"/> <javac srcdir="source" destdir="classes" debug="true" source="1.5" target="1.5"> <classpath refid="theClasspath"/> <include name="**/*.java" /> </javac> <jar destfile="distHooks/hooksForGrouper.jar"> <manifest> <attribute name="Built-By" value="${user.name}"/> </manifest> <fileset dir="classes"> <include name="**/*.class"/> </fileset> <fileset dir="source"> <include name="**/*"/> </fileset> </jar> <copy todir="lib/custom" file="distHooks/hooksforGrouper.jar" /> </target> </project>
- Run ant
C:\temp\grouper.apiBinary-1.5.3>ant Buildfile: build.xml build: [delete] Deleting directory C:\temp\grouper.apiBinary-1.5.3\classes [mkdir] Created dir: C:\temp\grouper.apiBinary-1.5.3\classes [delete] Deleting directory C:\temp\grouper.apiBinary-1.5.3\distHooks [mkdir] Created dir: C:\temp\grouper.apiBinary-1.5.3\distHooks [javac] Compiling 1 source file to C:\temp\grouper.apiBinary-1.5.3\classes [jar] Building jar: C:\temp\grouper.apiBinary-1.5.3\distHooks\hooksForGrouper.jar [copy] Copying 1 file to C:\temp\grouper.apiBinary-1.5.3\lib\custom BUILD SUCCESSFUL Total time: 1 second C:\temp\grouper.apiBinary-1.5.3>
- Register the hook in the grouper.properties
hooks.group.class=test.GroupAddUosHook
- Try it out in gsh (restart gsh)
gsh 0% grouperSession = GrouperSession.startRootSession(); edu.internet2.middleware.grouper.GrouperSession: c54ae34f1fed4e908cf2731691857745,'GrouperSystem','application' gsh 1% stem = new edu.internet2.middleware.grouper.StemSave(grouperSession).assignStemNameToEdit("aStem").assignName("aStem").assignCreateParentStemsIfNotExist(true).save(); stem: name='aStem' displayName='aStem' uuid='576e26d770584119a1903d7095fab9f2' gsh 2% subject = SubjectFinder.findById("test.subject.0", true); subject: id='test.subject.0' type='person' source='jdbc' name='my name is test.subject.0' gsh 3% stem.grantPriv(subject, NamingPrivilege.CREATE, false); true gsh 4% GrouperSession.stopQuietly(grouperSession); gsh 5% exit Start again to get new grouper session (necessary pre Grouper 1.6) gsh 0% subject = SubjectFinder.findById("test.subject.0", true); subject: id='test.subject.0' type='person' source='jdbc' name='my name is test.subject.0' gsh 1% grouperSession = GrouperSession.start(subject); edu.internet2.middleware.grouper.GrouperSession: f81e665ebe6c41818d5d98120fb940a0,'test.subject.0','person' gsh 2% addGroup("aStem", "aGroup9", "aGroup9"); group: name='aStem:aGroup9' displayName='aStem:aGroup9' uuid='bfac07adf0964722a3226355af09c927' gsh 3% groupGetTypes("aStem:aGroup9"); type: 'base' type: 'posixGroup' gsh 4% getGroupAttr("aStem:aGroup9", "gidNumber"); 8 gsh 5% setGroupAttr("aStem:aGroup9", "gidNumber", "7"); gsh 6% // Error: unable to evaluate command: Sourced file: inline evaluation of: ``setGroupAttr("aStem:aGroup9", "gidNumber", "7"); ;'' : Error invoking compiled command: : Error in compiled command: edu.internet2.middleware.grouper.hooks.logic.HookVeto: cantEditTypeNotInGroup: Not allowed to edit type: posixGroup, changing attribute gidNumber since the user Subject id: test.subject.0, sourceId: jdbc is not in group: null