7 Replies Latest reply on Mar 2, 2010 6:57 PM by deanhiller

    one data source with multiple database users

    diemon

      Hello
      I have problem with configuring JBoss 4.2.1+Seam 2.0.1+Oracle 10 to use one data source with multiple users. I have configured *-ds.xml file with

      <datasources>
      <local-tx-datasource>
       <jndi-name>myDatasource</jndi-name>
       <connection-url>jdbc:oracle:thin:@server:1521:db</connection-url>
       <driver-class>oracle.jdbc.driver.OracleDriver</driver-class>
       <security-domain>MyRealm</security-domain>
      </local-tx-datasource>
      </datasources>
      

      and added to login-config.xml:
      <authentication>
       <login-module code = "my.login.module.MyLoginModule" flag = "required">
       <module-option name="sysUserName">user</module-option>
       <module-option name="sysPassword">pass</module-option>
       <module-option name="managedConnectionFactoryName">jboss.jca:service=LocalTxCM,name=myDatasource</module-option>
       </login-module>
      </authentication>
      

      my login module code is as follows:
      import java.security.AccessController;
      import java.security.Principal;
      import java.security.PrivilegedAction;
      import java.security.acl.Group;
      import java.util.Map;
      
      import javax.management.MBeanServer;
      import javax.management.MBeanServerFactory;
      import javax.management.MalformedObjectNameException;
      import javax.management.ObjectName;
      import javax.resource.spi.ManagedConnectionFactory;
      import javax.resource.spi.security.PasswordCredential;
      import javax.security.auth.Subject;
      import javax.security.auth.callback.CallbackHandler;
      import javax.security.auth.login.LoginException;
      
      import org.jboss.mx.util.MBeanServerLocator;
      import org.jboss.seam.security.Identity;
      import org.jboss.security.SecurityAssociation;
      import org.jboss.security.SimplePrincipal;
      import org.jboss.security.auth.spi.AbstractServerLoginModule;
      
      public class MyLoginModule extends AbstractServerLoginModule {
      
       private static final org.apache.log4j.Logger log = org.apache.log4j.Logger
       .getLogger(my.login.module.MyLoginModule.class);
      
       /* used at jboss startup */
       private static boolean sysMode = true;
      
       private String sysUserName;
       private String sysPassword;
       private String userName;
       private String password;
      
       private MBeanServer server;
       private ObjectName managedConnectionFactoryName;
       private ManagedConnectionFactory mcf;
      
       public SkorLoginModule() {}
      
       @Override
       public void initialize(Subject subject, CallbackHandler handler, Map sharedState, Map options) {
      
       super.initialize(subject, callbackHandler, sharedState, options);
      
       String name = (String) options.get("managedConnectionFactoryName");
       try {
       managedConnectionFactoryName = new ObjectName(name);
       } catch (MalformedObjectNameException mone) {
       throw new IllegalArgumentException("Malformed ObjectName: " + name);
       }
      
       sysUserName = (String)options.get("sysUserName");
       if (sysUserName == null) {
       throw new IllegalArgumentException("Must supply a system user name!");
       }
       userName = (String)options.get("sysUserName");
      
       sysPassword = (String)options.get("sysPassword");
       if (sysPassword == null) {
       throw new IllegalArgumentException("Must supply a system user password!");
       }
       password = (String)options.get("sysPassword");
      
       server = MBeanServerLocator.locateJBoss();
       getMcf();
       }
      
       @Override
       public boolean login() throws LoginException {
      
       setUserNameAndPassword();
       log.info("login(): userName=" + userName + ", sysMode=" + sysMode);
      
       Principal principal = new SimplePrincipal(userName);
      
       PasswordCredential credential = new
       PasswordCredential(userName, password.toCharArray());
       credential.setManagedConnectionFactory(getMcf());
      
       subject.getPrincipals().add(principal);
       subject.getPrivateCredentials().add(credential);
      
       super.loginOk = true;
       return true;
       }
      
       protected ManagedConnectionFactory getMcf() {
      
       if (mcf == null) {
       try {
       mcf = (ManagedConnectionFactory)server.getAttribute(managedConnectionFactoryName, "ManagedConnectionFactory");
       } catch (Exception e) {
       throw new IllegalArgumentException("Managed Connection Factory not found: " + managedConnectionFactoryName);
       }
       }
       return mcf;
       }
      
       @Override
       protected Principal getIdentity() {
      
       setUserNameAndPassword();
       log.info("getIdentity(): userName=" + userName + ", sysMode=" + sysMode);
      
       return new SimplePrincipal(userName);
       }
      
       @Override
       protected Group[] getRoleSets() throws LoginException {
       return new Group[] {};
       }
      
       private void setUserNameAndPassword() {
       if (sysMode) {
       userName = sysUserName;
       password = sysPassword;
       } else {
       String[] ss = Identity.instance().getUsername().split(" ");
       String s = ss[0].substring(0, 1).toLowerCase();
       s += ss[1].toLowerCase();
       userName = s;
       password = s;
       }
       }
      }
      


      The problem is that when I try to switch user with:
      org.jboss.seam.security.Identity.instance().setUsername("User Name");
      SkorLoginModule.setSysMode(false);
      try {
       LoginContext loginContext = new LoginContext("MyRealm");
       loginContext.login();
      } catch (LoginException e) {
       System.out.println("error");
      }
      
      

      there aren't created any sub-pools for every user. There is one physical db connection. When I try to flush cache from JaasSecurityManager, the connection i reseted and previously logged in user is disconnected.
      Another question is: when should I invoke
      loginContext.login()
      because now it's invoked in a stateless bean which authenticate method is configured in seam's compoments.xml file as:
      <security:identity authenticate-method="#{authenticator.authenticate}"
       security-rules="#{securityRules}"/>
      

      I think the authenticate method should be invoked somewhere else - in authenticator bean the entity manager is already injected by @PersistenceContext annotation.

      Thanks in advance for any help.

        • 1. Re: one data source with multiple database users

          What have JCA login modules got to do with Seam authentication?

          There's another thread from last year that explains the misunderstanding
          in more detail (search for it).

          I'd like to know if there some Seam documentation that is misleading people.
          i.e. Establishment of credentials to login to a database != authentication of a user in a
          web-app.

          I'd guess (it is unclear from the incomplete information posted) that you
          want to use ConfiguredIdentityLoginModule for the datasource.
          If you want to use the Web app's identity (which has been established properly)
          then use CallerIdentityLoginModule.

          If this choice isn't the issue then, I'd suggest the security forum.
          Your problem has nothing to do with JCA.

          • 2. Re: one data source with multiple database users
            diemon

            Let me put my problem in other words. User is authenticated and logged in authenticator.authenticate method as configured in components.xml. After checking request certificate (no user logging form in present), the org.jboss.seam.security.Identity object is filled with usrename and some other stuff. As we are in a bean method -'authenticate', which contains entity manager, it's clear that we have an established database connection. I need to switch database user and open connection from one of connection sub-pools created for 'Subjects' (PoolBySubject). When I use my own login module and switch the db connection credentials there is another connection opened but if another user was logged in, he is disconnected (no concurrent connections are opened).

            • 3. Re: one data source with multiple database users

              Rather than using words, show the evidence.

              I still think you're confused between authentication (what Seam does)
              and establishment (what JCA does) of credentials.

              • 4. Re: one data source with multiple database users
                diemon

                The problem was in establishing database connections with different credentials in Seam components. I solved the problem in a very simple way. I've used hibernate configuration option hibernate.connection.provider_class where in getConnection method one can simply return new connection from data source with any username/password.

                • 5. Re: one data source with multiple database users
                  peterj

                  I hope you don't expect decent performance from your application, or that you have very few users. Establishing a database connection is a very expensive operation. Getting a new connection each time you need to access the database is a definite performance killer.

                  You do not, by any chance, have a mainframe background? What you want is typical in mainframes - the end user's identity is used to access the database thus enabling the db admin to lock down the database based on users or their roles.

                  • 6. Re: one data source with multiple database users
                    diemon

                    I hope so too. Well, the connection poolling is up to Hibernate and JBoss. I've only changed the connection provision. According to what Oracle shows, the session looks to be kept between web requests. getConnection method is invoked many times. It looks like the connection pool managed by JBoss works good.

                    • 7. Re: one data source with multiple database users
                      deanhiller

                      what version of jboss are you using?  I am using 5.1.  I inserted log4jdbc so I can see the connection logs.  I did a request from the first war which grabbed the 5th connection from the pool and then did a request from the second war and it grabbed the 5th connection as well.  It is a pool after all.

                       

                      Anyone know how to switch the user on the db connection?  We would prefer to automate it so when our first war gets it, the user firstwarUser is used and when our second war gets it, secWarUser is used on the connection so we can track which apps where doing bad things they should not be doing(and the dbas would like to lock down the database per app which means we need a user per app).  Any ideas how to do this?

                       

                      thanks,

                      Dean