Wednesday, March 16, 2016

OpenID Connect Session Management Support in WSO2 IS 5.2.0



OpenID Connect is an emerging authentication protocol defined on top of OAuth 2.0 protocol. The complete protocol suite consists of a series of documents.

Here, we are going to focus on one such document, i.e OpenID Connect Session Management and how that will be supported with WSO2 IS 5.2.0, which will be released soon.

OpenID Connect Session Management specification, defines a way for a Relying Party (RP), to monitor the login status of an end user with an OpenID Connect Provider (OP) minimizing the network traffic. The specification proposes to use two hidden iframes, one at the RP (RP iframe) and the other page is served by the OP (OP iframe) and it is loaded from an invisible iframe at the RP side. These iframes synchronizes the session state between the OP and RP such that the RP gets to know when session state has changed and re-authenticates with a passive request. If an authentication failure or unsuccessful response is received RP will handle that as a logout of the end user.

Please refer the specification for more detail.

So let’s see how WSO2 IS 5.2.0 will support for OIDC Session Management.
Basically, there are two endpoints exposed to support this feature.

OIDC Logout Endpoint:

https://<IS_SERVER_HOST>:<IS_SERVER_PORT>/oidc/logout

Ex:

For a fresh server running in local the endpoint URL will be as below.

https://localhost:9443/oidc/logout

By invoking this endpoint a RP can notify the OP to logout an end user from the OP. Due to some implementation limitations for the moment WSO2 IS 5.2.0 will not support the query parameters defined in the specification. Thus, a RP will not be able to request to redirect the user agent back to the RP after a logout has been performed with ‘post_logout_redirect_uri’ query parameter. But, these will be addressed soon, with the next release.

OIDC Session Iframe Endpoint:

https://<IS_SERVER_HOST>:<IS_SERVER_POST>/oidc/checksession?client_id=<CLIENT_ID>

Ex:

For a fresh server running in local the endpoint URL will be as below.

https://localhost:9443/oidc/checksession?client_id=2PX8XTppZBa6FYRZ6wqFs_o0mGYa


This endpoint provides the OP iframe, that supports session state synchronization with RP client via HTML5 postMessage API. This page should be loaded from an invisible iframe embedded in the RP client application.

As defined in the specification, the page will accept post message requests from the respective RP iframe and will post back the status of the session state.

How OIDC Session Management works at WSO2 IS 5.2.0


As per the specification WSO2 IS 5.2.0 will also return the additional ‘session_state’ parameter in the authentication response, when authenticated over the authorization code flow or implicit flow. This session state value is initially calculated at the server based on the salted cryptographic hash of the Client ID, Client Origin and OP Browser State.

Here Client Origin is derived from the ‘Callback Url’ registered at the OP, which is the URI scheme, hostname and port number of the ‘Callback Url’ as defined here. OP Browser State is maintained by a cookie, called ‘opbs’. The Session State value will be changed as per the end user’s authentication status (login, logout) in the browser, and as authentication status of Clients being used by the end user changes (ex: user logins for a new client) in the browser.

Once the session between the RP and OP is established with the authentication request and response, RP is expected to check the session status at the OP by polling a hidden OP iframe from a RP iframe without causing network traffic.

The post message request from the RP iframe to the OP iframe should be a concatenation of the Session State and the Client ID as below.

Client ID + “ “ + Session State

When OP iframe receives the post message it extracts the Session State and Client ID received. Then it recalculates the Session State using the received Client ID, OP browser state and Client Origin which is known. OP iframe will compare the received Session State value with the calculated value. If they match OP iframe will post the string ‘unchanged’ to the RP. if they do not match OP iframe will post as ‘changed’. If some error occurred and OP iframe could not determine the parameters needed for the calculation it will post as ‘error’.

RP iframe will receive back the post message from OP iframe, which would be either ‘changed’, ‘unchanged’ or ‘error ‘. Upon receipt of ‘changed’ RP must perform re-authentication with ‘prompt=none’ to obtain the current Session State at the OP.

