2 Replies Latest reply on Sep 27, 2010 4:12 PM by jonananas

    Re: Seam, SAML, JAAS: How do I map IDP to an application user?

    jonananas

      Thanks for your reply, and you're right, that  makes me comfortable, at least more so

       

      Some notes:

      I don't really need the actual user, I just need to know the organisation, and I am assuming that it's safe to use the IDP-id (set in external-authentication-config.xml).

      Also I'm probably implementing IDP-discovery fairly easily, either by mapping the incoming ip (most or all organisations use a proxy with a short ip-range) or by providing a custom entrypoint for each organisation.

       

       

       

      Your suggestion above was very insightful, to use JPA to lookup the user directly. That seems more straightforward than what I was about to do; to override the Credentials with a IDPCredentials and create a custom IDPToLocalUserLoginModule that would handle the mapping between IDP and user.

       

      However, I still have the problem that after finding my user using JPA I would like to create a corresponding principal to be used by identity. I tried to do this using identity.getSubject.addPrincipal(), but realized that identity.acceptExternallyAuthenticatedPrincipal(Principal principal) sets identity.principal to the SAMLPrincipal. I don't want that since the principal.name is base for further authorization. If that's a bad idea I guess I could work around it by creating a session-scoped user-object that would override the identity.principal. I would prefer not to though.

       

      I just tried creating my own org.picketlink.identity.seam.federation.internalAuthenticator by simply removing the identity.acceptExternallyAuthenticatedPrincipal(Principal principal) call, which seem to work with the InternalAuthenticator above. Is there a better way? If not using identity.login, how do I set the principal? (Or are you suggesting I shouldn't?)

       

       

      Again, thank you.

       

      -- Jonas

       

      {code}

      
      

      package com.metria.fsok.web.sso;

       

      import java.security.Principal;

      import java.util.LinkedList;

      import java.util.List;

       

      import javax.servlet.http.HttpServletRequest;

       

      import org.jboss.seam.annotations.AutoCreate;

      import org.jboss.seam.annotations.Import;

      import org.jboss.seam.annotations.In;

      import org.jboss.seam.annotations.Install;

      import org.jboss.seam.annotations.Logger;

      import org.jboss.seam.annotations.Name;

      import org.jboss.seam.log.Log;

      import org.jboss.seam.security.Identity;

      import org.picketlink.identity.seam.federation.configuration.ServiceProvider;

       

      /**

      * @author Marcel Kolsteren

      * @since Jan 30, 2010

      */

      @Name("org.picketlink.identity.seam.federation.internalAuthenticator")

      @AutoCreate

      @Install(precedence = Install.DEPLOYMENT + 10)

      @Import("org.picketlink.identity.seam.federation")

      public class PicketLinkInternalAuthenticator extends org.picketlink.identity.seam.federation.InternalAuthenticator {

      @In

      private Identity identity;

       

      @In

      private ServiceProvider serviceProvider;

       

      @Logger

      Log log;

       

      @Override

      public boolean authenticate(Principal principal, HttpServletRequest httpRequest) {

      List<String> roles = new LinkedList<String>();

      Boolean internallyAuthenticated = serviceProvider.getInternalAuthenticationMethod().invoke(principal, roles);

       

      log.debug("Authenticated= " + internallyAuthenticated + " as " + identity.getPrincipal().getName());

       

      if (internallyAuthenticated) {

                              // Removed to keep current principal

      // identity.acceptExternallyAuthenticatedPrincipal(principal);

      for (String role : roles) {

      identity.addRole(role);

      }

      }

      log.debug("Authenticated= " + internallyAuthenticated + " as " + identity.getPrincipal().getName());

       

      return internallyAuthenticated;

      }

      }

      {code}

      package com.metria.fsok.web.sso;
      import java.security.Principal;
      import java.util.LinkedList;
      import java.util.List;
      import javax.servlet.http.HttpServletRequest;
      import org.jboss.seam.annotations.AutoCreate;
      import org.jboss.seam.annotations.Import;
      import org.jboss.seam.annotations.In;
      import org.jboss.seam.annotations.Install;
      import org.jboss.seam.annotations.Logger;
      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.log.Log;
      import org.jboss.seam.security.Identity;
      import org.picketlink.identity.seam.federation.configuration.ServiceProvider;
      /**
      * @author Marcel Kolsteren
      * @since Jan 30, 2010
      */
      @Name("org.picketlink.identity.seam.federation.internalAuthenticator")
      @AutoCreate
      @Install(precedence = Install.DEPLOYMENT + 10)
      @Import("org.picketlink.identity.seam.federation")
      public class PicketLinkInternalAuthenticator extends org.picketlink.identity.seam.federation.InternalAuthenticator {
      @In
      private Identity identity;
      @In
      private ServiceProvider serviceProvider;
      @Logger
      Log log;
      @Override
      public boolean authenticate(Principal principal, HttpServletRequest httpRequest) {
      List<String> roles = new LinkedList<String>();
      Boolean internallyAuthenticated = serviceProvider.getInternalAuthenticationMethod().invoke(principal, roles);
      log.debug("Authenticated= " + internallyAuthenticated + " as " + identity.getPrincipal().getName());
      if (internallyAuthenticated) {
      // identity.acceptExternallyAuthenticatedPrincipal(principal);
      for (String role : roles) {
      identity.addRole(role);
      }
      }
      log.debug("Authenticated= " + internallyAuthenticated + " as " + identity.getPrincipal().getName());
      return internallyAuthenticated;
      }
      }

        • 1. Re: Seam, SAML, JAAS: How do I map IDP to an application user?
          marcelkolsteren

          Right, the identity provider discovery indeed gets straightforward when you use the IP-range detection or custom entry pages.

           

          There might be a more elegant method for putting your own principal in the identity. Recently, event support was added:

           

          https://jira.jboss.org/browse/PLFED-90

           

          The component internalAuthenticator now fires the event Identity.EVENT_LOGIN_SUCCESSFUL after the identity.acceptExternallyAuthenticatedPrincipal has been called. So if you listen to that event, you can do the JPA user lookup there, based on the contents of identity.getPrincipal(). After having constructed your own Principal from the SeamSamlPrincipal, you can call identity.acceptExternallyAuthenticatedPrincipal yourself. The result will be that the identity.getPrincipal() will be your own principal (which you desire), and that identity.getSubject().getPrincipals() will contain the SeamSamlPrincipal as well as your own Principal. That's a cleaner, less obtrusive way to get what you want. One remark: the mentioned event will also be fired if you do local JAAS based login, so you need to check whether the identity.getPrincipal is a SeamSamlPrincipal, before doing the JPA lookup.

          1 of 1 people found this helpful
          • 2. Re: Seam, SAML, JAAS: How do I map IDP to an application user?
            jonananas

            Again, thank's a lot for the quick reply!

            I had the weekend to think things over and thought I'd add some final remarks:

            Sorry if I'm being a bit thickheaded, but I think I might have been a bit too inclined to keep the original application the way it was in my last reply.

             

            I now think I should go with your original suggestion and change the authorization of the original application, keeping the SamlPrincipal as it is. It seems to be a cleaner and more robust solution, and the way you intended PicketLink to be used. Overriding PicketLink behaviour is not really robust I think, even if using the event as you suggested would clean that part up.

             

            Please correct me if I'm wrong but the principal should reflect it's original, and overriding it in application code the way I suggested just seem wrong to me now.

             

            Again, thank's a lot. You're replies have been most helpful and I feel I'm finally in safe waters