10 Replies Latest reply: Oct 4, 2012 5:19 AM by kieselhorst RSS

Security propagation from remote EJB clients to AS7

rodakr Novice

Hi guys

 

Would it be possible to add support to remote EJB AS7 Client JAAS Security Context Propagation ?

Something like to get Subject from Call context on client Side and forward it to Server Side and let the Security Real to deside for authentication/authorization.

 

This wuold be realy helpful,  AS7 EJB remote Client without Security is pretty useless... and since beta1 Server Sider requres Authenticated users.. :-)

  • 1. Re: Security propagation from remote EJB clients to AS7
    rodakr Novice

    .. it would make sence require security from ejb remote clients as well

  • 2. Re: Security propagation from remote EJB clients to AS7
    jaikiran pai Master

    Yes, it's planned for upcoming releases. We did not want to hold up Beta1 release for this since we wanted to users to be able to start using the other EJB remoting bits that had been implemented.

  • 3. Re: Security propagation from remote EJB clients to AS7
    Darran Lofthouse Master

    Yes this is being implemented this week.

  • 4. Re: Security propagation from remote EJB clients to AS7
    rodakr Novice

    Great news!

     

    Thank you

  • 5. Re: Security propagation from remote EJB clients to AS7
    rodakr Novice

    Hi

     

    AS 7.1 CR1b1 is out. Is there some security bits, which can be used ?

     

    1)

    Can you provide client sample code using SASL Security ( for now PLAIN example would be enought ).

     

    ( or just add this example to https://docs.jboss.org/author/display/AS71/Developer+Guide#DeveloperGuide-EJBinvocationsfromaremoteclientusingJNDI )

     

    2)

    I looked in source code of  org.jboss.sasl.JBossSaslProvider.java  ( jboss-sasl-1.0.0.Beta9.jar )

     

    Ony SASL MECH I see here are:

     

    "ANONYMOUS"

    "PLAIN",

    "DIGEST-MD5",

    "JBOSS-LOCAL-USER"

     

    Could you also add "GSSAPI"  (  here how to from Darran Lofthouse http://community.jboss.org/wiki/SASLAndKerberos )

     

    Basically I would like to do this but with AS7.1:

     

    http://community.jboss.org/wiki/EJB3AuthenticationWithSPNEGO

     

    I tried to call remote ejb after sucessfull JAAS Login, but JAAS Login Context seams to not get propagatet to Server over Jboss Remote...

     

    Here how I tried ( the same Code but calling Web URL Secured with SPNEGO works, so KRB5 Java Setup is ok)  :

     

     

     

    import java.io.BufferedReader;

    import java.io.IOException;

    import java.io.InputStreamReader;

    import java.security.AccessController;

    import java.security.Principal;

    import java.security.PrivilegedExceptionAction;

    import java.security.Security;

    import java.util.Collections;

    import java.util.Hashtable;

    import java.util.Properties;

    import java.util.Set;

     

    import javax.naming.Context;

    import javax.naming.InitialContext;

    import javax.naming.NamingException;

    import javax.security.auth.Subject;

    import javax.security.auth.callback.Callback;

    import javax.security.auth.callback.CallbackHandler;

    import javax.security.auth.callback.NameCallback;

    import javax.security.auth.callback.PasswordCallback;

    import javax.security.auth.callback.TextInputCallback;

    import javax.security.auth.callback.TextOutputCallback;

    import javax.security.auth.callback.UnsupportedCallbackException;

    import javax.security.auth.login.LoginContext;

    import javax.security.sasl.Sasl;

    import javax.security.sasl.SaslClient;

    import javax.security.sasl.SaslException;

     

    import test.ejb3.TestServiceItf;

     

    public class TestServiceClient {

        static String JAAS_CONFIG_ENTRY = "com.sun.security.jgss.krb5.initiate";

        static BufferedReader br = new BufferedReader( new InputStreamReader (System.in));

     

     

     

        public static void main(String[] args) throws Exception {

     

     

            LoginContext lc = null;

            try {

                System.out.println("\n >> Enter Win user Name : ");

                String callbackUser  = br.readLine ();

                System.out.println("\n >> Enter Win User AD password : ");

     

                String callbackPwd  = br.readLine ();

     

                // jaas collback might be needed for ticket refresh...

                lc = new LoginContext(JAAS_CONFIG_ENTRY,new NamePasswordCallbackHandler2(callbackUser,callbackPwd ));

     

                lc.login();

                //and get a subject

                Subject mySubject = lc.getSubject();

                System.out.println(" *********??????????********>>>> subject: "+mySubject);

                Set<Principal> sp = mySubject.getPrincipals();

                if ( sp == null ) System.out.println(" 0 principals ");

                else {

                    System.out.println(+sp.size()+" principals");

                    for ( Principal p : sp ) {

                        System.out.println("principal name :"+p.getName());

                    }

                }

                // in case if not passed to java as property..

                System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");

                System.setProperty( "sun.security.krb5.debug", "true");

     

     

                PrivilegedExceptionAction<String> action = new GetAction( null, null  );

                //jaas call the service

                String aRet = (String)mySubject.doAs(mySubject, action);

     

                // successfuly called, read returned values

                System.out.println("successfully caled protected Method  : "+aRet);

            } catch (Exception e) {

                e.printStackTrace();

                System.exit(-1);

            }

        }

     

        /**

         *  dummy readLine Helper

         * @return

         */

     

        public static String readLine(String message)

            {

                String s = null;

                System.out.println(message);

                try {

                    InputStreamReader converter = new InputStreamReader(System.in);

                    BufferedReader in = new BufferedReader(converter);

                    s = in.readLine();

                } catch (Exception e) {

                    System.out.println("Error! Exception: "+e);

                } finally {

                    System.out.println("");

                }

                return s;

            }

     

     

     

     

     

     

    }

     

    class GetAction implements PrivilegedExceptionAction<String> {

     

        private String toke;

        private String user;

        private String testEjbItf="test.ejb3.TestServiceItf";

        // context.lookup("ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName);

        private String testEjbJndi="ejb:/sl-securityTestEjb3//TestServiceSLEJB3Bean!test.ejb3.TestServiceItf";

     

     

        public GetAction(String user , String token) {

            this.user = user;

            this.toke=token;

     

        }

     

        static {

     

            try {

                Sasl.createSaslClient(new String[]{"PLAIN"}, null, "remoting", "linux2", Collections.EMPTY_MAP, new NamePasswordCallbackHandler2("auser","apassword" ) );

            } catch (SaslException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

     

            }

     

        // make shure

        public String run() throws Exception {

     

            //Sasl.createSaslClient(new String[]{"GSSAPI"}, null, "remoting", "linux2", Collections.EMPTY_MAP, new NamePasswordCallbackHandler2("xxx","yyy" ) );

            //Sasl.createSaslClient(new String[]{"PLAIN"}, null, "remoting", "linux2", Collections.EMPTY_MAP, new NamePasswordCallbackHandler2("xxx","yyy" ) );

            javax.security.auth.Subject currentSubject = javax.security.auth.Subject.getSubject( AccessController.getContext());

            if ( currentSubject == null ) System.out.println(" our Action runs as Subject: null ");

            else System.out.println(" our Action runs as Subject: "+currentSubject.toString());

            Context ctx = getInitialContext();

            System.out.println("Initial Context created");

            System.out.println("lookup"+testEjbJndi+" @RolesAllowed({\"BackofficeRole\"})");

            Class itfClass = Thread.currentThread().getContextClassLoader().loadClass(testEjbItf);

            TestServiceItf testService = (TestServiceItf)  ctx.lookup(testEjbJndi);

            System.out.println("lookup testEjbJndi successful");

            System.out.println(" call unsecured Method permittAllMethod()");

            Subject asu = testService.permittAllMethod(" calling unsecured");

            System.out.println(" successfully called, received Subject: "+asu);

            System.out.println(" call secured Method with role "+testService.BACKOFFICE_ROLE);

            asu = testService.pwvAuthenticatorSecuredMethod(" calling secured");

            System.out.println(" successfully called, received Subject: "+asu);

            return "Test ok";

        }

     

        private static Context getInitialContext() throws NamingException {

             final Hashtable jndiProperties = new Hashtable();

             jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");

             jndiProperties.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");

             final Context context = new InitialContext(jndiProperties);

             return context;

            }

     

     

    }

     

    class NamePasswordCallbackHandler2 implements CallbackHandler

    {

        /**

         * The username to be provided when prompted.

         */

        private String username;

     

        /**

         * The password to be provided when prompted.

         */

        private String password;

     

        private String url;

     

        /**

         * Create a new NamePasswordCallbackHandler (required Cams default

         * constructor that is dynamically called by the authentication

         * server).

         * @param anURL

         * @param callbackPwd

         * @param callbackUser

         */

        public NamePasswordCallbackHandler2(String callbackUser, String callbackPwd)

        {

            this.username = callbackUser;

            this.password = callbackPwd;

        }

     

     

        /**

         * Set the username.

         *

         * @param username the username to be provided to a NameCallback.

         */

        public void setUsername(String username)

        {

            if (username == null)

            {

                this.username = "";

                return;

            }

     

            this.username = username;

        }

     

        /**

         * Set the password.

         *

         * @param password the password to be provided to a PasswordCallback.

         */

        public void setPassword(String password)

        {

            if (password == null)

            {

                this.password = "";

                return;

            }

     

            this.password = password;

        }

     

        public void handle(Callback[] callbacks)

        throws IOException, UnsupportedCallbackException

      {

        for(int i = 0; i < callbacks.length; i++)

        {

          if(callbacks[i] instanceof TextOutputCallback)

          {

            // Display the message according to the specified type

            TextOutputCallback toc = (TextOutputCallback)callbacks[i];

            switch(toc.getMessageType())

            {

            case TextOutputCallback.INFORMATION:

              log(toc.getMessage());

              break;

            case TextOutputCallback.ERROR:

              log("ERROR: " + toc.getMessage());

              break;

            case TextOutputCallback.WARNING:

              log("WARNING: " + toc.getMessage());

              break;

            default:

              throw new IOException("Unsupported message type: "+toc.getMessageType());

            }

          }

          else if(callbacks[i] instanceof NameCallback)

          {

            // If username not supplied on cmd line, prompt the user for the username.

            NameCallback nc = (NameCallback)callbacks[i];

            if (username == null || username.isEmpty()) {

              System.err.print(nc.getPrompt());

              System.err.flush();

              nc.setName((new BufferedReader(new InputStreamReader(System.in))).readLine());

            }

            else {

              log("username: "+username);

              nc.setName(username);

            }

          }

          else if(callbacks[i] instanceof PasswordCallback)

          {

            PasswordCallback pc = (PasswordCallback)callbacks[i];

     

            // If password not supplied on cmd line, prompt the user for the password.

            if (password == null || password.isEmpty()) {

              System.err.print(pc.getPrompt());

              System.err.flush();

     

              // Note: JAAS specifies that the password is a char[] rather than a String

              String tmpPassword = (new BufferedReader(new InputStreamReader(System.in))).readLine();

              int passLen = tmpPassword.length();

              char[] passwordArray = new char[passLen];

              for(int passIdx = 0; passIdx < passLen; passIdx++)

                passwordArray[passIdx] = tmpPassword.charAt(passIdx);

              pc.setPassword(passwordArray);

            }

            else {

              String tPass = new String();

              for(int p = 0; p < password.length(); p++)

                tPass += "*";

              log("password: "+tPass);

              pc.setPassword(password.toCharArray());

            }       

          }

          else if(callbacks[i] instanceof TextInputCallback)

          {

            // Prompt the user for the username

            TextInputCallback callback = (TextInputCallback)callbacks[i];

            System.err.print(callback.getPrompt());

            System.err.flush();

            callback.setText((new BufferedReader(new InputStreamReader(System.in))).readLine());

          }

          else

          {

            throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");

          }

        }

      }

     

      private void log(String str) { System.out.println(str); }

     

     

    Happy New Year

     

    Radek Rodak

  • 6. Re: Security propagation from remote EJB clients to AS7
    Jan Snelders Newbie

    Darran Lofthouse wrote:

     

    Yes this is being implemented this week.

    Does this mean remote authentication (Standalone Client --> Secured EJB) isn't working at all so far in JBoss 7.1 CR1? Also not for the documented authentication.login modules at https://docs.jboss.org/author/display/AS71/Authentication+Modules?

     

    If so, I would like to know which JIRA Issue(s) we can track in order to know when we can start trying/testing remote authentication.

     

    Thanks in advance for any help.

  • 7. Re: Security propagation from remote EJB clients to AS7
    Oleg Stepanov Newbie

    Please guys, any clues on this? How can I get a remote EJB client authenticated on AS 7? Whatever I've tried so far results in 'anonymous' principal being seen by EJBs on the server...

  • 8. Re: Security propagation from remote EJB clients to AS7
    Jan Snelders Newbie

    No clues here unfortunately.
    I'm trying the nighlty builds on a regular basis without success: https://community.jboss.org/thread/176963?tstart=0. Apparently I'm also looking at an anomymous principal?

     

    I don't see any other posts about remote EJB authentication problems answered so far.

  • 9. Re: Security propagation from remote EJB clients to AS7
    kieselhorst Newbie

    IMHO authentication works with the latest version, but the propagation of the JAAS LoginContext (ClientLoginModule) is still unsupported. This means if you call javax.ejb.EJBContext.getCallerPrincipal(), lookup javax.security.auth.Subject.container via javax.security.jacc.PolicyContext or similar you will get the default user specified in the client properties or on the remote-outbound-connection.

     

    I'd greatly appreciate any samples on how to implement remote client calls with different authentications in AS7.

  • 10. Re: Security propagation from remote EJB clients to AS7
    kieselhorst Newbie

    This thread also deals with this issue and contains a JIRA reference: https://issues.jboss.org/browse/AS7-5047