If the end user has logged out from the OP, RP will receive an authentication failure along with a new Session State value. RP should handle this as a end user logout. Otherwise, RP will receive a successful authentication response along with a new Session State value and RP should update the Session State value

How can we test OIDC Session Management with Playground2 Sample application


In order to test OIDC Session Management feature we need to have a Relying Party implementation, which implements the RP iframe. The specification itself includes an example pseudo-code for the RP iframe. You can either refer that or refer the sample ‘Playground2’ relying party application that we have updated to support OIDC session management. (Get the source code from here and build with mvn clean install. In the target folder you will see an artifact as playground2.war).

1. Let’s deploy two relying party applications. For that make a copy of playground2.war and rename that as playground3.war. Then deploy them both in a web server such as tomcat. Here I’m using a tomcat server running on my local machine, in port 8080.

If you invoke http://localhost:8080/playground2/ url you should see the page below. Similarly you should see the same page if you invoke http://localhost:8080/playground3/





2. Then we need to register both of these relying party applications at the WSO2 Identity Server. Here I’m running the Identity Server on my local machine.

Goto the management console and click ‘Add’ button under ‘Service Providers’ in ‘Main’ tab.




Add the ‘Service Provider Name’ as ‘playground2’ and click ‘Register’

Goto ‘Inbound Authentication Configuration’ > ‘OAuth/OpenID Connect Configuration’ and click ‘Configure’




Add “http://localhost:8080/playground2/oauth2client” to the ‘Callback Url’ and click ‘Update’

Note down the ‘OAuth Client Key’ and ‘OAuth Client Secret’ values, since we need them in order to invoke the API for authentication.

Similarly register ‘playground3’ application also with the “http://localhost:8080/playground3/oauth2client” callback url


3. Let’s try to authenticate the user via the two registered applications.

I have created a user as ‘testuser1’ at the WSO2 Identity Server and authenticating against that user.

Invoke “http://localhost:8080/playground2/ “ and click on ‘Import Photos’




Provide below inputs and click ‘Authorize’

Authorization Grant Type :
Authorization Code (With this sample we can test OIDC only for Authorization Code flow)

Client Id :
Client ID of the playground2 application registered

Scope :
openid

Callback URL :
http://localhost:8080/playground2/oauth2client

Authorize Endpoint :
https://localhost:9443/oauth2/authorize

Logout Endpoint : 
https://localhost:9443/oidc/logout

Session Iframe Endpoint :
https://localhost:9443/oidc/checksession?client_id=<ClientID of playground2 application>


Login page will prompt. Provide the username and password.




Click ‘Approve Always’ in the consent page




Once the authentication is success, OP will redirect back to the client application with the authorization code and the session state.



If you see the console you will see the console logs printed by the RP iframe while polling the OP iframe.


Get the ID token and access token by giving inputs below.

Authorization Code :
Code received

Callback URL :
http://localhost:8080/playground2/oauth2client

Access Token Endpoint :
https://localhost:9443/oauth2/token

Client Secret :
Client Secret of playground2 application


OP will respond with the ID token and access token and you will see the below page.




We can further invoke the user info endpoint and obtain user claims with the access token received.

Give the ‘UserInfo Endpoint’ as ‘https://localhost:9443/oauth2/userinfo?schema=openid’ and click ‘Get UserInfo’



Similarly, invoke the playground3 application.

As soon as you receive the authorization code for the initiated authentication request for playground3 app, if you open up the browser console of playground2 application, you will note that RP iframe of playground2 has initiated a passive authentication request as the session state has been changed. And as the response has received, app will update it’s session state value and keep polling the OP iframe again.



Go back to the playground3 application and click ‘Logout’. Then approve the logout consent prompted.



Now the user will be logged out from the OP.




Go back to the playground2 application. You will note that the home page has been loaded. If you see the console you will note that the playground2 app’s RP iframe has initiated a passive authentication request and has received an error since end user session is no longer available at OP. So the app has handled this as a logout scenario.

Thursday, January 14, 2016

