This is part of a series of posts about OpenIAM. OpenIAM is an Identity Management platform that helps organisations manage the digital identities of its workforce and customers.
Check out the OpenIAM category for other posts.
In this post, I'm going to show you how to make use of a lesser known feature of OpenIAM called the PropertyValueCache
. The PropertyValueCache
can be used to implement some best practices by avoiding hardcoding values that you need to reuse throughout your groovy scripts.
OpenIAM offers a lot of flexibility when it comes to implementing logic or new functionality. Since 4.2.1.0 it's included a Business Rules engine which offers a UI driven low/no-code way to perform basic tasks. If you need something more complex you'll need to write a groovy script. Groovy scripts allow you to extend OpenIAM's functionality and express complex logic in a Java like language. OpenIAM ships with an extensive number of Groovy scripts, however, these scripts should only be considered basic examples.
While working on my implementation of OpenIAM, I found myself hard coding the same values over and over across lots of groovy scripts. An example, we have different types of users, Staff
, Students
and External
. If we decide that the word External
doesn't accurately describe that type of user and we want to rename it, I would need to go through all of our groovy scripts and find where I've hard coded this value and replace it. That is far from ideal and not very smart. I spent some time trying to come up with a better solution than hard coding what are effectively configuration settings.
The first option would be to store the value as a variable, allowing you to store the value once and reuse it. However, with this approach you cannot access this value from other scripts and would still need to go through all your scripts replacing that value if you need to change it.
Next you could store your shared variables within a single file and import or include it in your scripts. Unfortunately, this doesn't really work in groovy, especially if your scripts are across different directories.
After exploring the code base and database I came up with a good solution to this, the PropertyValueCache
.
The PropertyValueCache
or property_file_values
table in the database drives the System Configuration of OpenIAM. Adding new entries here make the value available to all of your groovy scripts. Even better, after adding some custom language definitions, these are editable fields within the System Configuration UI. This mechanism can be used as a single source of truth, making values you need to reuse available everywhere.
Before we begin, you will need admin access to an OpenIAM instance, as well as the database.
Let's try it out, we are going to create an entry within the property_file_values
table, then we will create a groovy script and attach it to a batch task that outputs the database entry to the logs using the PropertyValueCache
. Though this isn't exactly a real world example, it should give you enough to make use of this in your own scripts.
Let's create the shared value that we want to retrieve from the database. OpenIAM supports a number of different databases. Connect to your database using your preferred tool. My instances uses PostgreSQL and PGAdmin4.
The property_file_values
table is made up of the following columns:
Name | Type | Description |
---|---|---|
property_id | varchar(200) | The property name or location used to retreive the value. This is set using Reverse Domain Name Notation |
property_value | varchar(400) | The value that will be returned |
property_type | varchar(30) | The type of value that is being stored. This is used by the frontend to know what type of input box to display. Just some of the types this can be: Role , Resource , Group , Integer , OrderableValue , ChallengeResponseGroup , OrganizationType , User , OrganizationTypeHierarchy , Widget , String , Secret , ManagedSystem , RegularExpression , Boolean , Select , Organization and MultiSelect |
is_read_only | char(1) | Y \ N - Whether the field should be editable within the UI |
is_multilangual | char(1) | Y \ N - I've not used this but I guess it allows you to specify whether a different value should be available for different languages |
is_empty_value_allowed | char(1) | Y \ N - Whether the entry is required or not. |
category | varchar(100) | The name of the category to display the field under within the UI |
As you can see, there are a number of options associated with each entry in the property_file_values
table. The more interesting field is the property_type
, which can make it really easy to integrate your value into the System Settings section of the webconsole. For example, if you need to provide one of your scripts the ID of a group, you can set the type to Group
and the UI will provide you with a typeahead box that will allow you to pick a group. Once saved the id from the group will be stored as the value.
For the sake of this demo, we will just be using a string. Let's create a new entry in this table and name it using Reverse Domain Name Notation.
insert into property_file_values
("property_id", "property_value", "property_type", "is_read_only", "is_multilangual", "is_empty_value_allowed", "category")
values ('uk.neilherbert.openiam.name', 'Neil Herbert', 'String', 'N', 'N', 'N', 'System');
Running this query will insert a new record with the id uk.neilherbert.openiam.name
and the value Neil Herbert
. You should be able to see this new value within the System
tab under System Configuration. You'll notice that it does not have a label.
Labels are not driven by the database but the language files. To create a label for this, you will need to update your language files such as the messages_en.properties
file:
uk.neilherbert.openiam.name.name=Label Here
uk.neilherbert.openiam.name.title=Label Here
For each property you add to the PropertyValueCache, you need to add both a .name
and .title
entry within your language files.
Now we have a custom entry in the PropertyValueCache
, let me show you how to retrieve it.
Log into the WebConsole and go to the Administration menu → Groovy Manager
Save the following code as a new script at /batch/propertValueCacheExample.groovy
import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory
import org.openiam.idm.srvc.property.service.PropertyValueCache
import org.springframework.context.ApplicationContext
// Dependencies
Log log = LogFactory.getLog("propertValueExample") // Logging
ApplicationContext appContext = (ApplicationContext) context // IoC Container
PropertyValueCache propertyValueCache = appContext.getBean(PropertyValueCache.class) // Global Settings
log.info("Getting Value from PropertyValueCache")
String value = propertyValueCache.getString("uk.neilherbert.openiam.name") ?: "Not Found"
log.info("${value}")
Before diving into this code, we will be using logging to output the value of the PropertyValueCache
. Checkout my post Adding Logging to OpenIAM Groovy Scripts to learn about logging within OpenIAM groovy scripts.
Though the script I've shared is really short, it shows you how easy it is to use the PropertyValueCache
.
At the top of the script we import all the classes we need to use to make this script work. At a minimum you need to include the Spring Framework ApplicationContext class and the PropertyValueCache
itself. The other imports I've included are related to logging.
import org.openiam.idm.srvc.property.service.PropertyValueCache
import org.springframework.context.ApplicationContext
After the imports we need to get an instance of the PropertyValueCache
from the spring framework IOC or Application Context. OpenIAM is written using the Spring Framework so extends much of the frameworks functionality. The Application Context container is an Inversion of Control (IOC) container. It handles dependency injection. It allows dependencies to be instantiated once and it's state shared across the application. This means you no longer have to create new instances of shared classes and provide them with configuration. Imagine having to create a new database class and configure it's connection each time you needed to make a query. IOC allows it to be created in one part of your application, usually some form of startup or boot method, and make that instance of it available everywhere else. A lot of the OIAM functionality is setup using IOC such as the PropertyValueCache
. To use it, we simply ask the Application Context to get it for us.
ApplicationContext appContext = (ApplicationContext) context // IoC Container
PropertyValueCache propertyValueCache = appContext.getBean(PropertyValueCache.class) // Global Settings
Once we have an instance of the PropertyValueCache
, we can simply ask it to get us the value from a property_id.
String value = propertyValueCache.getString("uk.neilherbert.openiam.name") ?: "Not Found"
The PropertyValueCache
class has a number of methods that can be called including getBoolean(string)
, getInt(string)
and getString(string)
which will return the value as the appropriate type.
Now that we have both the database entry and groovy script inplace, lets see the PropertyValueCache
in action by running our groovy script as a batch task.
Go to the Administration Menu → Batch Task
On the left-hand side click on New Batch Task
Create a new batch task with the following settings
Field | Value |
---|---|
Task Name | Property Value Cache Example |
Execution Time | Cron Job |
Cron Expression | 0 * * * * * |
Execution Script | Groovy Script |
Groovy Script URL | /batch/propertValueCacheExample.groovy |
Click Save
. OpenIAM will create the Batch Task and redirect you to the Edit Task page.
Underneath the Batch Task fields you will find some buttons including Execute
, you can click on this to run the script. Before clicking Execute, we need to make sure we are looking at the logs.
Depending on how you've deployed OpenIAM will depend on where you will find your logs. It's probably worth pointing out that these logs are different to what you'll find in the Log Viewer within the WebConsole UI. The logs that we are going to generate go into the operating systems logs.
For Kubernetes you will need to run the following kubectl logs
command:
kubectl logs -l release=test --all-containers --max-log-requests 34 -f
Replace test
with the same value set as APP_NAME
within your env.sh
file. If you are running lots of replicas, you might need to increase the --max-log-requests
if you get an error.
For Docker you can run the following command:
docker logs --tail=0 --follow
For RPM installs, you'll find your logs in the /usr/local/openiam/logs/
folder and can tail them with:
tail -f /usr/local/openiam/logs/*
Click the Execute
button.
Click Yes
to execute the batch task.
After a few seconds you should see the following in your logs (I've stripped the timestamp and a few bits from the output to make it easier to read).
Getting Value from PropertyValueCache
Neil Herbert
Though I'm pretty sure the PropertyValueCache
wasn't intended for this use or at least by end-users, however, it makes it extremely easy to store values that would need to be hardcoded across lots of files within a centralised location. Even better, these values become configuration items and are editable by your sysadmin from the UI. Simply put a new row into the property_file_values
table and use the property_id
to retrieve it from any groovy script!
Need help with OpenIAM? Make sure you join the official OpenIAM Community where you can ask for help from other community members.