In my previous article on looping, we looked at looping through a collection in an OGNL expression. In this article, we will take a different approach and learn more about what we can do inside the curly braces { } of an OGNL expression.
In the previous example, we set up a loop counter and used it to extract a particular entry from our collection or array. The curly braces served as the loop control like the for or where clause in Java. Since the curly braces controlled the loop, you could remove the need for the counter during the loop iteration if there were some other way to get the current value of an attribute. And since the attribute we care about is group, we would want to somehow get the value of the current group.
See the complete list of articles in my OGNL series at the end of this post.
So if we have an array object containing all the groups the user is a member of, we would want to iterate through it and get the group value. If the whole group array is [marketing, sales, IT] then in the first iteration, we'd want to get "marketing," in the second, "sales" and the third, "IT."
There is a way to get those group values without having a loop counter. In my second article we talked about how the #this variable allowed us to get information from the current context. You could use it to get the value of an attribute that is available for use from PingFederate. Inside the curly braces, you can also use it to get the current group value that is being processed in the loop. This is called "projection" in OGNL and provides a very powerful tool for working with collections, for more information see the OGNL language guide.
Look at the code below and compare it to the example in my last article. You will notice that the counter i is no longer set or incremented; you don't need it. What has changed is that at the start, we assign a value to #group with #this (line 4).
1. #groupCnOnly = new java.util.ArrayList(),
2. #groups = #this.get("ds.LDAP.memberOf")!=null?#this.get("ds.LDAP.memberOf").getValues():{},
3. #groups.{
4. #group = #this,
5. #group = new javax.naming.ldap.LdapName(#group),
6. #cn = #group.getRdn(#group.size() - 1).getValue().toString(),
7. #groupCnOnly.add(#cn)
8.},
9. #this.get("ds.LDAP.memberOf")!=null? new org.sourceid.saml20.adapter.attribute.AttributeValue(#groupCnOnly):null
Let's review the code line by line (line numbers above should of course be removed when you copy this code into your own PingFederate environment):
- With the org.sourceid.saml20.adapter.attribute.AttributeValue class, we can create an object that takes a java.util.ArrayList as a collection. We want to return the CN for all the groups, so we create an object to hold those CNs.
- We check to make sure that the memberOf attribute retrieved from the LDAP data source actually exists, in other words, does the user belong to at least one group?
- If he does, then we extract this collection (an ArrayList) from the current context.
- If he does not, then we create an empty collection with the {} braces.
- The groups object either contains the collection of groups or an empty collection. The curly braces will provide an iteration through each entry in the collection. This is effectively a for or where loop that will take us through the number entries in the collection. Inside the curly braces you place the code to process each entry in turn.
- We extract the current entry using #this. It has to be first and standalone; thus, we initialize group on its own line.
- We take the value that is a DN and use it to create a javax.naming.ldap.LdapName that will break down the DN into its separate components.
- From the group element, get the last entry (another array you are dealing with here) which is the CN and get just the value (what is after the equals in CN=).
- We add this CN to our just created ArrayList that is going to hold our collection of CNs.
- While we still have values in the collection, we go back to the open { curly brace and continue.
- We verify that the user did belong to at least one group and, if so, we return the new collection of just CNs; if not, we simply set the return value to null
Now the code:
The results of executing the code:
Stay tuned for more about OGNL. In the meantime please leave a comment on this post and let me know what topics you would like to see. Follow me on Twitter: @jdasilvaPI
****************************************
OGNL Blog Series:
- Introduction to OGNL
- A simple OGNL expression
- Declaring variables in OGNL
- Method calls in OGNL
- Arrays in OGNL
- OGNL: What about those curly braces?
- Looping in OGNL
- Looping in OGNL take 2
- So what exactly is #this in OGNL?
- A continuing look at #this variable in OGNL
- Functions in OGNL
- Misc Topics in OGNL
John DaSilva develops training and solutions at Ping Identity.