How to manage Authenticated Session in WSO2 IS 5.1.0

So I’m going to discuss about configuring the authenticated session in WSO2 IS 5.1.0.  The authenticated session means the session created for the end user, who authenticates for a Service Provider application via some authentication protocol (SAML, OpenID, OpenIDConnect, etc .). This is different from the management console login session.
In WSO2 IS, this authenticated session for a user is maintained with a cookie called  ‘commonAuthId’. When a user authenticates, a session is created for that user and that session is cached. That session’s identifier is set in the commonAuthId cookie.
I have previously blogged about, how authenticated session is maintained in WSO2 IS 500 here.
In IS 510 it’s moreover the same, but more configurable and simpler :).


In IS 500, we could not configure the session idle timeout, since cache timeout was not configurable. So it sticked to the default cache timeout period which was 15 minutes. But of course, we could increase it with remember me option and session data persistence.


The best thing in IS 510 is it’s configurable. Further, we can simply configure the ‘session idle timeout’ and the ‘remember me period’ from management console. Not only that, management console configuration applies only for the logged in tenant, which means it’s configurable per tenant.


There’s a global configuration for the ‘session idle timeout’ and the ‘remember me period’ in identity.xml (IS_HOME/repository/conf/identity/identity.xml)


<TimeConfig>
<SessionIdleTimeout>15</SessionIdleTimeout>
   <RememberMeTimeout>20160</RememberMeTimeout>
</TimeConfig>


This configuration is in minutes. So the default session idle timeout is 15 minutes, and the remember me timeout is two weeks. If you want to change the configuration globally, you can change it from here. So that will apply for the tenants you create, as the default configuration.
However, this configuration is overridable from the management console.
  1. Goto Home > Identity > Identity Providers and click List
  2. Then Click ‘Resident Identity Provider’
  3. There under ‘Resident Realm Configuration’ you can configure for session idle timeout by changing the value of ‘Idle Session Time Out’ and configure remember me period by changing the value of ‘Remember Me Period’. 
  4. Click ‘Update’ to update the configuration. Once updated this configuration will effect for the tenant you are logged in



There are few more configurations available to manage logged in session in identity.xml under Server.JDBCPersistenceManager configuration block.
In IS 510, session is persisted by default and a clean up task runs and remove persisted sessions older than two weeks. These default configurations can be changed if desired with below configurations in identity.xml.


Session persistence can be enabled or disabled from below configuration. However, note that regardless of the configuration it being enabled by default. So this <Enable> element can be used only to disable session persistence.


<SessionDataPersist>
<...>...<...>
<Enable>true</Enable>
<...>...<...>
</SessionDataPersist>


As I mentioned before, session persistence comes with a cleanup service that removes stale sessions.


<SessionDataPersist>
<...>...<...>
<SessionDataCleanUp>
<Enable>true</Enable>
<CleanUpPeriod>10</CleanUpPeriod>
<CleanUpTimeout>60</CleanUpTimeout>
</SessionDataCleanUp>
<...>...<...>
</SessionDataPersist>


Cleanup service is enabled by default. It can be disabled with SessionDataPersist.SessionDataCleanUp.Enable element.

SessionDataPersist.SessionDataCleanUp.CleanUpPeriod defines the time period among two consecutive cleanups in minutes. By default it is 1 day.

SessionDataPersist.SessionDataCleanUp.CleanUpTimeout defines the timeout value of session data in minutes. By default it is two weeks.

For an example if we consider the above configuration it means that the clean up task will run periodically with a period of 10 minutes.
And in a cleanup process it will remove all sessions persisted before 60 minutes.


In addition, below configurations are possible as well under <SessionDataPersist> element.


SessionDataPersist.OperationDataCleanUp.Enable
Along with persisting session and removing, the respective operation is stored with a timestamp, to reduce session persistence issues due to parallel executions of persistence and clean up processes.
There is a clean up task to clean up this table. By default it’s disabled and it can be enabled with this configuration.


