OpenAM as an identity provider for Office 365 (WSFed)

This post will run through the step necessary to configure OpenAM 13.5 to be an identity provider for Office 365 and Azure using WS-Federation.

One of the new features in OpenAM 13.5 is support for WS-Federation Active Requestor Profile.  This will enable OpenAM to support a greater range of Office 365 rich clients and Azure authentication scenarios when acting as an IDP.

Why WS-Federation?

 Office 365 and Azure support WS-Federation, SAML2 and in some cases OpenID Connect for integration with third party identity providers. While SAML2 (specifically SAML2 ECP) can be used for federation, it is only supported in newer Microsoft rich clients. WS-Federation must be used to support slightly older products such as Lync, Outlook 2011 (Mac) and Office 2010 (Windows). In particular, to support Lync and support adding an email account in Outlook 2010/2011, WS-Federation active requestor profile must be enabled.

What Works

 Using my completely informal testing procedure on my two laptops, an iPad and a Nexus tablet – I’ve managed to get the following results with the configuration below.

platform test result
MacOS 10.11.5 Office 2011 Office setup from Word ok
Lync for Mac 2011 SignIn ok
Outlook 2011 E-Mail account setup & signin ok
Office 2011 Document Connection ok
Office 2016 SignIn ok
Chrome web Sign In ok
Safari Web Sign In ok
Windows 8.1 Office 2013 CTR Setup ok
Skype For Business Sign In ok
Outlook 2013 E-Mail account setup ok
OneDrive SignIn ok
IE web Sign In ok
FireFox web SIgn In ok
Chrome web Sign In ok
Apple iPad IOS 9.3.5 Microsoft Word SignIn ok
Skype For Business Sign In ok
Outlook E-Mail account setup ok
OneDrive for business Sign In ok
Safari Web Sign In ok
Apple Mail, contacts, calendar Account setup & signin ok
Nexus Tablet Android 5.3 Microsoft Word SignIn ok
Outlook E-Mail account setup ok
OneDrive for business Sign In ok
Chrome web Sign In ok
Gmail, calendar, contacts, device management ok
Skype For Business Sign In ok

Overview of the steps

I’ll go through everything that is needed to configure OpenAM 13.5 to work with Office 365.
  1. Configuring a DNS zone for Office 365.
  2. Setting up the required DNS records for that zone.
  3. Making sure that the active directory domain is properly configured with the right UPN suffixes for the user accounts.
  4. Setting up Windows Desktop SSO (Integrated Windows Authentication) to work with OpenAM.
  5. Using PowerShell to configure Office365 to use an external identity provider.
  6. Setting up OpenAM with the WS-Federation entities for Office 365.
  7. Setting up an account in Office365 and setting it to “federated” mode.

Configuration Overview

In this configuration, our public DNS zone is test365.forgepoc.com and we’ll have users with the email address something@test365.forgepoc.com. They’ll have accounts in an internal Active Directory domain. In common with best practice for Active Directory, the DNS zone of the AD domain in this exercise uses a subdomain of the public DNS zone, test365corp.test365.forgepoc.com.

You don’t need Active Directory to make this work, you could use any database such as OpenDJ. But as Office 365 is typically used on Windows desktops in an Active Directory domain, I’m using it here.

The reverse proxy will be configured with a public trusted SSL certificate (required for WS-Federation active requestor profile to work with Office 365) and act as an SSL termination point for OpenAM. The host will be called login.test365.forgepoc.com.

You don’t need a proxy in order to use OpenAM as an IDP for Office 365, but it is highly recommended.

Requirements

  1. A Windows Active Directory domain (see my blog post on setting up one of these).
  2. An OpenAM instance on any supported operating system, configured to use Active Directory for authentication and profile attributes (see my blog post here on setting up and active directory dataStore). OpenAM should be setup with SSL internally.
  3. A reverse proxy in between OpenAM and the internet, capable of supporting SSL termination (I’m using NginX).
  4. A Windows Active Directory domain configured with network connectivity to the OpenAM instance.
  5. A business Office 365 subscription capable of federating with third party identity providers. in this example, I used a business premium subscription.
  6. An SSL certificate issued from a public trusted certificate authority such as goddaddy.
  7. A public DNS zone which you can configure with the DNS records required for use with Office 365.
  8. Windows machines and devices for testing.
Note: Currently WSFed Active Requestor profile is only supported in the top level realm in OpenAM. There is an open issue for this here. Alternatively you can set up OpenAM to federate with office 365 using SAML2 ECP, but this only works with newer MS rich clients.

Configuring a DNS zone for Office 365

Microsoft make this extremely easy using the admin section of the Office 365 dashboard. Here I’m choosing to set this up myself because I already own the domain forgepoc.com and I have other stuff on it. However, it is much easier to allow Office 365 to act as your DNS service. Doing so automatically configures the required DNS records.To do it the manual way, log in to your Office 365 subscription and select the admin center:

From the left hand menu select settings > Domains.
Click “add a domain” and enter your domain name.

In common with obtaining SSL certificates, you have to verify ownership of your DNS domain by adding a specific TXT record to it.

Now add the required DNS records. It’s important that these are accurate, but luckily Microsoft provide a test tool to verify they are set correctly. Here is a screenshot of the records for my DNS Zone test365.forgepoc.com from my DNS provider:

CNAME Records
Host Name               Points To    
lyncdiscover            webdir.online.lync.com    
msoid                   clientconfig.microsoftonline-p.net    
sip                     sipdir.online.lync.com    
enterpriseregistration  enterpriseregistration.windows.net    
enterpriseenrollment    enterpriseenrollment.manage.microsoft.com    
autodiscover            autodiscover.outlook.com    

MX Records                
Host Name               Points To                                           Priority    
@                       test365-forgepoc-com.mail.protection.outlook.com    0    

SRV Records
Host Name               Points To                                           Port    Weight    Priority    
_sip._tls               sipdir.online.lync.com                              443     1        100    
_sipfederationtls._tcp  sipfed.online.lync.com                              5061    1        100    

