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.