I am wrapping a crazy busy week. Probably one of my most technically in-depth week in a really long time. So what kept me busy? Deep-diving into OpenAM’s Entitlement’s engine, learning about it’s REST interfaces and how to extend OpenAM to leverage custom service types. I’ll explain later since I know your thinking, “Tumy … dude, what the heck is a service type?”.
Alright, let’s jump into it …
Entitlements are policies or rules that state what you (or any user) can and can’t do. Sounds simple right? In Information Security entitlements usually define what resources a user can access, how they can access it, when they can access it and so on and so on. A resource can be a web url, a banking transaction, a database record, or frankly anything you might want to protect. Typically entitlements are expressed through XACML http://en.wikipedia.org/wiki/XACML. Entitlements are used in access control settings and used to define fine-grained authorization rules. This is starting to become too much of a Entitlements 101 class so let me just jump into the hand’s on stuff.
Ok, Forgerock … in their OpenAM product they have an Entitlements engine which is essentially a Policy Management Point and a Policy Decision Point (Google is your friend if you don’t know what those things are). Out of the box OpenAM supports a few different “service types” which are essentially a set of resources and their associated actions. For example a web url would potentially have the actions of “GET” and “POST”. There are a couple of other service types too (a banking example and a few others). But what happens when our resource is not a web URL and we want to have actions besides “GET” or “POST”. What we if we wanted to have a resources defined as database table names and we wanted to have actions such as “READ”, “UPDATE”, “DELETE”. (Update: Starting in OpenAM Version 11.2 some of these additional actions are available out of the box) We want to be able to create rules that we can either allow a user to read information from a specific table or deny their ability to read from a certain table. Ok, hopefully you get the idea … if you don’t email me and we can talk about it. OpenAM has a great set of command line tools that you can use to interface with the product, these tools have also been “web” enabled on a jsp page which is accessible through the admin console (it’s disabled by default though).
To create this new service type there are a few steps we need to take:
- Create a custom Application Type
- Create a custom Service Type
- Create a custom Application
- Create the policy, using the custom service type
4 easy steps.
The Custom Application Type is a few lines that get imported. Let’s assume that you have enabled the web ssoadmin.jsp and have accessed it here:
https://am.host:port/openam/ssoadm.jsp
You would see a page like this:
Do a quick search for “create-appl-type” and you then click on it.
Fill in the form that is displayed with this information:
Application Type Name: BTPoliyService
actions=READ=true
actions=UPDATE=true
actions=DELETE=true
actions=ADD-ACCESS=true
resourceComparator=com.sun.identity.entitlement.URLResourceName
saveIndexImpl=com.sun.identity.entitlement.util.ResourceNameIndexGenerator
searchIndexImpl=com.sun.identity.entitlement.util.ResourceNameSplitter
This creates the set of actions that will be available for your resources of this type. Save that and then you need to create the Custom Service Type. This is created by modifying an XML file and then importing that file into a form that is similar to the one we just saw.
The service type provides a little more detail on the actions and sets the True/False values that will be displayed in the policy manager.
<?xml version=”1.0″ encoding=”UTF-8″?>DOCTYPE ServicesConfiguration SYSTEM “jar://com/sun/identity/sm/sms.dtd”>
<Schema serviceHierarchy=”/DSAMEConfig/BTPolicyService” i18nFileName=”BTPolicyService” i18nKey=”BTPolicyService”>
<Global>
<AttributeSchema name=”serviceObjectClasses” type=”list” syntax=”string” i18nKey=”BTPolicyService”/>
</Global>
<Policy>
<AttributeSchema i18nKey=”READ” name=”READ” syntax=”boolean” type=”single” uitype=”radio” >
<IsResourceNameAllowed></IsResourceNameAllowed>
<BooleanValues>
<BooleanTrueValue>true</BooleanTrueValue>
<BooleanFalseValue>false</BooleanFalseValue>
</BooleanValues>
</AttributeSchema>
<AttributeSchema i18nKey=”DELETE” name=”DELETE” syntax=”boolean” type=”single” uitype=”radio” >
<IsResourceNameAllowed></IsResourceNameAllowed>
<BooleanValues>
<BooleanTrueValue>true</BooleanTrueValue>
<BooleanFalseValue>false</BooleanFalseValue>
</BooleanValues>
</AttributeSchema>
<AttributeSchema i18nKey=”UPDATE” name=”UPDATE” syntax=”boolean” type=”single” uitype=”radio” >
<IsResourceNameAllowed></IsResourceNameAllowed>
<BooleanValues>
<BooleanTrueValue>true</BooleanTrueValue>
<BooleanFalseValue>false</BooleanFalseValue>
</BooleanValues>
</AttributeSchema>
<AttributeSchema i18nKey=”ADD-ACCESS” name=”ADD-ACCESS” syntax=”boolean” type=”single” uitype=”radio” >
<IsResourceNameAllowed></IsResourceNameAllowed>
<BooleanValues>
<BooleanTrueValue>true</BooleanTrueValue>
<BooleanFalseValue>false</BooleanFalseValue>
</BooleanValues>
</AttributeSchema>
</Policy>
</Schema>
</Service>
</ServicesConfiguration>
In the above XML file, you should notice there are several spots where I have provided the name of the service “DatabaseTablePolicyService” and then the actions and their True/False values. In the ssoadm.jsp search for “create-svc” and then copy and paste this file into that form.
Next step and last step of the “extending” part of the process. So, in the ssoadm.jsp web page, search for “create-appl”. Click on this link and it will open a form very similar to the “create-appl-type” form. Enter the following information:
actions=READ=true
actions=UPDATE=true
actions=DELETE=true
actions=ADD-ACCESS=true
applicationType=BTPolicyService
resources= table://*
entitlementCombiner=com.sun.identity.entitlement.DenyOverride
resourceComparator=com.sun.identity.entitlement.URLResourceName
conditions=com.sun.identity.admin.model.DnsNameViewCondition
subjects=com.sun.identity.admin.model.IdRepoGroupViewSubject
subjects=com.sun.identity.admin.model.IdRepoRoleViewSubject
subjects=com.sun.identity.admin.model.IdRepoUserViewSubject
subjects=com.sun.identity.admin.model.VirtualViewSubject
subjects=com.sun.identity.admin.model.AttributeViewSubject
subjects=com.sun.identity.admin.model.OrViewSubject
subjects=com.sun.identity.admin.model.AndViewSubject
subjects=com.sun.identity.admin.model.NotViewSubject
conditions=dateRange
conditions=daysOfWeek
conditions=dnsName
conditions=ipRange
conditions=timeRange
conditions=timezone
conditions=or
conditions=and
conditions=not
Notice in the above file, that I add the application name and it matches the name we have used in the other configurations. I added the actions again and finally I actually define a resource. I personally like to describe the resource type in a URL style … I can use “table://” as my resource in the policy and that will help remind me later what type of resource that is. You don’t have to prefix your resources in your policy with that … it seems to be optional.
At this point you can jump back over to the OpenAM Admin console and create a policy based on this resource, as you can see in the following screenshot.
So, that’s pretty cool stuff … The entitlements engine is pretty robust, it’s fast and … it has a RESTful interface. I am going to do a deep-dive blog post on the RESTful services at some point but for now let’s just take a look at how you can evaluate an entitlement.
Evaluating a Privilege:
* ssoToken = Authenticated User’s Token
* iPlanetDirectoryPro = session cookie … admin users session token
* action = action user is attempting (GET, POST, READ, DELETE, etc)
* application = application type of policy (defaults to iPlanetAMWebAgentService)
* Subject (user attempting action … encoded session token)
curl -v -H “X-Query-Parameters: ssotoken:AQIC5wM2LY4SfczpL5a3M02ju3uyOd6iMj4zZvPZXB3BNQ4.*AAJTSQACMDE.*” -b “iPlanetDirectoryPro=”AQIC5wM2LY4SfcxcPg_yUwYu-iQPHH663tv9AnoEEr6j_2k.*AAJTSQACMDE.*”” “http://am.host:port/openam/ws/1/entitlement/entitlement?action=READ&resource=table://my_table_name&application=BTPolicyService&subject=4l18suAL/hXNCfzykwIlbV0WbtM%3D”
This will return a JSON formatted object:
{
“statusCode”:200,
“body”:{
“actionsValues”:{READ:”true”, UPDATE:”false”, DELETE:”true”, ADD-ACCESS:”false”},
“resourceName”:”table://my_table_name”},
“statusMessage”:”OK”
}
You can create a policy that would return attributes, from the user’s identity record, along with this JSON object. There are also RESTful services that will just return an allow or deny, which is great if you don’t need as much information back.
So, that was real high level and really basic but I hope that I gave you some ideas for the potential of this engine. Let me know if you have any questions or want to chat about. Also, I am available on a consulting basis to help design or implement this in your environment.
Acknowledgements:
- There were a bunch of people at ForgeRock that help me out at various points through this. You guys know who you are … I’ll leave your names out so that you don’t get bombarded with requests.
- Also, there were a few non-ForgeRock guys that went through this last year and gave me some pointers along the way. Thanks!
- And finally … to the guys that did this first at Sun. Thanks for building this stuff and documenting it. I am thankful that those web pages that you created haven’t vanished yet.
Hello Brad!
Thank you for excellent tutorial, it helped me much! However currently I am facing one problem that I cannot overcome. I need to create a rule, which will allow to specify a different action value than just “true” or “false”. I need an action value like “redirect” in order to turn the accessing user to another resource in certain conditions…
A use-case for this is the following:
A user during self-registration process (using Membership authentication
module) has given all required personal details, but one field (for
example credit card number) was optional, so he left it blank. He can
access resource A and B without problems. But there exists another
resource C, which requires, that credit card number is present in the
user’s profile in order for him to have access to it.
My approach to this is the following:
When the user wants to access resource C, he has to authenticate himself with an authentication module on a certain level above a threshold (can be done with a policy condition). This authentication module checks if the credit card data is present in his profile. If he has authenticated with a module on a lower level, he should be redirected to fill in missing data in his profile.
Do you think it is the right approach? How could I implement the “redirect” action in this situation? Or maybe there is another, more clever solution for such a flow?
I will be grateful for any suggestions!
Cheers,
Wlodzimierz
Wlodzimierz,
Thank you for the positive feedback. I am glad that you found this post useful. If you are looking to add a new action type (“Redirect”) you can easily do that but keep in mind the action type of boolean means that this attribute will either be enabled or disabled for this user but there isn’t a hook to perform an action from that value.
What you are describing sounds a lot like adaptive authentication (Risk Based Authentication). http://docs.forgerock.org/en/openam/10.1.0/admin-guide/index.html#adaptive-auth-module-conf-hints adaptive authentication allows you check certain values (attributes, location, etc) to determine if the user meets the minimum requirements to access the resource. I could see in your use case where you could check to see if credit card number is blank. If credit card number is blank it increases the risk score and then you could create an authentication module to perform some action (like asking for a credit card number). Like most things there are probably a couple of ways to implement.
Take a look at the adaptive authentication module and let me know if you think that will work for you.
I am also available for consulting work should you desire additional support with this.
Thanks,
Brad
Hi Brad,
Many thanks for your interest in this matter. Actually, the RiskBased authentication looks interesting, but it still does not solve this issue.
I do not mean to add a new action type (like GET or POST), but an Action Value. For instance an example user is already authenticated, and can access some resources, but when he accesses a certain web resource (e.g. http://example.com/resourceWithCreditCardNeeded.html) with GET request, in the policy it should be available to decide not only to “allow” or “deny”, but also to “redirect” him to his profile in order to add missing data to his profile. Since in the Service XML there is BooleanValues element, it allows only boolean action values (true or false, allow or deny). I wonder if it is possible to use e.g. ChoiceValues element and determine other action values, like for instance “redirect”? But then this decision would need to be understandable by the policy agent in the web server, am I right? Is this the right course of thinking?
Another option that comes to my mind is to implement this on the web server side, as a reply to the user on the “deny” decision from the policy agent, when the user accesses resources with greater authentication needs… but this approach does not convince me since we would like to put the whole weight of authentication&authorization responsibility on OpenAM and not to decouple it on the web server or other parties…
I hope this will be beneficial for others struggling with similar challanges. In case this topic is advanced enough to employ you as a consultant – let me know.
Cheers,
Wlodzimierz
Wlodzimierz,
So, you would like for OpenAM to check to see if the user is authorized, based on whether or not they have a value in the CreditCardNumber attribute. If they are not authorized then you would like for them to be redirected to a form that prompts them to provide a credit card number.
The easiest way may be for you to implement that logic into your application. You can leverage the entitlement’s engine by creating a policy rule that checks the value of the credit card number but you would need to implement the query via your application. So, rather than using the Policy Agent as your Policy Enforcement Point (PEP) your application would take on that role. You can still leverage the Policy Agent for Authentication and then on successful authentication your application would make authorization checks to the entitlement engine.
XACML has the concept of obligations … OpenAM’s UI doesn’t have a mechanism to create obligations but I believe if you create your XACML policy and then import (using the command line admin tool) then you can import obligations in your policy. You may be able to leverage the obligations to hold the URL that you want to redirect users to. So, when you perform your query you may get a “failed” or “deny” but the URL would be provided in the obligation and your application could redirect the user to that URL. That is just a thought off the top of my head.
Brad
Hey Brad,
Thanks for this information this helped me while I was using openam 11.0.1 as of now I’m planning to upgrade to openam 13.5. I have few questions can you please share some knowledge on that.
1. Do I need to seperately configure any of these actions with openam 13.5 or all these are supported.
2. while I was trying to run these ssoadm commands with 13.5 instance I’m seeing these errors.
ssoadm set-sub-cfg –servicename sunEntitlementService –subconfigname applicationTypes/iPlanetAMWebAgentService –realm / –operation set –datafile /opt/openam/ssoconfig/datafile -u amadmin -f /.password
ssoadm set-sub-cfg –servicename sunEntitlementService –subconfigname registeredApplications/iPlanetAMWebAgentService –realm / –operation set –datafile /opt/openam/ssoconfig/DATAFILE6 -u amadmin -f /.password
Any help is appreciated.
Thanks,
Richy
Hey Richy,
Thanks for checking out the blog, glad it was able to help you out some. I haven’t tried this out with 13.5 so I am not sure off the top of my head. I could try and take a look at this when I find some time in the next few days. You mentioned that you were getting some errors … but I don’t see that you included what those errors are. Can you send me the errors that you are getting when you run the ssoadm commands?
Thanks,
Brad
Hi Brad,
Thanks for quick reply and sorry that I didn’t mentioned the errors here.
The attribute name actinos does not match the service schema
I Initially thought this is because of order mismatch between entitlements.xml and amWebagent.xml.
even after correcting those it still throwing the same error.
Thanks,
Richy
Richy,
I would suspect something being off in your service description but hard to say without looking at it. You said this was working fine in previous versions of OpenAM?
Brad