TXT Records
Host Name               Value    
@                       v=spf1 include:spf.protection.outlook.com -all

Configuring your proxy

A proxy is not required to get Office 365 up and running with OpenAM, but it is recommended. You’ll need some sort of proxy configuration if you plan to use multiple OpenAM servers in a HA deployment behind a load balancer.

For WSFED to work correctly behind a proxy, we need to set the host header on the proxy. Here is my NginX site configuration:

 

location / {
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $host:$server_port;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Host $host;
    proxy_pass https://login.test365corp.o365.forgepoc.com:8443;
    proxy_redirect default;
}
In the apache web server, you can achieve the same thing by setting the proxy_pass, proxy_pass reverse and ProxyPreserveHost directives.
<VirtualHost *:443>
    ServerName login.test365.forgepoc.com:443
 ProxyRequests off
 ProxyPass / https://login.test365corp.test365.forgepoc.com:8443/
 ProxyPassReverse / https://login.test365corp.test365.forgepoc.com:8443/
 ProxyPreserveHost On

    ...

</VirtualHost>

Configuring Active Directory UPN suffixes – optional, but recommended

If you have an existing Active Directory domain then it is likely that this will be configured already and you can skip this section. However, if you’ve set up an AD domain to do some basic tests and integration work, then read on.

Let’s say I make a user in active directory for Charlie Brown. I use the wizard in Active Directory users and computers and give him first name Charlie, last name Brown, username charlie.brown. Charlie will then be able to put in any of the following into the username prompt when logging on to a domain joined machine:

  • samAccountName: charlie.brown
  • cn: charlie brown
  • dn: CN=charlie brown,OU=user accounts,OU=test365corp,DC=test365corp,DC=o365,DC=forgepoc,DC=com
  • UPN: charlie.brown@test365corp.test365.forgepoc.com

Active Directory has a concept of user principal names (UPN) – a means of allowing a user account to be referenced by an email address style username that can have a different domain part to the DNS domain of the active directory domain. A UPN consists of the samAccountName and a DNS domain specified by an administrator.

Now let’s say mike wants to log on to his laptop with his email address, charlie.brown@test365.forgepoc.com. To do that, the Windows sysadmin needs to define an additional UPN suffix in the domain.

In office 365, if users authenticate to services directly with office 365 (WSFed active profile) then the user has to authenticate with their UPN. Therefore it makes sense to set the user’s active directory UPN to be the same as their office 365 UPN, which would normally be their email address. That way, users only need to remember one username.

In this example, we’ll configure a UPN suffix for the external DNS domain test365.forgepoc.com. Open Active Directory Domains and Trusts (domain.msc) and right click on the root node in the left pane:

Add the UPN suffix:

Quickstart OpenAM configuration using ssoadm batch commands

If you know OpenAM well, here are some ssoadm batch commands that will get you setup quickly. Use the metadata files from below and skip the remaining sections on configuring OpenAM.
create-datastore -e / -m ActiveDirectory -t LDAPv3ForAD -a "sun-idrepo-ldapv3-config-ldap-server=svr1.test365corp.test365.forgepoc.com:636" "sun-idrepo-ldapv3-config-authid=CN=ldapUser,CN=Users,DC=test365corp,DC=test365,DC=forgepoc,DC=com" "sun-idrepo-ldapv3-config-authpw=SOMEPASSWORD" "sun-idrepo-ldapv3-config-connection-mode=LDAPS" "sun-idrepo-ldapv3-config-organization_name=DC=test365corp,DC=test365,DC=forgepoc,DC=com" "sun-idrepo-ldapv3-config-people-container-name=ou" "sun-idrepo-ldapv3-config-people-container-value=test365corp" "sun-idrepo-ldapv3-config-psearchbase=CDC=test365corp,DC=test365,DC=forgepoc,DC=com"
create-auth-instance -e / -t AD -m ActiveDirectoryModule
update-auth-instance -e / -m ActiveDirectoryModule -a "iplanet-am-auth-ldap-bind-dn=cn=ldapAuth,cn=users,DC=test365corp,DC=test365,DC=forgepoc,DC=com" "iplanet-am-auth-ldap-bind-passwd=SOMEPASSSWORD" "iplanet-am-auth-ldap-server=svr1.test365corp.test365.forgepoc.com:636" "openam-auth-ldap-connection-mode=LDAPS" "iplanet-am-auth-ldap-user-naming-attribute=cn" "iplanet-am-auth-ldap-base-dn=DC=test365corp,DC=test365,DC=forgepoc,DC=com" "iplanet-am-auth-ldap-user-search-attributes=mail" "iplanet-am-auth-ldap-user-search-attributes=cn" "iplanet-am-auth-ldap-return-user-dn=true"
create-auth-cfg -e / -m employeeChain
update-auth-cfg-entr -e / -m employeeChain -a "ActiveDirectoryModule|REQUIRED"
set-realm-svc-attrs -e / -s iPlanetAMAuthService -a "iplanet-am-auth-org-config=employeeChain"
import-entity -e / -c wsfed -m /home/centos/idpMeta.xml -x /home/centos/idpMetaExtended.xml
import-entity -e / -c wsfed -m /home/centos/spMeta.xml -x /home/centos/spMetaExtended.xml
create-site -s site1 -i https://login.test365.forgepoc.com:443/openam
add-site-members -s site1 -e https://login.test365corp.test365.forgepoc.com:8443/openam

Configure OpenAM to work behind a proxy

Use the deployment menu in OpenAM 13.5 to add a site to the deployment. Make the site URL the URL of your proxy. Once done, add your OpenAM server(s) to that site.

Configuring OpenAM authentication services

I’m assuming here that you’ve already got an Active Directory dataStore setup in the top level realm.
Head over to authentication and create an Active Directory authentication module. Make sure to configure this as described here, it is required for WS-Federation active requestor profile to work later on.
Set up the module as described below. Below, I’ve allowed users to log on with mail as well as their usual login method, assuming that the mail attribute in the user account matches the UPN of the account setup in office 365.