SessionDataPersist.OperationDataCleanUp.CleanUpPeriod
This can be used to configure the timeout value of session operations data. By default it’s 720 minutes. It means at a cleanup task execution, it will remove data older than 720 minutes.


SessionDataPersist.Temporary
Setting this property to true will store data added to some other caches as well. So that in a cache hit if entry is not found, data will be retrieved from the session persistence store.


I just thought of mentioning about the caches for which persistence is enabled with ‘SessionDataPersist.Enable’ and for which persistence is enabled with ‘SessionDataPersist.Temporary’ for further reference.


Caches that persist data and reads from the store when session persistence is enabled.


Cache
Class
AppAuthFrameworkSessionContextCache
org.wso2.carbon.identity.application.authentication.framework.cache.SessionContextCache
AuthorizationGrantCache
org.wso2.carbon.identity.oauth.cache.AuthorizationGrantCache
SAMLSSOParticipantCache
org.wso2.carbon.identity.sso.saml.cache.SAMLSSOParticipantCache
SAMLSSOSessionIndexCache
org.wso2.carbon.identity.sso.saml.cache.SAMLSSOSessionIndexCache


Caches that persist data and reads from the store only if ‘SessionDataPersist.Temporary’ is set to true.


Cache
Class
AuthenticationContextCache
org.wso2.carbon.identity.application.authentication.framework.cache.AuthenticationContextCache
AuthenticationRequestCache
org.wso2.carbon.identity.application.authentication.framework.cache.AuthenticationRequestCache
AuthenticationResultCache
org.wso2.carbon.identity.application.authentication.framework.cache.AuthenticationResultCache
InboundAuthenticationContextCache
org.wso2.carbon.identity.application.authentication.framework.inbound.InboundAuthenticationContextCache
OAuthSessionDataCache
org.wso2.carbon.identity.oauth.cache.SessionDataCache
SAMLSSOSessionDataCache
org.wso2.carbon.identity.sso.saml.cache.SessionDataCache
PassiveSTSSessionDataCache
org.wso2.carbon.identity.sts.passive.ui.cache.SessionDataCache


Thanks for reading …

Saturday, December 19, 2015

Office 365 SAML 2.0 Federation with WSO2 Identity Server


Office 365 basically support three identity models [1].

Cloud Identity:
Here user identity is managed in Azure Active Directory (Cloud directory used by Office 365)

Synchronized Identity:
Here user identity is managed in an on-premises server and the user accounts and password hashes are synchronized with Azure Active Directory

Federated Identity:
Here user identity is verified by the on-premises Identity Provider (IdP). Yet user accounts should be synchronized with Azure AD except the password hashes, so that the user authentication happens via the on-premises IdP.

So here, I'm going to explain about configuring the 'Federated Identity' model with WSO2 Identity Server with SAML 2.0.

