First, lets understand the single logout work flow that is initiated by SP
Please note here, i am using following diagram (This is copied from specification). Here IDP is referred to SAML2 SSO Identity Provider and SP is referred to SAML2 SSO Service Provider
1. LogoutRequest issued by SP to IDP
2. IDP determines authenticated SPs for given user session. If there are no SPs, other than the SP who sends logout request, the profile proceeds with step 5.
Otherwise, steps 3 and 4 are repeated for each SP
3. LogoutRequest issued by IDP to SP
4. SP issues LogoutResponse to IDP
5. IDP issues LogoutResponse to SP who sends logout request
Let see what is in these requests and response messages
LogoutRequest is extend from RequestAbstractType.
There are some attributes that must be in the RequestAbstractType element
1. ID – An identifier for the request. This must be unique. Basically a random number.
2. Version – Indicate SAML version
3. IssueInstant – Time instant of issue of the request. The time value is encoded in UTC
Apart from that, One of following is a required attribute for LogoutRequest request…
4. BaseID or NameID or EncryptedID
This indicate the principle (user identifier). Basically name that is known to both IDP and SP.
Also there are few optional elements
5. NotOnOrAfter – The time at which the request expires in UTC
6. Reason – reason for the logout, in the form of a URI reference.
There are two standard reasons
urn:oasis:names:tc:SAML:2.0:logout:user – user terminates session and initiates logout
urn:oasis:names:tc:SAML:2.0:logout:admin – admin terminates session and initiates logout
7. SessionIndex – This is the session identifier that is used to identify the user session with both IDP and SP for given user.
LogoutRepsonse is extend from StatusResponseType. There are some attributes that must be in the StatusResponseType element. i.e. ID, Version and IssueInstant which is same as in RequestAbstractType. There is element called Status element that is required. Status element would contain the status code corresponding to the request.
Lets take sample scenarios to explain how IDP and SPs handle the single logout scenario. Here we assume that there are IDP and two SPs; i.e called as SP1 and SP2
Please note all request response messages must be signed or otherwise authenticated and integrity protected by the under line protocol.
Step 1. User is trying access SP1 and user has no authenticated session, therefore user is redirected to IDP
Step 2. IDP has no authenticated session for user. Therefore user would be authenticated with user store.
Step 3. After successful authentication;
IDP creates SAML token based on user and user’s attributes.
IDP creates a session for user and IDP that is normally called as SSO session. This SSO session is uniquely identified by session Id (which would be sent in assertion as SessionIndex) and the user. SSO session would contain details about the SP1. Mostly SSO session would be persisted by the IDP
Step 4. User is redirected to SP1 with SAML Response.
Here we are interesting in followings element in the SAML Assertion
a) Subject – This is used to identify the authenticated User. Mostly NameID is used for this. Basically this is user name of the authenticated user.
b) AuthnStatement – This provides some statement describing how subject has been authenticated with IDP.
<saml2:authnstatement authninstant="2013-06-28T11:49:29.879Z" sessionindex="26C0530CBEA1DCF404C95B029D6A64AF"> <saml2:authncontext> <saml2:authncontextclassref>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml2:authncontextclassref> </saml2:authncontext> </saml2:authnstatement>
Here user has been authenticated by providing password. Also it specifies the session identifier of the session that has been created with IDP and user, using SessionIndex attribute
Step 5. If SAML response is valid, SP1 would create session for user and SP1. Then, created session would be map with the received SessionIndex value.
Step 6. Now same user is trying to access SP2. and user has no authenticated session, therefore user is redirected to IDP
Step 7. IDP has an authenticated SSO session for user and IDP. Therefore SAML token is created. SSO session would be updated with SP2 details.
Step 8. User is redirected to SP2 with SAML Response. SAML Assertion would be same as we discussed in step4
Step 9. If SAML response is valid, SP2 would create session with user and SP2. Then, created session would be map with the received SessionIndex.
Now lets see single logout scenario….
Step 10. User is trying to logout from SP1. Then LogoutRequest is sent to IDP from SP1.
Lets see what should be in this request.
Basically, SP1 need to provided the SSO session that is associated with IDP and the User.
SP1 could finds out, received SessionIndex id and NameID for the user. As these details has been kept in SP’s session
Then creates LogoutRequest based on that..
Sample LogoutRequest would be as follows
<saml2p:logoutrequest id="flkjhgfehcfjkjjmabgkcmlcnalbcillibfeeeag" issueinstant="2013-06-28T11:51:06.024Z" notonorafter="2013-06-28T11:56:06.024Z" reason="urn:oasis:names:tc:SAML:2.0:logout:user" version="2.0" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"> <saml2:nameid format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">admin</saml2:nameid> <saml2p:sessionindex>26C0530CBEA1DCF404C95B029D6A64AF</saml2p:sessionindex> </saml2p:logoutrequest>
Step 11. IDP validates LogoutRequest and If valid, it finds out the associate SSO session for given SessionIndex and that also is matched with NameID
Step 12. IDP identifies the SPs that have been authenticated for the user from the SSO session. Then IDP sends LogoutRequest to each SP (other than SP1) with corresponding SessionIndex and NameID
Therefore same LogoutRequest that is discussed in step10 would be sent to SP2 from IDP
Step 13. SP2 validates and processes LogoutRequest. SP2 invalidates the session that is associated with SessionIndex and is matched with NameID
Step 14. SP2 sends LogoutResponse to IDP with the status of success
<saml2p:status> <saml2p:statuscode value="urn:oasis:names:tc:SAML:2.0:status:Success" /> </saml2p:status>
Step 15. IDP validates the LogoutResponse and tracks on received status
Step 16. Finally IDP invalidates SSO session that is associated with SessionIndex and is matched with NameID
Step 17. IDP sends LogoutResponse to SP1
If all are success LogoutResponse would be with status code
If SP2 sends an error status in LogoutResponse, then with status code
If any other error, it would be with error status code.
However, Step12, Step13, Step 14 and Step15 are normally happening in separate threads. It means once, IDP receives a logout request from SP1, IDP would invalidate the SSO session that is associated with SessionIndex and is matched with NameID. Then IDP sends the LogoutResponse to SP1. But in separate flow IDP would execute the Step12, Step13, Step 14 and Step15 steps.
I guess, this would help you to understand how single logout must be implemented. Basically , if i simplify, this in code level…
In IDP implementation, There must be a some kind of SSO session (session between User and IDP) persistence method. It can be a simple in-memory Map; with SessionIndex (session Id) as the key and session as the value of the Map. Please find sample implementation from here
In SP implementation. There must be a some kind of user session (session between User and SP) persistence method. It can be a simple in-memory Map; with SessionIndex (received SessionIndex in Assertion) as the key and user session as the value of the Map. Please find sample implementation from here
With WSO2 Identity Server release, you could find sample web apps that demonstrate single logout functions. Please refer this