However, if you have UPN sufixes setup in your AD domain (as described in my instructions above) you’ll probably want to use userPrincipalName instead of mail:

Add this module to a chain and set it to be the default organisation login chain for your realm:

Create your WS-Federation hosted IDP and Remote SP

Manually creating WSFED entities in OpenAM is a bit tedious so I’ve provided some ready made entities for you to use here. I am assuming these will be added to the top level realm – you’ll need to adjust your endpoints to match your realm if you’ve used something different. I am also assuming that we’ll use the default OpenAM test certificate for token signing. You should use something different in production.

Go to the Federation section in OpenAM and create a circle of trust called cot:

Import these entities using the import entity button, making sure to add them to the correct realm:

You should now have a list of entities that looks something like this:

Set up your Azure tenant using PowerShell

If you haven’t done it already, install the Azure Powershell cmdlets on a Windows machine that you have access to.
Authenticate using Connect-MsolService:

Then use the Set-MsolDomainAuthentication cmdlet to setup your domain and make sure to set the signing certificate to the cert you are signing your assertions with:

$BrandName   = "ForgeRock test365"
$dom         = "test365.forgepoc.com"

$IssuerUri   = "urn:uri:test365forgepocemployeestlr"
$PassiveUri  = "https://login.test365.forgepoc.com:443/openam/WSFederationServlet/metaAlias/wsidp"
$ActiveUri   = "https://login.test365.forgepoc.com:443/openam/WSFederationServlet/sts/metaAlias/wsidp"
$MexUri      = "https://login.test365.forgepoc.com:443/openam/WSFederationServlet/ws-trust/mex/metaAlias/wsidp"

$Protocol    = "WsFed"

$SigningCert = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

Set-MsolDomainAuthentication `
-Authentication Managed `
-DomainName $dom

Set-MsolDomainAuthentication `
-Authentication Federated `
-DomainName $dom `
-FederationBrandName $BrandName `
-PassiveLogOnUri $PassiveUri `
-ActiveLogOnUri $ActiveUri `
-MetadataExchangeUri $MexUri `
-SigningCertificate $SigningCert `
-IssuerUri $IssuerUri `
-LogOffUri $PassiveUri `
-PreferredAuthenticationProtocol $Protocol

Enabling “modern authentication” on the Azure Exchange and Skype services

Until recently, I had all Windows, MacOS, IOS and Android rich clients working, apart from one: Skype for business for Android. I was about to start analysing the network traffic, when my colleague Peter Major directed my to a community forum question from the user Steven Van Geel.

Even though Steven’s question was related to using Android Skype for business with OpenAM as a an Office 365 IDP using SAML2 ECP, the fix he describes also corrects the behaviour with the android app with a WsFed Active profile IDP. Turning on Microsoft “modern authentication” on the Skype for business online tenant allows the Skype client to authenticate.

I have not had a chance to had a look at why this is and why it only affects the Android Skype client. I will update this blog post when I find out. It is highly possible that this may be required for other clients in future as Microsoft gradually move services onto their “Modern Authentication” standard. Note that modern authentication can be turned on for Skype and for Exchange (Outlook).

For now, here are some brief instructions for enabling this. These are pretty similar to the steps for setting up the Azure online domain. First you need to install the Skype for Business PowerShell management cmdlets.

Then run the following to authenticate to your Skype Online (aka Lync Online) tenant:

 

$credential = Get-Credential
$session = New-CsOnlineSession -Credential $credential
Import-PSSession $session
Get-Module
Then turn on Modern Authentication as described in this article:
Set-CsOAuthConfiguration -ClientAdalAuthOverride Allowed

Setting up your first user

All that is left to do now is to configure a user to sign on to Office 365. Office 365 requires that accounts which federate with Office 365 also have an account entry set up in Office 365 itself. Certain properties have to be set on that account, such as the UPN and what licenses are assigned to the user. Microsoft provide the tools DirSync and Azure AD Connect that automatically synchronise on-prem Active Directory with Office 365. These are cut down versions of their identity Management Solution, “ForeFront Identity Manager” (FFIM – now EOL). ForgeRock have an Identity Management product, OpenIDM which has a powerful PowerShell connector. This can be configured to automatically provision accounts to Office 365 (see example scripts here and the IDM trunk docs here), but this is outside the scope of this post.

Here, I’ll show how to manually set up an account.

Assuming you have the following user in Active Directory:

The following PowerShell will set up that user in office 365 by copying the attributes from the same user in Active Directory.
$user = Get-ADUser charlie.brown
MSOnlineExtendedNew-MsolUser `
-DisplayName $user.Name `
-FirstName $user.GivenName `
-ImmutableId ([System.Convert]::ToBase64String(($user.ObjectGUID).ToByteArray())) `
-LastName $user.Surname `
-LicenseAssignment (Get-MsolAccountSku | select -ExpandProperty AccountSkuId) `
-UsageLocation GB `
-UserPrincipalName $user.UserPrincipalName

So how does this PowerShell work? We get the charlie.brown user from AD then pass the properties from it to the New-MsolUser method. We use the Get-MsolAccountSku method to find the SKU of the license we need to assign to the user. We also convert the Active Directory ObjectGUID property into the base64 format expected in Office 365.

Note: If the UPN of your user doesn’t match the name that they may fill in on something like the email account setup in Outlook, then you may want to change the userPrincipalName to use the mail attribute instead.

 

Conclusion

You should now be able to log on to Office 365 using all of the methods described above. There are some issues that you may encounter with this approach which you can track our progress on here.

What next? You may want to look at integrating this with with Integrated Windows Authentication (aka Kerberos, Windows Desktop SSO). I’ve done a blog post on that.

In a future blog post, I’ll look at doing the same thing with SAML2 ECP and the pros/cons of using that instead.

This blog post was first published @ http://authntoz.blogspot.no/, included here with permission from the author.

OpenAM: New topic-based documentation

This blog post was first published @ marginnotes2.wordpress.com, included here with permission.

OpenAM’s capabilities have grown significantly in the last few releases, with the result that even the product docs outgrew the old organization. Thanks to Chris Lee, Cristina Herraz, David Goldsmith, and Gene Hirayama, the draft docs are now arranged to make it easier to find just what you are looking for.

Instead of a guide-based doc set, what you see now are topic-oriented categories that bring you right to the features you want to use:

  • Try OpenAM (up and running quickly, ready for evaluation)
  • Access Management (authentication and single sign-on, authorization, RADIUS)
  • Federation (OAuth 2.0, OpenID Connect 1.0, SAML, STS)
  • User Services (self-registration, self-serve account and password management, self-serve sharing using UMA)
  • Installation and Maintenance (plan, install, set up, upgrade, and maintain access management services)
  • Extensibility (REST APIs, Java APIs and SPIs, C SDK)
  • Policy Agents (for enforcing policy on web sites and in Java web applications)

Each guide is written so that you find everything about a topic in one place. Are you focused on centralizing access policies for authorization? Read the Authorization Guide. Interested in granting access to account info for modern mobile and web applications using OpenID Connect? See the OpenID Connect 1.0 Guide. Participating in a federation of SAML 2 providers? Check out the SAML 2.0 Guide.

Those of you who knew the old layout intimately are probably going to wonder, “Where did you move my stuff?” In fact, there is a guide for that, too. Having Trouble Finding Something? indicates where your stuff went, with tables of correspondence from each section in the old layout to the topic in the new layout.

Great to see this leap forward towards a topic-based documentation set for OpenAM!

OpenAM: New topic-based documentation

ForgeRock LogoOpenAM’s capabilities have grown significantly in the last few releases, with the result that even the product docs outgrew the old organization. Thanks to Chris Lee, Cristina Herraz, David Goldsmith, and Gene Hirayama, the draft docs are now arranged to make it easier to find just what you are looking for.

Instead of a guide-based doc set, what you see now are topic-oriented categories that bring you right to the features you want to use:

  • Try OpenAM (up and running quickly, ready for evaluation)
  • Access Management (authentication and single sign-on, authorization, RADIUS)
  • Federation (OAuth 2.0, OpenID Connect 1.0, SAML, STS)
  • User Services (self-registration, self-serve account and password management, self-serve sharing using UMA)
  • Installation and Maintenance (plan, install, set up, upgrade, and maintain access management services)
  • Extensibility (REST APIs, Java APIs and SPIs, C SDK)
  • Policy Agents (for enforcing policy on web sites and in Java web applications)

Each guide is written so that you find everything about a topic in one place. Are you focused on centralizing access policies for authorization? Read the Authorization Guide. Interested in granting access to account info for modern mobile and web applications using OpenID Connect? See the OpenID Connect 1.0 Guide. Participating in a federation of SAML 2 providers? Check out the SAML 2.0 Guide.

Those of you who knew the old layout intimately are probably going to wonder, “Where did you move my stuff?” In fact, there is a guide for that, too. Having Trouble Finding Something? indicates where your stuff went, with tables of correspondence from each section in the old layout to the topic in the new layout.

Great to see this leap forward towards a topic-based documentation set for OpenAM!


SiteMinder Policy conversion to OpenAM XACML

In this article I discuss migrating SiteMinder policies to OpenAM. I have laid out an approach and framework to make the conversion possible using XML parsing, XML codifying and custom metadata that is necessary to resolve embedded repository externalities in the SiteMinder policy definition. I have also written a Java-based program that uses the methodology discussed in this article to parse through the SiteMinder policy and resolve each policy construct to an OpenAM equivalent policy object. The program codifies the XACML output step-by-step and on completion, one is able to import the XACML policy set into OpenAM via the policy editor.

There are going to be some complications in your situation such as when converting whitelisted resource URI – that SiteMinder does not ‘trap’ in the policy definition- you will need to know which URI are not in your SM policy extract and allowed by default, and then go about creating or adding the same URI in a new or ‘converted’ OpenAM policy. You would then need to whitelist those URI by explicitly allowing access in OpenAM.

I begin by describing the general layout of an XPS domain export at a high level, and how different policy constructs in a SiteMinder policy map over to OpenAM.

Survey of SiteMinder Policy Objects

While there is not a one-to-one mapping for every policy construct, there is a logical mapping that is useful to achieve a first pass on the conversion. Some of the complications are elaborated on below.

CA.SM::Domain -> OpenAM Policy Set Definition

The CA.SM::Domain object is the parent object to several domain-specific properties such as Mode, Name and UserDirectoriesLink references. Nested directly under the Domain object are CA.SM::Realm,  CA.SM::Policy and CA.SM::Response objects.

CA.SM::Realm -> OpenAM Policy Resources

The Realm object includes properties that describe the AgentGroupLink and AuthScheme settings, session properties such as IdleTimeout, and among other things, the ResourceFilter that is the protected resource URI. Realm also contains a nested object, called the CA.SM::Rule with an associated XID that describes the Actions available for the ResourceFilter- such as GET, PUT and POST- and properties that describe regular expression matching, time restrictions, resource pattern and IsEnabled among other things.

CA.SM::Response -> OpenAM Response Attributes

Response object is a container for one or more name-value pairs, or ‘response attributes’ expected by the agent. These can be of type Web agent responses or RADIUS responses. This conversion article and the Java program are limited to handling only the Web agent responses currently.

The Response object has an associated XID, and includes properties that describe the authorization conditions when the response is applicable- such as AccessAccept and AccessChallenge- and properties for AgentTypeLink and Name.

CA.SM::ResponseAttr

Response also nests CA.SM::ResponseAttr objects, each with a unique XID, that each have properties for AgentTypeAttrLink- pointing to ReferenceObjects such as “WebAgent-HTTP-Header-Variable” indicating the means of transport for the response attributs- and also the Value of the response codified in the form of display-name=<%userattr=”profile-attribute-name”%>. Here it is assumed that the value is sourced from a user attribute, which is mostly the case, although several types of ResponseAttrs are possible, including user attribute as already mentioned, DN Attribute, Static values, Session Variable, etc.

CA.SM::Policy -> OpenAM Policy Definition

Nested under the Domain object, and at peer level to the Realm and Response objects is the CA.SM::Policy object that serves to tie together protected resource URI to the corresponding user audience, rules including actions, response objects and optionally, IP address restrictions and time restrictions for those URI.

CA.SM::PolicyLink

The Policy object container has one or more CA.SM::PolicyLink objects that can be thought of as associations between the protected resources and the responses configured for each of them. The PolicyLink objects each have CA.SM::ResponseLink and CA.SM::RuleLink properties.

CA.SM::ResponseLink and CA.SM::RuleLink

The ResponseLink is a pointer to the Response object definition, and the RuleLink is a pointer to the Rule definition stored inside a CA.SM::Realm object. When invoked for a specific Realm, the policy enforces the Rule Actions as well as the Response attributes in case the policy evaluation is successful.

CA.SM::UserPolicy

The Policy object also contains one or more CA.SM::UserPolicy objects that can be thought of as audience restriction conditions. The UserPolicy object has properties defining the FilterPath, which is a SQL query but one that could be used to locate a set of users this policy applies to. Another property is the UserDirectoryLink that is a pointer to the external repository that contains the user profile data, and specifically stores the XID of the ReferenceObject by the name CA.SM::UserDirectory.

References

Besides Domain objects, there are also reference objects at a peer level to Domain. The Reference object tree encapsulates all external information that the policy references.

CA.SM::UserDirectory

The user repository information is stored under the CA.SM::UserDirectory ReferenceObject that includes a NameSpace attribute- such as “ODBC:”- and Server name. As mentioned previously the UserPolicy object stores a reference to the UserDirectory object using a UserDirectoryLink.

The program relies on these user directory references to be resolved using a metadata container in OpenDJ.

CA.SM::AgentGroup

The AgentGroup object refers to the SiteMinder agent configurations that all protect the same resources. The attribute AgentTypeLink contains a value that is referenced from CA.SM::Response objects using the AgentTypeLink property tying the web agent to that particular response object. There could be one or more Agent Groups.

CA.SM::AgentTypeAttr

One or more of these Reference objects define in what form the agent expects the response objects to be returned. Two currently supported, and commonly used, values include “WebAgent-HTTP-Header-Variable” and “WebAgent-HTTP-Cookie-Variable”. These are available for use in accept or reject responses only in SiteMinder.

Some other Reference objects include CA.SM::AgentType, which describes the SM agent- basically a Web Agent. Another is the CA.SM::AuthScheme which includes details about the form of authentication such as Forms-based, Basic auth or API.

Conversion to OpenAM

Converting CA.SM::Domain and CA.SM::Realm objects

Simply parse out these objects from the SiteMinder policy extract and create OpenAM policy set XACML definitions.

A code sample to establish the proper order and parity between the XACML elements is shown here:

        Element target = doc.createElementNS("ns2", "ns2:Target");
 	Element anyOf_subject = getAnyOfSubjectTree(doc, xmlMap);
 	target.appendChild(anyOf_subject);

 	Element anyOf_resource = getAnyOfResourceTree(doc, xmlMap, resourceUri);
 	target.appendChild(anyOf_resource);
 		
  	Element anyOf_application = getAnyOfApplicationTree(doc, xmlMap);
       	target.appendChild(anyOf_application);
       	
       	Element anyOf_action = getAnyOfActionTree(doc, xmlMap, actions);
       	target.appendChild(anyOf_action);

A code sample for creating the Resource URI in XACML format is shown below:

private static Element getAnyOfResourceTree(Document doc, Map<String, String> xmlMap, List resourceUri) {
// many AnyOf elements to define subject, resources, actions, etc
  	Element anyOf = doc.createElementNS("ns2", "ns2:AnyOf");
  	for(String url : resourceUri) {
		Element allOf = doc.createElementNS("ns2", "ns2:AllOf");
		Element Match = doc.createElementNS("ns2", "ns2:Match");
		Match.setAttribute("MatchId", "urn:sun:opensso:entitlement:resource-match:application:"+xmlMap.get("PolicyId"));
	       	Element AttributeValue = doc.createElementNS("ns2", "ns2:AttributeValue");
                AttributeValue.setAttribute("DataType", "http://www.w3.org/2001/XMLSchema#string");
                AttributeValue.setTextContent("*://*:*" + url);
   	        Match.appendChild(AttributeValue);
	       	Element AttributeDesignator = doc.createElementNS("ns2", "ns2:AttributeDesignator");
	       	AttributeDesignator.setAttribute("Category", "urn:oasis:names:tc:xacml:3.0:attribute-category:resource");
	       	AttributeDesignator.setAttribute("AttributeId", "urn:oasis:names:tc:xacml:1.0:resource:resource-id");
	       	AttributeDesignator.setAttribute("MustBePresent", "true");
	       	AttributeDesignator.setAttribute("DataType", "http://www.w3.org/2001/XMLSchema#string");
	       	Match.appendChild(AttributeDesignator);
	       	allOf.appendChild(Match);
	       	anyOf.appendChild(allOf);
  	}
	return anyOf;
}

Converting the CA.SM::Rule.Actions objects

Here the challenge is to convert the ResourceFilters into ResourceURI objects in the XACML definition, and then add the relevant actions to those resource URI as defined in the CA.SM::Realm object definition. A sample method that adds basic actions to a policy is shown here:

private static Element getAnyOfActionTree(Document doc, Map<String, String> xmlMap, List actions) {
	// many AnyOf elements to define subject, resources, actions, etc
  		Element anyOf = doc.createElementNS("ns2", "ns2:AnyOf");
  		for(String action : actions) {
      		Element allOf = doc.createElementNS("ns2", "ns2:AllOf");
  		Element Match = doc.createElementNS("ns2", "ns2:Match");
  		Match.setAttribute("MatchId", "urn:sun:opensso:entitlement:action-match:application:"+xmlMap.get("PolicyId"));
	       	Element AttributeValue = doc.createElementNS("ns2", "ns2:AttributeValue");
	       	AttributeValue.setAttribute("DataType", "http://www.w3.org/2001/XMLSchema#string");
	       	AttributeValue.setTextContent(action);
		   Match.appendChild(AttributeValue);
	       	Element AttributeDesignator = doc.createElementNS("ns2", "ns2:AttributeDesignator");
	       	AttributeDesignator.setAttribute("Category", "urn:oasis:names:tc:xacml:3.0:attribute-category:action");
	       	AttributeDesignator.setAttribute("AttributeId", "urn:oasis:names:tc:xacml:1.0:action:action-id");
	       	AttributeDesignator.setAttribute("MustBePresent", "true");
	       	AttributeDesignator.setAttribute("DataType", "http://www.w3.org/2001/XMLSchema#string");
	       	Match.appendChild(AttributeDesignator);
	       	allOf.appendChild(Match);       	
	       	anyOf.appendChild(allOf);
  	}
  	return anyOf;
   }

Converting Policy bindings for CA.SM::Real,  CA.SM::Response and CA.SM::UserPolicy objects

This portion is the most complex in the conversion because linkages have to be parsed out of the SiteMinder policy extract and rendered as separate OpenAM policies in XACML format. In order to convert a CA.SM::Policy object the program needs to follow the following algorithm at the very at least and in order:

  1. Establish the linkages between the CA.SM::Realm objects and the CA.SM::Response objects using the PolicyLink binder object
  2. Resolve the Response object, dynamic key-value pairs, by either directly reading the data from an external repository, or converting the references attributes to LDAP specific attributes
  3. Resolve the Subject Restrictions manifest in the PolicyLink.UserPolicy by converting the SQL Query to an LDAP search filter
  4. Create one OpenAM policy under the previously established Policy Set per Realm-Response-UserPolicy linkage

These steps are necessary in order to preserve the linkage of specific resource URI being accessible over the policy decision and returning specific response attributes.

Parsing out the bindings between CA.SM::Realm and CA.SM::Response objects

Since not all CA.SM::Realm objects in the SiteMinder policy extract refer to all the CA.SM::Response objects it becomes necessary to collect those objects that are bound together and dispatch them into one OpenAM policy. This is because OpenAM ties together a group of protected resource URI to a group of subject conditions, environment conditions and response attributes.

Resolving the Response object into static or dynamic OpenAM Response Attributes

A design decision here could be that the response attributes will be pulled from a user repository such as OpenDJ, making the CA.SM::ResponseAttr.Value definitions very easy to resolve. After parsing the definitions that usually are of the form:

CL_Header=<%userattr="<%userattr="CL_Cookie_Value"%>|UID=<%userattr="DEF_PROFILE_ID"%>|State=<%userattr="ST"%>|City=<%userattr="ADDR_CITY"%>|AddressLine1=<%userattr="ADDR1"%>|AddressLine2=<%userattr="ADDR2"%>|CompanyName=<%userattr="COMPANY"%>

One could construct the response objects one by one, with the display attribute (left of the “=” sign) as key and user profile attribute within quotes above, as the value. Simplistic string split and parsing techniques could be used to achieve this. The mapping of user profile attributes shown here could also be stored as key-value pairs in a metadata container in OpenDJ:

 

meta

Here, the connection information is stored as an LDAP url in description, admin username in sn and password (hidden) in givenName. The mapping of the user attributes is stored in cn. Using this information the program resolves the key-value pairs from the source repository to that of the target repository schema and the resulting key-value pairs are codified as OpenAM Response objects into XACML, as shown:

urn:sun:opensso:entitlement:json-resource-attribute:com.sun.identity.entitlement.UserAttributes:<attr-name>

Resolve the Subject Restrictions manifest in the PolicyLink.UserPolicy

Converting subject conditions derived from CA.SM::UserPolicy objects such as this one:

userpolicy

..would involve the same framework presented above, except this time we will create an LDAP search filter from the SQL Query- again assuming we are seeking data from an LDAP repository- to ensure the policy is only fired when the subject condition is satisfied.

The program can also provide support for directly retrieving user profile attributes – either for Subject Restrictions presented above in the form of LDAP filters, or for dynamically creating the Response key-value pairs in XACML. The metadata can have connection information stored as shown above that could be used to achieve this external lookup.

 

A Beginners Guide to OpenIDM Part 5 – User Registration

Last time we configured mappings to create user objects in OpenIDM from a CSV file. This is commonly something you might do when populating a new identity system for the first time with your existing users, but what about getting new users into the system?

 

This blog we will take a look at configuring OpenIDM’s user self registration functionality and how we can perform some post processing on new users.Note: As many of you will be aware OpenIDM 4.5 has recently been released, for now I am going to continue using OpenIDM 4 for this blog but everything we talk about here is still applicable to 4.5, albeit with minor differences. I will likely move to OpenIDM 4.5 (or 5 even) when the beginners series is concluded.

User Registration

To turn on User Registration in OpenIDM, first log in as an administrator. Then navigate to Configure, then User Registration.

 

 You will see the User Registration configuration screen:

 

 

Now before we turn it on, log out and take a look at the OpenIDM user login screen: http://localhost.localdomain.com:8080/#login/

 

 

Just try to remember what it looks like right now, as it will change in a moment.

 

By default, User Registration is disabled. Lets enable it now. Click the “Enable User Registration” slider.

 

You can see that we have a number of Registration Steps. These can be turned on and off as you require, they can also be re-ordered by dragging and dropping.

 

Lets briefly talk about what each of these steps involves:
  • reCAPTCHA for Registration: Google’s “I am not a robot” dialog. To prevent automated bots registering.
  • Email Validation: User is sent an email, they must click a link in the email to progress registration. Verifying that they do indeed have access to the email account.
  • User Details: Simply allows you to modify the attribute on the user object associated with email address. By default this is mail but you might want to change it based on your managed user schema if you have made changes.
  • KBA Stage: Whether or not to enforce the use of Knowledge Based Authentication i.e. challenge questions and answers.
  • Registration Form: Here you can change the Identity Service URL to another managed object.
Note that you cannot configure everything in the UI, but we will shortly take a close look at how you can do that for Email Validation and KBA Stage if required.

 

So lets make sure that we have turned everything on in the as in the image above, except for reCAPTCHA. There is no save button. Toggling the sliders is sufficient here.

 

Now log out again, and take another look at the user login screen:

 

 

You should see we now have a link to Register. You can take a look but this won’t really work yet as we need to configure the steps, mainly Email Validation. So lets do that now.

 

Configuring Email Validation

We need to configure Email Validation and for this we are going to need an email server. If you have an email server, great. If not I suggest downloading something like https://mailtrap.io

 

Navigate to Configure, then System Preferences.

 

Select the Email tab.

 

 

Toggle the Enable Email slider, then Use SMTP Authentication.

 

 

Enter the host, port and credentials for your email server.

 

 

Then press Save.

Testing Registration

Logout of OpenIDM, navigate to the user login page: http://localhost.localdomain.com:8080/#login/ and select the Register link again.

 

Enter a test email address and press SEND.

 

All being well you should receive an email:

 

 

If you click the link, you will continue the registration process in OpenIDM.

 

Press Save, then you can complete your KBA questions:

 

 

When that is done, press Save for the final time and you should see that…

 

 

Registration is complete, if you Return to Login Page you should be able to log in with your new user ( by default this is the username we set on the 2nd page, not the email address ).

 

 

Customising Registration

As with everything ForgeRock every step of the Registration process can be customised, and you can use our REST API’s if you want to build a completely customised experience.

 

However there are two customisations which are frequently performed, let’s take a quick look at them now.

Customising the Registration Email

This can be easily achieved through the UI, if you return to Configure, then User Registration and edit the Email Validation step.

 

 

If you prefer you can also edit this directly via <openidm>/conf/selfservice-registration.json

 

Customising KBA Challenge Questions

If you want to edit KBA questions you need to do this directly by editing <openidm>/conf/selfservice.kba.json

This blog post was first published @ http://identity-implementation.blogspot.no/, included here with permission from the author.

Identity Disorder Podcast, Episode 4: The Rodeo of Things

identity-disorder-speakers-ep004

In episode 4, Daniel and Chris are pleased to welcome one of ForgeRock’s founders, Victor Ake. Victor gives his insight into the Identity of Things, talking the differences between constrained and unconstrained devices, how IoT brokers work, securing IoT devices using identity standards, and how microservices fit in to the picture. Other topics include airport hotels, wrestling, and–wait for it–the rodeo.

Episode Links:

ForgeRock IoT Page:
https://www.forgerock.com/solutions/devices-things/

ForgeRock Identity Summit in London and Paris
https://summits.forgerock.com/

All upcoming ForgeRock events:
https://www.forgerock.com/about-us/events/

Debugging OpenAM and OpenIDM

My background is the what I call the world of legacy identity, as such it took me a little while to get used to the world of ForgeRock, REST API’s and the like.


If you come from that world you may find debugging implementation issues with ForgeRock is a little different so I wanted to write up a short guide to share what I have learned.

Have you checked the logs?

Some things never change and your first port of call to debug any issues should be the log files.

OpenAM

There are actually two places to check when debugging OpenAM:


Note: <openam_install_dir> is the directory in which OpenAM was installed, not the web container.


<openam_install_dir>openam/debug



This is where you find the debug logs. Generally very detailed logs for all the different components of OpenAM.


<openam_install_dir>openam/log


This is where you find access and error logs. Detailing access requests and the result of those requests.


For example, if we look at access.csv:



You can see the result of my last login as amadmin.

Configuring log levels

If you don’t see anything, you may need to change the logging configuration.


Navigate to: http://localhost.localdomain.com:18080/openam/Debug.jsp




This interface is fairly straight forward



In the above example I have set the policy component to Message level.


Just hit confirm and the change will be made immediately without a restart required.

OpenIDM

Again, there are actually two places to check when debugging OpenIDM:


<openidm_install_dir>openidm/logs


The main OpenIDM log files can be found here. OpenIDM used JDK logging and the configuration file can be found here if you need to make changes to logging levels:


<openidm_install_dir>openidm/conf/logging.properties


There is a helpful guide as to how do that here: http://www.javapractices.com/topic/TopicAction.do?Id=143


So far that is all fairly standard, however if you do not find anything in the logs then you may want to examine the REST services.

Debugging REST services

As I have said a few times on his blog, the ForgeRock platform is completely underpinned by REST services.


The User Interfaces for OpenAM and OpenIDM both make extensive use of REST service calls in their functioning.


When debugging issues, especially anything that results in an error visible in the UI. You should take a look at the requests and responses.


I use FireFox Developer Tools to do this but I know there are equivalents for other browsers.


It’s as simple as turning on Developer Tools and examining the network requests whilst using OpenAM and OpenIDM.



So lets try making a new authentication chain in OpenAM.



What we need to find is the POST request for the creation of the chain. If you browse up and down the list you should find it pretty quickly. On the right you can see the Headers in the request, the parameters and importantly the response code:




And the response:


So let’s see what that looks like when we have an error:



Generally you will see something like the above, and if you check the actual response, you should see a more detailed message that can help you debug the issue.

This blog post was first published @ http://identity-implementation.blogspot.no/, included here with permission from the author.

OpenDJ: Monitoring Unindexed Searches…

FR_plogo_org_FC_openDJ-300x86OpenDJ, the open source LDAP directory services, makes use of indexes to optimise search queries. When a search query doesn’t match any index, the server will cursor through the whole database to return the entries, if any, that match the search filter. These unindexed queries can require a lot of resources : I/Os, CPU… In order to reduce the resource consumption, OpenDJ rejects unindexed queries by default, except for the Root DNs (i.e. for cn=Directory Manager).

In previous articles, I’ve talked about privileges for administratives accounts, and also about Analyzing Search Filters and Indexes.

Today, I’m going to show you how to monitor for unindexed searches by keeping a dedicated log file, using the traditional access logger and filtering criteria.

First, we’re going to create a new access logger, named “Searches” that will write its messages under “logs/search”.

dsconfig -D cn=directory manager -w secret12 -h localhost -p 4444 -n -X 
    create-log-publisher 
    --set enabled:true 
    --set log-file:logs/search 
    --set filtering-policy:inclusive 
    --set log-format:combined 
    --type file-based-access 
    --publisher-name Searches

Then we’re defining a Filtering Criteria, that will restrict what is being logged in that file: Let’s log only “search” operations, that are marked as “unindexed” and take more than “5000” milliseconds.

dsconfig -D cn=directory manager -w secret12 -h localhost -p 4444 -n -X 
    create-access-log-filtering-criteria 
    --publisher-name Searches 
    --set log-record-type:search 
    --set search-response-is-indexed:false 
    --set response-etime-greater-than:5000 
    --type generic 
    --criteria-name Expensive Searches

Voila! Now, whenever a search request is unindexed and take more than 5 seconds, the server will log the request to logs/search (in a single line) as below :

$ tail logs/search
[12/Sep/2016:14:25:31 +0200] SEARCH conn=10 op=1 msgID=2 base="dc=example,
dc=com" scope=sub filter="(objectclass=*)" attrs="+,*" result=0 nentries=
10003 unindexed etime=6542

This file can be monitored and used to trigger alerts to administrators, or simply used to collect and analyse the filters that result into unindexed requests, in order to better tune the OpenDJ indexes.

Note that sometimes, it is a good option to leave some requests unindexed (the cost of indexing them outweighs the benefits of the index). If these requests are unfrequent, run by specific administrators for reporting reasons, and if the results are expecting to contain a lot of entries. If so, a best practice is to have a dedicated replica for administration and run these expensive requests. Also, it is better if the client applications are tuned to expect these requests to take a long time.

Filed under: Directory Services Tagged: directory-server, ForgeRock, index, ldap, opendj, opensource, performance, search, Tips, tuning

This blog post was first published @ ludopoitou.com, included here with permission.

OpenDJ: Monitoring Unindexed Searches…

FR_plogo_org_FC_openDJ-300x86OpenDJ, the open source LDAP directory services, makes use of indexes to optimise search queries. When a search query doesn’t match any index, the server will cursor through the whole database to return the entries, if any, that match the search filter. These unindexed queries can require a lot of resources : I/Os, CPU… In order to reduce the resource consumption, OpenDJ rejects unindexed queries by default, except for the Root DNs (i.e. for cn=Directory Manager).

In previous articles, I’ve talked about privileges for administratives accounts, and also about Analyzing Search Filters and Indexes.

Today, I’m going to show you how to monitor for unindexed searches by keeping a dedicated log file, using the traditional access logger and filtering criteria.

First, we’re going to create a new access logger, named “Searches” that will write its messages under “logs/search”.

dsconfig -D cn=directory\ manager -w secret12 -h localhost -p 4444 -n -X \
    create-log-publisher \
    --set enabled:true \
    --set log-file:logs/search \
    --set filtering-policy:inclusive \
    --set log-format:combined \
    --type file-based-access \
    --publisher-name Searches

Then we’re defining a Filtering Criteria, that will restrict what is being logged in that file: Let’s log only “search” operations, that are marked as “unindexed” and take more than “5000” milliseconds.

dsconfig -D cn=directory\ manager -w secret12 -h localhost -p 4444 -n -X \
    create-access-log-filtering-criteria \
    --publisher-name Searches \
    --set log-record-type:search \
    --set search-response-is-indexed:false \
    --set response-etime-greater-than:5000 \
    --type generic \
    --criteria-name Expensive\ Searches

Voila! Now, whenever a search request is unindexed and take more than 5 seconds, the server will log the request to logs/search (in a single line) as below :

$ tail logs/search
[12/Sep/2016:14:25:31 +0200] SEARCH conn=10 op=1 msgID=2 base="dc=example,
dc=com" scope=sub filter="(objectclass=*)" attrs="+,*" result=0 nentries=
10003 unindexed etime=6542

This file can be monitored and used to trigger alerts to administrators, or simply used to collect and analyse the filters that result into unindexed requests, in order to better tune the OpenDJ indexes.

Note that sometimes, it is a good option to leave some requests unindexed (the cost of indexing them outweighs the benefits of the index). If these requests are unfrequent, run by specific administrators for reporting reasons, and if the results are expecting to contain a lot of entries. If so, a best practice is to have a dedicated replica for administration and run these expensive requests. Also, it is better if the client applications are tuned to expect these requests to take a long time.


Filed under: Directory Services Tagged: directory-server, ForgeRock, index, ldap, opendj, opensource, performance, search, Tips, tuning

OpenAM Text To Speech Authentication Module

For a recent POC I had a requirement to implement two factor authentication for users who may have impaired vision and would struggle to read an OTP or the code from a 2FA application.

To achieve this I cloned the existing OpenAM HOTP module and integrated it with The Twilio service: https://www.twilio.com/

I might do a bit more of a deep dive into how exactly this works later but for now the code is up in Github:

https://github.com/wayneblacklock/ttsAuthModule

And you can see a video of how it works below:

There is definitely room for improvement here, at the moment I am using the a Twimlet to encode the voice, in a production deployment you will want to generate TWIML (https://www.twilio.com/docs/api/twiml) in order to have more control over the voice i.e. introduce pauses etc.

This blog post was first published @ http://identity-implementation.blogspot.no/, included here with permission from the author.