So, before starting make sure that you have below.

  • Office 365 Business Account with access to Admin Portal (Here I'm using a 30 day trial business account.)
  • Internet-resolvable domain name (Office 365 SSO requires an Internet-resolvable domain name to use as the suffix in each user’s username. You cannot federate the default domain that is provided by Microsoft that ends with "onmicrosoft.com").
  • A Windows Platform with Windows Azure Active Directory Powershell installed. You can get it from here.
  • WSO2 Identity Server 5.1.0 (You can get the latest releases of WSO2 Identity Server from here)

So first lets see how we can configure Azure Active Directory to trust our on-premises IdP which is the WSO2 Identity Server in this case.


1. Start Widows Azure Active Directory Powershell.


2.  Run $cred=Get-Credential
     This will prompt for windows Azure AD Admin credentials.



3. Run Connect-MsolService –Credential $cred to connect with stored credentials













4. To verify the availability of validated domain, run Get-MsolDomain . The ‘Status’ of our domain should be ‘Verified’, and ‘Authentication’ should be ‘Managed’.












5. Configure the domain as a federated domain, providing respective federation settings that match the IdP. Let's store federation settings in parameters.

Store your domain
$dom = "malithimal.com"

IdP Logon URL to POST SAML Authentication Request. Here it's the SAML SSO endpoint URL of WSO2 IS.
$logonurl = "https://localhost:9443/samlsso"

Issuer Id of the IdP. This should be the “Identity Provider Entity Id” in Resident IDP of WSO2 IS with regard to SAML.
$issueruri = "wso2is.510"

IdP Logout URL to POST SAML Logout Request. So it's the SAML SSO endpoint URL of WSO2 IS.
$logouturl = "https://localhost:9443/samlsso"

IdP Certificate. Base64 encoded signing certificate of WSO2 IS should be given here. For default key store configured in WSO2 IS certificate is as below. Please note that the certificate should be given in a single line without a break.
$cert = "MIICNTCCAZ6gAwIBAgIES343gjANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxDTALBgNVBAoMBFdTTzIxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xMDAyMTkwNzAyMjZaFw0zNTAyMTMwNzAyMjZaMFUxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzENMAsGA1UECgwEV1NPMjESMBAGA1UEAwwJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCUp/oV1vWc8/TkQSiAvTousMzOM4asB2iltr2QKozni5aVFu818MpOLZIr8LMnTzWllJvvaA5RAAdpbECb+48FjbBe0hseUdN5HpwvnH/DW8ZccGvk53I6Orq7hLCv1ZHtuOCokghz/ATrhyPq+QktMfXnRS4HrKGJTzxaCcU7OQIDAQABoxIwEDAOBgNVHQ8BAf8EBAMCBPAwDQYJKoZIhvcNAQEFBQADgYEAW5wPR7cr1LAdq+IrR44iQlRG5ITCZXY9hI0PygLP2rHANh+PYfTmxbuOnykNGyhM6FjFLbW2uZHQTY1jMrPprjOrmyK5sjJRO4d1DeGHT/YnIjs9JogRKv4XHECwLtIVdAbIdWHEtVZJyMSktcyysFcvuhPQK8Qc/E/Wq8uHSCo="

6. Run below to establish the trust
Set-MsolDomainAuthentication –DomainName $dom -Authentication Federated -PassiveLogOnUri $logonurl -SigningCertificate $cert -IssuerUri $issueruri -LogOffUri $logouturl -PreferredAuthenticationProtocol SAMLP













7. To verify federation settings run Get-MsolDomainFederationSettings -Domain $dom













So now we have setup the trust between our on-premises IdP WSO2 Identity Server and Azure Active Directory.

Note:
In case you need to redo configurations first you will need to move your domain back to managed authentication mode as below.

Set-MsolDomainAuthentication -DomainName $dom -Authentication Managed

Then redo the settings by providing parameters as in step (5) and setting the authentication method again as in step (6)


So let's move on to configuring WSO2 Identity Server.


So I have configured an Active Directory User Store as my primary User Store in my local server.
You can refer [2] in order to configure an Active Directory User Store.

Basically, there are three attributes that Azure AD expects in a SAML 2.0 message.


NameID The value of this assertion must be the same as the Azure AD user’s ImmutableID. This is the subject in the SAML response to Azure AD. So in this case we will use the ObjectGUID attribute in AD which is unique per user
IDPEmailThe User Principal Name (UPN) is listed in the SAML response as an attribute element with the name IDPEmail This is the user’s UserPrincipalName (UPN) in Windows Azure AD/Office 365. Basically this is the login username that a user tries out to login for Office 365. It should match with the domain name. (ex: malithi@malithimal.com). So here we will use the userPrincipalName attribute in AD to store this value
IssuerThis is required to be a URI of the Identity Provider

So from above three let's first configure the IdP Issuer Id. This should be the same value that you have provided as IssuerUri in step (5) and (6) when configuring Azure AD.

1. Start up WSO2 IS, running below from the console at path /repository/bin
    (I'm working on Unix so executing the shell command)
    sh wso2server.sh

2. Login to the Management Console invoking 'https://localhost:9443/carbon/'

3. Go to the 'Resident Identity Provider > Inbound Authentication Configuration > SAML2 Web SSO Configuration' and replace the value of 'Identity Provider Entity Id' with the value given for param '$issueruri' in step (5) when configuring Azure AD















4.  Add below two claims by going to 'Claims > Add > Add New Claim' under ‘http://wso2.org/claims’ dialect to include 'NameID' and 'IDPEmail' attributes in the SAML response as expected by Azure AD







Note:
Please un tick the 'Supported by Default' checkbox of below Claims under ‘http://wso2.org/claims’ dialect. These attributes are not supported by Active Directory by default. Either we have to map them to a proper attribute in Active Directory or need to add the mapped attributes. Since these are ticked as 'Supported by Default' these attributes are shown in the default user profile and we will get an error once we try to update the profile.


ClaimClaim UriMapped Attribute
Countryhttp://wso2.org/claims/country country
Organizationhttp://wso2.org/claims/organization organizationName
IMhttp://wso2.org/claims/im im


5. Go to 'Service Providers > Add' and add a new Service Provider as 'Office365'















6.  Go to 'Inbound Authentication Configuration > SAML2 Web SSO Configuration > Configure' and configure SAML2 Settings as below.


AttributeValue
Issuerurn:federation:MicrosoftOnline
Assertion Consumer URLshttps://login.microsoftonline.com/login.srf
NameID formaturn:oasis:names:tc:SAML:2.0:nameid-format:persistent
Enable Response SigningTicked (True)
Enable Attribute ProfileTicked (True)
Include Attributes in the Response AlwaysTicked (True)


















7. Configure the attributes required by Azure AD

Service Provider ClaimLocal ClaimRequested Claim
IDPEmailhttp://wso2.org/claims/upnTicked (True)
NameIDhttp://wso2.org/claims/objectguidTicked (True)
















Make sure to set the configured 'NameID' claim as the 'Subject Claim URI'


Ok. So we have configured Office 365 as a Service Provider in WSO2 IS.
Now we need to have a user to test this and that user should be synced with Azure AD.

So I have a user as 'maltestuser1' in WSO2 IS and I have updated the user profile as below to have a UserPrincipalName.














Note:
ObjectUUID is a binary attribute. So in order to see the value properly in the management console we have to add the below user store property to user store configuration at /repository/conf/user-mgt.xml.

<UserStoreManager ... >
...
<Property name="java.naming.ldap.attributes.binary">objectGUID</Property>
...
</UserStoreManager>


So as I have mentioned in the very beginning, federation eliminates the need to send passwords between Active Directory and Office 365, yet, it still requires synchronizing the user accounts with Azure AD. We can perform this synchronization manually, adding Office 365 users that match each Active Directory user account or we can also automate the process with the Microsoft Directory Synchronization Tool

So here, we will manually sync this user with Azure AD. 

1. Connect with Windows Azure AD Powershell module executing step (1), (2) and (3) followed when configuring Azure AD.

2. Run below
New-MsolUser -UserPrincipalName maltestuser1@malithimal.com -ImmutableID jSxdNXJhcUSqepFsYn495Q== -LastName maltestuser1 -FirstName maltestuser1 -DisplayName "Malithi's Test User 1"













Note:
Make sure to use the value specified under objectGUID as -ImmutableId and the value specified under userPrincipalName,  as the UserPrincipalName.


If you log on to the Office 365 Admin Portal you will now see the newly added user there.
















Ok. So let's logon to Office 365 with the user created.


1. Go to https://login.microsoftonline.com/

2. Enter the username with federated domain (This is the value given for UserPrincipalName)
In my case it's maltestuser1@malithimal.com

3. You will be redirected to the login page of the WSO2 Identity Server

4. Give user credentials these and log on.

5. So you will be successfully logged on to Office 365.

6. If you signed out from Office 365, WSO2 IS will receive a SAML Logout Request and the user will be signed out from the IdP.

So that's it :)

[1] https://blogs.office.com/2014/05/13/choosing-a-sign-in-model-for-office-365/
[2] https://docs.wso2.com/display/IS500/Configuring+an+Active+Directory+User+Store