midPoint is an IAM solution from Evolveum, and Grouper is a IAM solution from Internet2 that can do wonderful things together. There is a great midPoint/Grouper demo available, with a set of instructions. However, there isn’t a lot of documentation on how to implement what is done in the demo for your own production instance. This post is what I did to make it initially work for NDSU. I still have work to do to take it to production.
Listed files can be found in the repo at either midPoint_container/demo/grouper/midpoint_server/container_files/mp-home/post-initial-objects or midPoint_container/demo/grouper/midpoint-objects-manual/tasks/ for the tasks.
First, you need to get the connector from the repo at midPoint_container/demo/grouper/midpoint_server/container_files/mp-home/icf-connectors/ and put that in the icf-connectors dir for your midPoint. You also need to update your schema to include:
<xsd:complexType name="OrgExtensionType"> <xsd:annotation> <xsd:appinfo> <a:extension ref="c:OrgType"/> </xsd:appinfo> </xsd:annotation> <xsd:sequence> <xsd:element name="grouperName" type="xsd:string" minOccurs="0"/> <xsd:element name="ldapDn" type="xsd:string" minOccurs="0"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="ArchetypeExtensionType"> <xsd:annotation> <xsd:appinfo> <a:extension ref="c:ArchetypeType"/> </xsd:appinfo> </xsd:annotation> <xsd:sequence> <xsd:element name="grouperNamePrefix" type="xsd:string" minOccurs="0"/> <!-- e.g. ref:affiliation: --> <xsd:element name="ldapRootDn" type="xsd:string" minOccurs="0"/> <!-- e.g. ou=Affiliations,ou=Groups,dc=internet2,dc=edu --> <xsd:element name="midPointNamePrefix" type="xsd:string" minOccurs="0"/> <!-- e.g. affiliation_ --> <xsd:element name="midPointDisplayNamePrefix" type="xsd:string" minOccurs="0"/> <!-- e.g. Affiliation: --> </xsd:sequence> </xsd:complexType>
And don’t forget to restart midPoint after these changes.
In my particular setup, I don’t have LDAP or a similar concept. So I’m removing some of those bits from the existing setup from demo-grouper. I also am not bringing in extra affiliations and roles, although that is certainly something you could do. It might even make some sense to better configure resources. However, you still need the following in their entirety: functionLibraries/100-function-library-grouper.xml, objectTemplates/100-grouper-template-user.xml, org/100-org-generic-groups.xml, roles/200-metarole-grouper-provided-group.xml.
You will also need archetypes/300-archetype-generic-grouper-group.xml. In my particular case I removed the metarole-ldap-group assignment. Don’t forget to change the xmlns:ext namespace in this file to match your schema extension if you rolled it into your own. In my case, I also remove the ext:ldapRootDn entry as I don’t have LDAP in play from midPoint (that is handled by Grouper).
You also likely need to bring in the objectTemplates/100-grouper-template-user.xml and then make that your default user template.
After that, you’re now ready to bring in the resource from resources/100-grouper.xml. There are several values that you need to configure. You can find instructions on the Internet2 page for the connector. You will likely need to add a virtualHost configuration entry to get it to connect to something other than the default vhost. The main part of the connector uses Grouper’s REST API, and it supports using midPoint constants to store username and password so that you don’t have to hard code that into a file that you want to include in your repo. Unfortunately, I haven’t found a way to get that to work with the AMQP connector configuration. Update the matching and exclusion patterns as you see fit. There is a chunk of code that covers inbound mapping, and it contains a switch to go between different archetypes depending on various matches. For this beginning work, I just deleted the switch statement and left the default archetypeOid alone as that matches the imported archetype. In the future we will likely want to do something more complex.
You can now import 100-grouper.xml and make sure that it checks out when testing the connection. Importing tasks/task-reconciliation-grouper-groups.xml gives you the reconciliation task to run against Grouper REST services. This should work and import your groups that match what you have specified. It should also import users, but it requires a recomputation of users if you do it this way. It appears that this task throws an error if you delete a group that has been imported.
Brining in tasks/task-async-update-grouper.xml gives you the ability to use the async part of the connector. This is reading change messages out of RabbitMQ that Grouper has sent. This will handle group additions that match the pattern, along with deleting groups. It will also handle member adds and removes. For it to show up on the group, the trigger scanner needs to run like with other resources.
Now you can go about figuring out how to get it to do useful work. Our plan is to have midPoint drive the subject DB for Grouper. Grouper will then drive membership into, among other things, services that care about user attributes, like Google Analytics or Qualtrics. That will come into one of these midPoint Orgs, which will then provision out via different connector. That connector will need to take advantage of disable instead of delete with delayed delete, which is the next task to figure out.