Uploaded image for project: 'OpenAM'
  1. OpenAM
  2. OPENAM-14465

SAML2 Artifact binding fails on multi-instance / multiserver IDP setup with SAML2 Failover on

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 13.5.1, 13.5.2, 14.1.1, 5.5.1, 6.0.0, 6.0.0.1, 6.0.0.2, 6.0.0.3, 6.0.0.4, 6.0.0.5, 6.0.0.6, 6.5.0, 6.5.0.1
    • Fix Version/s: 13.5.3, 6.5.1, 6.0.1, 7.0.0, 5.5.2
    • Component/s: SAML
    • Labels:
    • Environment:
      Must enable IDP SAML2 Failover to be true.

      Note that this is NOT really solved by AM stickiness as the request affinity is due to the SP contacting the IDP and SP end have no access to stickiness cookie of AM.
    • Needs backport:
      Yes
    • Support Ticket IDs:
    • Verified Version/s:
    • Needs QA verification:
      Yes
    • Functional tests:
      No
    • Are the reproduction steps defined?:
      Yes and I used the same an in the description

      Description

      Bug description

      When having multiple IDP with SAML2 Failover and using Artifact binding where first IDP that request for the initial SAMLArt (Artifact) is send to the SP and then the SP does the Artifact resolve to another load balance IDP, then it is possible that because the first IDP and Artifact responding IDP is not the same, the following exception will happen

      HTTP Status 500 - Couldn't obtain ArtifactResponse because of error in SOAP communication.
      type Status report
      
      message Couldn't obtain ArtifactResponse because of error in SOAP communication.
      
      description The server encountered an internal error that prevented it from fulfilling this request.
      

      and in the Federation logs:

      5.5.x
      libSAML2:02/21/2019 03:48:04:527 PM SGT: Thread[http-nio-8080-exec-8,5,main]: Tr
      ansactionId[e0395a56-e271-4afa-bd70-8edb2f29ce3b-511]
      ERROR: IDPArtifactResolution.doArtifactResolution: SAML2 error
      com.sun.identity.saml2.common.SAML2Exception: Cannot modify the object as the ob
      ject is immutable.
              at com.sun.identity.saml2.protocol.impl.ResponseImpl.setAssertion(Respon
      seImpl.java:346)
              at com.sun.identity.saml2.profile.IDPSSOUtil.signAndEncryptResponseCompo
      nents(IDPSSOUtil.java:2579)
              at com.sun.identity.saml2.profile.IDPArtifactResolution.onMessage(IDPArt
      ifactResolution.java:440)
              at com.sun.identity.saml2.profile.IDPArtifactResolution.doArtifactResolu
      tion(IDPArtifactResolution.java:159)
              at com.sun.identity.saml2.servlet.IDPArtifactResolutionServiceSOAP.doPos
      t(IDPArtifactResolutionServiceSOAP.java:53)
              at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
              at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
              at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(Appl
      icationFilterChain.java:292)
      

      How to reproduce the issue

      1. Setup Federation for SP and IDP. You can create 2 load balance IDP if needed.
      2. Enable SAML2 Fail-over to be true for the IDP
      3. Perform a standard SP SSO (hopefully with Artifact binding)

      It is important that the request from first IDP later goes to the 2nd IDP. There is hack you could even use DNS on SP host to target a another AM instance. (if you do not want to do any LB)

      Note that this is NOT really solved by AM stickiness as the request affinity is due to the SP contacting the IDP and SP end have no access to stickiness cookie of AM. So stickiness from Browser to AM is not the issue and hence merely asking for stickiness would not apply here (as it is a external SP issue).

      Alternate developer testcase (for single IDP machine test)

      • In IDPArtifactResolution line 315, always drop the local cache so that it uses the CTS (this may be quicker to test things). Eg: like simulating a IDP restart.

      Logic of the flow
      This is best described in https://www.oasis-open.org/committees/download.php/27819/sstc-saml-tech-overview-2.0-cd-02.pdf in page 28 for the Artifact binding

      AM specific
      In AM, when HTTP-Artifact lands on this AM2, there is code to try to see where the origin of this Artifact origin so that it know which originating AM has created this is. So internally it may do a cross-talk from this AM2 to the other one AM1. So if this portion work, this above CTS access may not happen [hence this cannot create mutable should not be seen) (as long as the origin AM has this in their local cache). So if this error happens it may mean also cross-talk is not working/failed. This may be perfectly fine for autonomous (where all the AM server's are having the same serverId) or say AM1 is restarted. However one may want to check that (for crosstalk for this to work):

      • AM1 <-> AM2 is routable (DNS-wise for the registered Artifact Resolution URL)
      • The AM1 & AM2 installed URL are valid/resolvable within these AM so that AM2 can contact AM1 using these URL
      • That the AM1/2 internal serverID are 2 digits (not changed somehow)
      • AM1 <-> AM2 communication issue (eg: HTTPS cert not trusted between AM1/2 due to crosstalk)
      Expected behaviour
      Artifact binding works w/o the exception
      
      Current behaviour
      Artifact binding fails if the Artifact resolve ends up on another AM IDP instance from where the local cache of the initial response is.
      

      Work around

      Stickiness will not solve this. But if there is an option avoid using Artifact binding and configure to use Redirect/POST binding.

      Code analysis

      When all the SAML2 object is created from XML, they are created as immutable. So if the object needs to be changed it cannot be recreated from XML

      IDPSSOUtil.java
      2136                    SAML2FailoverUtils.saveSAML2TokenWithoutSecondaryKey(artStr,
      2137                            res.toXMLString(true, true), expireTime);
      

      Here the response is serialized as XML string and later that is why

              at com.sun.identity.saml2.protocol.impl.ResponseImpl.setAssertion(Respon
      seImpl.java:346)
              at com.sun.identity.saml2.profile.IDPSSOUtil.signAndEncryptResponseCompo
      nents(IDPSSOUtil.java:2579)
      

      The issue is that

      IDPArtifactResolution.java
          public static SOAPMessage onMessage(SOAPMessage message,
                                              HttpServletRequest request,
                                              HttpServletResponse response,
                                              String realm,
                                              String idpEntityID)
      .....
                          String tmp = (String) SAML2FailoverUtils.retrieveSAML2Token(artStr);
                          res = ProtocolFactory.getInstance().createResponse(tmp);
      ...
      

      So the response is immutable.

      Possible fix, just save the response. As response is IDP generated (hopefully not external), we can just save this to CTS and reconstruct to directly. This will probably need OPENAM-12770 to work as we will rely on this to work.

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                chee-weng.chea C-Weng C
                Reporter:
                chee-weng.chea C-Weng C
              • Votes:
                1 Vote for this issue
                Watchers:
                7 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: