6 Replies Latest reply on Jul 20, 2018 8:23 AM by Sergiu Pienar

    WildFly Elytron security client programatic login

    Sergiu Pienar Expert

      I'm trying to migrate from picketbox to Elytron.

      In picketbox there used to be something of the form

       

      org.jboss.security.client.SecurityClient client = SecurityClientFactory.getSecurityClient();
      client.setSimple(User.SYSTEM_USER_NAME, User.SYSTEM_USER_PASSWORD);
      client.login();

       

      the allowed for a programatic login.

       

      The SecurityClient class was part of the jboss-security-spi-2.0.4.SP4.jar.

      Is there something similar that can be used with Elytron ?

        • 1. Re: WildFly Elytron security client programatic login
          Darran Lofthouse Master

          Are you executing this within a deployment associated with an Elyton security domain?

          • 2. Re: WildFly Elytron security client programatic login
            Sergiu Pienar Expert

            Yes. This is from within a jar (containing EJB's and startup classes) that is packed into an EAR. The jboss-app.xml of the EAR defines a security domain based on elytron. Found the below approach:               

             

            SecurityDomain currentSecurityDomain = SecurityDomain.getCurrent(); 
            Evidence evidence = new PasswordGuessEvidence(User.SYSTEM_USER_PASSWORD.toCharArray()); 
            try { 
            SecurityIdentity identity = currentSecurityDomain.authenticate(User.SYSTEM_USER_NAME, evidence); 
            } catch (RealmUnavailableException e) { // TODO write your own catch code! 
            } catch (SecurityException e) { // TODO write your own catch code! 
            }

            Is this the correct way of doing it ?

            • 3. Re: WildFly Elytron security client programatic login
              Darran Lofthouse Master

              That code sample is almost there, a big difference here is you know once you have a SecurityIdentity the authentication was successful - the old SecurityClient API didn't actually perform an authentication it just stored the credentials on a ThreadLocal for future use.

               

              Now that you have the SecurityIdentity from the authentication you need to use it for the ongoing request by using one of the various runAs methods it exposes: -

               

              SecurityIdentity (WildFly Elytron 1.4.0.Final API)

               

              The identity will then be automatically in place for the duration of the RunAs call and automatically cleaned up once the call returns.

              1 of 1 people found this helpful
              • 4. Re: WildFly Elytron security client programatic login
                Sergiu Pienar Expert

                Unfortunately this doesn't work when trying to authenticate:

                 

                ERROR [stderr] (Thread-291) org.wildfly.security.authz.AuthorizationFailureException: ELY01088: Attempting to run as "SYSTEM" authorization operation failed
                14:37:42,308 ERROR [stderr] (Thread-291)        at org.wildfly.security.auth.server.SecurityIdentity.createRunAsIdentity(SecurityIdentity.java:639)
                14:37:42,309 ERROR [stderr] (Thread-291)        at org.wildfly.security.auth.server.SecurityIdentity.createRunAsIdentity(SecurityIdentity.java:614)
                14:37:42,314 ERROR [stderr] (Thread-291)        at org.wildfly.security.auth.server.SecurityIdentity.createRunAsIdentity(SecurityIdentity.java:598)
                14:37:42,314 ERROR [stderr] (Thread-291)        at com.util.security.SecurityClient.doLogin(SecurityClient.java:85)

                 

                In the above snippet I added

                SecurityIdentity runAs = identity.createRunAsIdentity(User.SYSTEM_USER_NAME);

                 

                after calling authenticate on the security domain.

                 

                The Elytron domain that I'm using is linked to a jdbc-realm.

                • 5. Re: WildFly Elytron security client programatic login
                  Darran Lofthouse Master

                  That stack trace does not appear to match the code you posted?  The stack trace appears to be calling createRunAsIdentity instead - that method performs an authorization check to check if the current identity is authorized to run as the Principal requested.

                  • 6. Re: WildFly Elytron security client programatic login
                    Sergiu Pienar Expert

                    Here's a more complete image of what I'm trying to achieve:

                     

                    Old code:

                     

                    @Startup
                    @Singleton
                    @DependsOn({ "HibernateService", "CACDatasourceBean", "CACJobScheduleBean", "CACClientBean" })
                    public class ViSessionFactoryService
                    implements ViSessionFactoryServiceMBean {
                    
                    private static final Logger LOGGER = Logger.getLogger(SessionFactoryService.class);
                    
                    @Override
                    @PostConstruct
                    public void start() {
                    String startSessionFactories = PlatformConfig.getInstance().getClientSessionFactoriesStart();
                    
                    boolean start = new Boolean(startSessionFactories).booleanValue();
                    org.jboss.security.client.SecurityClient client = SecurityClientFactory.getSecurityClient();
                    client.setSimple(User.SYSTEM_USER_NAME, User.SYSTEM_USER_PASSWORD);
                    client.login();
                    
                    if (start) {
                    ViSessionFactoryService.LOGGER.info("start the client session factories, this can take while");
                    try {
                    CACDatasourceFactory.getLocal().recreateSessionFactories();
                    } catch (CACException e) {
                    ViSessionFactoryService.LOGGER.error(e);
                    } catch (NamingException e) {
                    ViSessionFactoryService.LOGGER.error(e);
                    }

                    .............

                     

                    The above would only work because when calling the CACDatasourceFactory.getLocal().recreateSessionFactories(); the SYSTEM use would have been already logged in and was allowed to call the recreateSessionFactories method, which has a @RolesAllowed annotation.

                     

                    The new code would be something like:

                     

                    @Startup
                    @Singleton
                    @DependsOn({ "HibernateService", "CACDatasourceBean", "CACJobScheduleBean", "CACClientBean" })
                    public class ViSessionFactoryService
                    implements ViSessionFactoryServiceMBean {
                    
                    private static final Logger LOGGER = Logger.getLogger(ViSessionFactoryService.class);
                    
                    @Override
                    @PostConstruct
                    public void start() {
                    String startSessionFactories = PlatformConfig.getInstance().getClientSessionFactoriesStart();
                    
                    boolean start = new Boolean(startSessionFactories).booleanValue();
                    
                    SecurityDomain currentSecurityDomain = SecurityDomain.getCurrent();
                    Evidence evidence = new PasswordGuessEvidence(User.SYSTEM_USER_PASSWORD.toCharArray());
                    currentSecurityDomain.authenticate(User.SYSTEM_USER_NAME, evidence);

                     

                    How can I use the SecurityIdentity to call my EJB's method (CACDatasourceBean) ?

                     

                    Later edit: If I'm doing identity.getRoles() I'm getting the correct roles for that user so this seems to be working correctly... what I now need would be to understand how to call the EJB's method from within the identities' runAs method.

                     

                    Would this do :

                     

                    identity.runAs(() -> {
                    try {
                    CACDatasourceFactory.getLocal().recreateSessionFactories();
                    } catch (CACException | NamingException e2) {
                    // TODO write your own catch code!
                    }
                    });

                     

                    ?

                    Later-later edit: It worked fine !

                     

                    Thanks.