Wednesday, February 23, 2011

Single Log Out with OpenSAML

To logout an user from the SP an LogoutRequest is sent. The data needed about the user is the SessionIndex and NameID from the data recived at login. I my case in the Assertion in the Artifact Resolve Response.

//IPR Ergogroup AS
public static void doSynchronousLogout(final HttpSession sessionToLogout, final SAMLMetaData metaData) throws SOAPException, SecurityException, ValidationException, IllegalArgumentException, java.lang.SecurityException, IllegalAccessException, MarshallingException, SignatureException {
   NameID nameId = (NameID)sessionToLogout.getAttribute("SAMLNameID");
   String sessionIndex = (String)sessionToLogout.getAttribute("SAMLSessionIndex");

   Body body = buildSAMLObjectWithDefaultName(Body.class);

   LogoutRequest logoutRequest = genererateLogoutRequest(nameId, sessionIndex, metaData);
   signLogoutRequest(logoutRequest);
   body.getUnknownXMLObjects().add(logoutRequest);
   nameId.detach();
   Envelope envelope = buildSAMLObjectWithDefaultName(Envelope.class);
   envelope.setBody(body);

   SAMLUtil.logSAMLObject(envelope);

   BasicSOAPMessageContext soapContext = new BasicSOAPMessageContext();

   soapContext.setOutboundMessage(envelope);

   HttpClientBuilder clientBuilder = new HttpClientBuilder();

   HttpSOAPClient soapClient = new HttpSOAPClient(clientBuilder.buildClient(), new BasicParserPool());

   String sloServiceURL = null;
   for (SingleLogoutService sls : metaData.getIdpEntityDescriptor().getIDPSSODescriptor(SAMLConstants.SAML20P_NS).getSingleLogoutServices()) {
      if (sls.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI)) {
         sloServiceURL = sls.getLocation();
      }
   }
   soapClient.send(sloServiceURL, soapContext);

   Envelope soapResponse = (Envelope)soapContext.getInboundMessage();

   SAMLUtil.logSAMLObject(soapResponse);

   validateSLOResponse(soapResponse, logoutRequest.getID());
   verifySLOResponseSignature(soapResponse);
   processSLOResponse(soapResponse);
  
}

 
private static LogoutRequest genererateLogoutRequest(final NameID nameId, final String sessionIndex, final SAMLMetaData metaData) throws IllegalArgumentException, java.lang.SecurityException, IllegalAccessException {
   LogoutRequest logoutRequest = buildSAMLObjectWithDefaultName(LogoutRequest.class);

   logoutRequest.setID(SAMLUtil.getSecureRandomIdentifier());

   for (SingleLogoutService sls : metaData.getIdpEntityDescriptor().getIDPSSODescriptor(SAMLConstants.SAML20P_NS).getSingleLogoutServices()) {
      if (sls.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI)) {
         logoutRequest.setDestination(sls.getLocation());
      }
   }

   logoutRequest.setIssueInstant(new DateTime());

   Issuer issuer = buildSAMLObjectWithDefaultName(Issuer.class);
   issuer.setValue(EvoteProperties.getProperty("SPEntityId"));
   logoutRequest.setIssuer(issuer);

   SessionIndex sessionIndexElement = buildSAMLObjectWithDefaultName(SessionIndex.class);
 
   sessionIndexElement.setSessionIndex(sessionIndex);
   logoutRequest.getSessionIndexes().add(sessionIndexElement);

   logoutRequest.setNameID(nameId);
   return logoutRequest;
}

LogoutRequest sent:

my-alias











Sn7qX8Yf4Pcs6SLl4Yn0NyEx6P0=


cE3wgjeM+45uk/XVNQl+1NZKeRwRzFnJN9xaL/36vnXqu6eLBqs8eqdQ2a+yY9UkZz0gU1NrTqUMQgIANw1WfkL2a+sxQqqu2p4ggXKNwHiMWbyfPEUkxQM4wSwr3ECObjyVqrgPDA+4TiDyqPj2NBtZGo8WU3fvpOGQkQN19f0=


MIIBrzCCARigAwIBAgIETTWluTANBgkqhkiG9w0BAQUFADAcMRowGAYDVQQDExFzdGVyYXMuZXZh
bGcuZXJnbzAeFw0xMTAxMTgxNDM3NDVaFw0yMTAxMTUxNDM3NDVaMBwxGjAYBgNVBAMTEXN0ZXJh
cy5ldmFsZy5lcmdvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCy96UiOiuQcDQMVNorHKWC
u8lAqHCpdgL8SEKsBven1e9Bek5VSspQdyh8Q/t8hmISZq0oEEvtcbZivV1hGQKQIWjTU/utSxGl
ZDbPNweuxNH6JHiNzDSzbNiMkdBJcy/Szfdx8HGpbnpXrpU+ICNnQl5Ee2V48hlkcH7jwlCMzwID
AQABMA0GCSqGSIb3DQEBBQUAA4GBABxQKfXHtomdAlXd+umpCyUUOgcs5shu4HHXr9m48H+YPCXs
kLwqzDe49WWaX9h7cLClVsHviAccno52Pj7mQfjKgvg1J3JHhTLINTrbgZ1e7mNtiJ9Lez2awbIt
v7RKU+R2AyiU6wHsjPGN+CQuiT9lZNWQMOih1R+yHT04kkl8



