one data source with multiple database users
diemon May 19, 2008 5:53 AMHello
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.