3 Replies Latest reply on Jan 14, 2014 10:37 AM by jorge ciombalo

    Programmatic IDP login with redirect to SP

    jorge ciombalo Newbie

      Hi all

       

      I have a specific situation where I have a set of applications (ears/wars) in the SAAS architecture, where for each client of these apps we have a database, that we call as domain, using the "tenant per database" approach. I also have a central database where the users/credentials are stored, along with the relation of the domains that each user can access, but the collection of roles need to be stored in each tenant. So we can achieve the following scenario:

       

      The "User 1" can access the domain "Customer A" and inside it he has the roles "Role X", "Role Y" & "Role Z".

      The "User 1" can access the domain "Customer B" and inside it he has only the roles "Role X" and "Role W".

      The "User 2" can access only the domain "Customer B" and inside it he has his own set of roles.

      And so on...

       

      For it to be possible, the first step was to encapsulate all this complexity in a IDP and simplify the job for the SPs. Inside the IDP, we had to blow up the login process in the following steps:

      1. Request and validate the user credentials; (OK)

      2. Load the list of the domains that this user can access; (OK)

      3. Show the domains in a drop down menu for him to pick one; (OK)

      4. Once choosen, load the roles he has in that domain; (OK)

      5. Redirect the user to the original Request (NOK);

       

      As you can see, after a bit of (should I say painfull) research I got achieved the most part of the job. For that, I had to write my own LoginModule and to perform a programmatic authentication against the j_security_check from my LoginController managed bean using HttpServletRequest.login(username, password).

       

      And everything is working fine (almost):

      The first time I access my SP I'm redirected to the login page from IDP and the authentication from the managed bean is working as I expected. The only problem is that I'm not able to redirect the user to the original request, holding the user inside my IDP, thats because I dont know how to programmatic redirect the user to the original request after I perform the authentication in the MBean.

       

      I think the SAML is working fine because if I rewrite the URL to the SP again then I can access the protected resources. My only need is to catch original URL in the managed bean to redirect the user to the SP after the successfull authentication. It would be important also if I could catch the URI parameters, cause sometimes I want send some generated URLs to the user by email, like:

       

      "http://serviceProvicer-Abc:1234/foo/bar.jsf?domain=abc&invoiceId=09876"

       

      In that case, I have parameters that I want to use in the IDP (domain) and parameters that belongs to the Service Provider (invoiceId), that should be present in the redirection.

       

      Does anyone knows how to achieve this last part of the job?

       

      Regards and Happy new year for everyone.

        • 1. Re: Programmatic IDP login with redirect to SP
          jorge ciombalo Newbie

          Hi again!

           

          I was looking the logs and after the call to the method HttpServletRequest.login(username, password)  the valve is throwing a exception, think this is causing my IDP to not redirect back to the SP. This is the exception printed in the console:

          17:32:37,437 ERROR [org.picketlink.identity.federation] (http-localhost-127.0.0.1-8080-4) PLFED000253: Exception in processing request: ParsingException [location=null]org.picketlink.identity.federation.core.exceptions.ParsingException: PLFED000074: Parsing Error.

            at org.picketlink.identity.federation.PicketLinkLoggerImpl.parserError(PicketLinkLoggerImpl.java:302) [picketlink-jbas7-2.1.8.Final.jar:2.1.8.Final]

            at org.picketlink.identity.federation.core.saml.v2.util.DocumentUtil.getDocument(DocumentUtil.java:208) [picketlink-core-2.1.8.Final.jar:2.1.8.Final]

            at org.picketlink.identity.federation.api.saml.v2.request.SAML2Request.getSAML2ObjectFromStream(SAML2Request.java:163) [picketlink-core-2.1.8.Final.jar:2.1.8.Final]

            at org.picketlink.identity.federation.web.util.IDPWebRequestUtil.getSAMLDocumentHolder(IDPWebRequestUtil.java:125) [picketlink-core-2.1.8.Final.jar:2.1.8.Final]

            at org.picketlink.identity.federation.bindings.tomcat.idp.AbstractIDPValve.processSAMLRequestMessage(AbstractIDPValve.java:656) [picketlink-jbas7-2.1.8.Final.jar:2.1.8.Final]

            at org.picketlink.identity.federation.bindings.tomcat.idp.AbstractIDPValve.handleSAMLMessage(AbstractIDPValve.java:329) [picketlink-jbas7-2.1.8.Final.jar:2.1.8.Final]

            at org.picketlink.identity.federation.bindings.tomcat.idp.AbstractIDPValve.invoke(AbstractIDPValve.java:284) [picketlink-jbas7-2.1.8.Final.jar:2.1.8.Final]

            at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153) [jboss-as-web-7.1.1.Final.jar:7.1.1.Final]

            at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [jbossweb-7.0.13.Final.jar:]

            at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.13.Final.jar:]

            at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.13.Final.jar:]

            at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) [jbossweb-7.0.13.Final.jar:]

            at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.13.Final.jar:]

            at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) [jbossweb-7.0.13.Final.jar:]

            at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.13.Final.jar:]

            at java.lang.Thread.run(Thread.java:744) [rt.jar:1.7.0_45]

          Caused by: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Invalid byte 1 of 1-byte UTF-8 sequence.

            at org.apache.xerces.parsers.DOMParser.parse(DOMParser.java:244)

            at org.apache.xerces.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:285)

            at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:121) [rt.jar:1.7.0_45]

            at org.picketlink.identity.federation.core.saml.v2.util.DocumentUtil.getDocument(DocumentUtil.java:204) [picketlink-core-2.1.8.Final.jar:2.1.8.Final]

            ... 14 more

          Caused by: org.apache.xerces.impl.io.MalformedByteSequenceException: Invalid byte 1 of 1-byte UTF-8 sequence.

            at org.apache.xerces.impl.io.UTF8Reader.invalidByte(UTF8Reader.java:694)

            at org.apache.xerces.impl.io.UTF8Reader.read(UTF8Reader.java:567)

            at org.apache.xerces.impl.XMLEntityScanner.load(XMLEntityScanner.java:1752)

            at org.apache.xerces.impl.XMLEntityScanner.skipString(XMLEntityScanner.java:1440)

            at org.apache.xerces.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:150)

            at org.apache.xerces.parsers.XML11Configuration.parse(XML11Configuration.java:802)

            at org.apache.xerces.parsers.XML11Configuration.parse(XML11Configuration.java:768)

            at org.apache.xerces.parsers.XMLParser.parse(XMLParser.java:108)

            at org.apache.xerces.parsers.DOMParser.parse(DOMParser.java:230)

            ... 17 more

           

          I've debugged my IDP during the login process and (with the "inspect" function of the eclipse IDE) the content of the note SAMLRequest inside the internal session is always there. The only difference if compared to the original SAMLRequest (extracted from the URL) is that in the session parameter the special chars are not treated.

           

          I'm using JBoss 7.1.1 with the following PL jars:

          picketlink-as7-extension-1.0.1.Final

          picketlink-bindings-2.0.2.Final

          picketlink-bindings-jboss-2.0.2.Final

          picketlink-core-2.1.8.Final

          picketlink-fed-2.0.2.Final

          picketlink-jbas7-2.1.8.Final

          • 2. Re: Programmatic IDP login with redirect to SP
            Pedro Igor Master

            Hi,

             

                Are you authenticating your users twice ? Asking because I think the IDP Valve will always kick in (and perform the authentication) before reaching your LoginController.

            • 3. Re: Programmatic IDP login with redirect to SP
              jorge ciombalo Newbie

              Hi Pedro,

               

              The problem is that I had configured  my SP to use the Redirect method, but while my IDP was performing the validations he was using the method POST. When the Valve tried to handle the SAML request after the login it have tried to parse the SAML message using the PostBindingUtil instead of RedirectBindingUtil.

               

              The workaround I have used was to setup my SP with the POST method. Another solution I thought was to extend the valve, adding the original request method in the internal session, and retrieving it while parsing the SAML message, but have hadn't time to implement it.

               

              Now I'm dealing with another questions:

              The first one is to send back to the SPs the domain that the user have choosen while performing the login, along with some aditional informations about it. I don't want these informations available in the session, but in a Thread local instead, so I think I'll have to write my own Handler to perform it instead of using SAML2AttributeHandler.

               

              The second question is that in some cases I want that the SP previously inform the IDP the domain to authenticate against. Thats because sometimes I have to send emails to the users with links to perform actions. Those links must have the domain that triggered the email and the user must login exactly in that domain, to continue with the original action after the login. I haven't found any handler like that so far I have searched, so I think I'll have to write another one to perform it.

               

              Let me know if you have any suggetions about these questions.

               

              Regards,

              Jorge