puEYi51x6aylfgXbBJTLSTTxOqck
s2ce6f528812bbf545358af381cc864c575e9cb901


This is the resulting LogoutResponse in my case:

idp-alias











CDFFLlD2FX8fjlPJLKpJZRusnx0=



cKgVEfLR48x7urpH+TV+V1gHYnVhc/ErkMhwp17rjAMfjHKHk0EPgH2+aOV7Z83udbfr0RPKF5Zd
Mg0zq1KIm29RsqUsUYNKKNiYPlEkBIoHPcc2AhftpA/VNRjea7q2W9+y6XV2YWjzGnArrfflv1KM
1t5C89Vz/VB0jQdJvMU=






Request is done successfully



14 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Hi,
    Thanks for sharing this nice information. Can you please suggest is there any way to configure single log out in openam. I currently integrate facebook/Google using oauth2.0 but single logout is not working with them. Have any idea about it .
    Thanks

    ReplyDelete
    Replies
    1. I'm sorry, I have never done any work with oauth 2.0 so I can answer that

      Delete
  3. This comment has been removed by the author.

    ReplyDelete
  4. Hi

    I have developed an application as SP using OpenAM fedlet. Single Sign on is working fine and Single Sign out also happening from Idp (Idp is SimpleSAMLPHP).

    But Im facing one issue, when I have connected two SP's and do single sign out its successfully signed out from Idp but the local session for second SP still exists and able to access the site even after logged out of Idp.

    I assume that for each request in SP should validate whether valid session exists in Idp, but I'm unable to find how to do with OpenAM fedlet.

    Can you please give me some valuable input to signout local session of SP when signout is happened from any other SP.

    Regards
    Arjun S

    ReplyDelete
    Replies
    1. A normal senario is that the SP your logging out from, redirects the user to the IDP. The IDP ivalidates the IDP session and sends out a SLO request over SOAP to the other SPs.
      When an SP validates a request it does not check the IDP session, but only its own local session.

      It sounds like there is a problem when the IDP tries to send SLO over SOAP to the other SP

      Delete
  5. Yes you are correct, The IDP ivalidates the IDP session and sends out a SLO request over SOAP to the other SPs.
    In my case the issue happend because of some minor configuration problem.

    Thanks a lot!

    ReplyDelete
  6. Your code makes use of a buildSAMLObjectWithDefaultName method which doesn't seem to be provided.

    ReplyDelete
    Replies
    1. Its a utility method I wrote, here http://mylifewithjava.blogspot.no/2011/04/convenience-methods-for-opensaml.html

      Delete
  7. Hi..i try to implement this in my SP but with the current openSAML Version some classes (e.g. BasicSOAPMessageContext) are no longer available in the code.
    So i tried to send the LogoutRequest with the HTTPRedirectDeflateEncoder but unfortunately i get an HTTP Error 400 (LogoutRequest. null) - The request sent by the client was syntactically incorrect.
    In my backend (openAM) i get an Nullpointer Exception at com.sun.identity.saml2.common.SAML2Utils.getRemoteServiceURL(SAML2Utils.java:1570)
    I really dont know what i have done wrong :-(

    ReplyDelete
  8. Hello Stefan how are you?
    Using OpenSaml v3.2 I am having trouble when receiving a Logout Request from other SP, the Logout comes in a redirect with the signature as a parameter and I have to verify it somehow, the verification I knew was SignatureValidator.validate, which receives a Signature object as a parameter, but I have no clue in how to convert what I get in that object.
    Unfortunately I couldn't find any examples online verifies signatures in redirects.

    Googling I found that a possible solution is use SAML2HTTPRedirectDeflateSignatureSecurityHandler but there aren't any examples to check how to implement it.

    1) Do you have any examples of verifying signatures when it is a redirect?
    2) Should I find a way to convert the Signature parameter into a Signature object and use the signature validator? Where should I look to solve it?
    3) If answer 2 is no: is the securityhandler that I mentioned a way of solving this? Do you have something to guide me in how to implement it?

    Sorry for asking so much,

    Thank you in advance!


    Francisco Perdomo

    ReplyDelete
    Replies
    1. Ok, I have not worked with decoding redirects. i quite sure that you should be using SAML2HTTPRedirectDeflateDecoder and then define a SAML message context to validate the signature. I have a post on signing and sending a rediect so you can probably take some inspiration from there. Good luck
      http://blog.samlsecurity.com/2016/08/signing-and-sending-authnrequests-in.html

      Delete