PicketBox - DataBaseAttributeLocator
valia981 Sep 20, 2012 10:23 AMHi all,
I've got an error using DatabaseAttributeLocator and I can't find a solution:
I'm deploying under jboss-as-7.1 a web application (this should be my PDP).
I have a simple main class which builds a XACML request, sends it to my PDP and waits for response.
Following this tutorial https://community.jboss.org/wiki/XACMLAttributeLocatorUsingTheDatabase I configure my web application to use database if some attribute in request is missing. I've created a simple database (MySQL), inserted correct values, checked connection (with another test program) and this is my pdp configuration
<ns:jbosspdp xmlns:ns="urn:jboss:xacml:2.0"> ...... ...... <ns:Locator Name="org.jboss.security.xacml.locators.attrib.DatabaseResourceAttributeLocator"> <ns:Option Name="DATABASE_FILE_NAME">database.file.properties</ns:Option> <ns:Option Name="sql">SELECT account_status FROM AccountStatus where subject_id=?;</ns:Option> <ns:Option Name="attributeSupportedId">urn:xacml:2.0:interop:example:resource:account-status</ns:Option> <ns:Option Name="preparedStatementValue">urn:xacml:2.0:interop:example:resource:owner-id</ns:Option> <ns:Option Name="valueDataType">http://www.w3.org/2001/XMLSchema#string</ns:Option> <ns:Option Name="columnName">account_status</ns:Option> </ns:Locator> </ns:Locators> </ns:jbosspdp>
and property file contains
connectionURL=jdbc\:mysql\://localhost\:3306/XACMLDBAttributeLocator#and credential driverName=com.mysql.jdbc.Driver
ConnectionURL is correct.
After this, I create my PDP.war, deploy it using jboss as 7.1, run my main and I've got an exception (ClassNotFound).
15:31:11,818 DEBUG [org.jboss.tm.TransactionManagerLocator] (MSC service thread 1-2) Unable to instantiate legacy transaction manager: java.lang.ClassNotFoundException: org.jboss.tm.TxManager from [Module "org.jboss.jboss-transaction-spi:main" from local module loader @adb1d4 (roots: /home/myhome/jboss-as-7.1.1.Final/modules)] at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:190) at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:468) at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:456) at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:423) at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398) at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:120) at java.lang.Class.forName0(Native Method) [rt.jar:1.6.0_29] at java.lang.Class.forName(Class.java:169) [rt.jar:1.6.0_29] at org.jboss.tm.TransactionManagerLocator.usePrivateAPI(TransactionManagerLocator.java:172) [jboss-transaction-spi-7.0.0.Final.jar:7.0.0.Final] at org.jboss.tm.TransactionManagerLocator.locate(TransactionManagerLocator.java:133) [jboss-transaction-spi-7.0.0.Final.jar:7.0.0.Final] at org.jboss.tm.TransactionManagerLocator.locateTransactionManager(TransactionManagerLocator.java:94) [jboss-transaction-spi-7.0.0.Final.jar:7.0.0.Final] at org.jboss.tm.usertx.client.ServerVMClientUserTransaction.<init>(ServerVMClientUserTransaction.java:93) [jboss-transaction-spi-7.0.0.Final.jar:7.0.0.Final] at org.jboss.tm.usertx.client.ServerVMClientUserTransaction.<clinit>(ServerVMClientUserTransaction.java:60) [jboss-transaction-spi-7.0.0.Final.jar:7.0.0.Final] at org.jboss.as.txn.service.ArjunaTransactionManagerService.start(ArjunaTransactionManagerService.java:115) [jboss-as-transactions-7.1.1.Final.jar:7.1.1.Final] at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1811) [jboss-msc-1.0.2.GA.jar:1.0.2.GA] at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1746) [jboss-msc-1.0.2.GA.jar:1.0.2.GA] at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [rt.jar:1.6.0_29] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [rt.jar:1.6.0_29] at java.lang.Thread.run(Thread.java:662) [rt.jar:1.6.0_29]
It seems a CLASSPATH problem, com.mysql.jdbc.Driver cannot be found.
I've tried to specify mysql driver in different ways:
- lib folder of my web application
- jboss module (creating following jboss tutorials)
- in CLASSPATH
and I've always got the same error.
Then I've searched for source code and my error is generated here (class org.jboss.security.xacml.locators.attrib.DatabaseAttributeLocator)
@Override protected Connection getConnection() { Connection connection = null; if (dsJNDIName != null) { try { Context ctx = new InitialContext(); DataSource ds = (DataSource) ctx.lookup(dsJNDIName); connection = ds.getConnection(); } catch (Exception e) { // log section } } if (connection == null && dbFileName != null) { Properties props = new Properties(); ClassLoader tcl = SecurityActions.getContextClassLoader(); try { props.load(tcl.getResourceAsStream(dbFileName)); } catch (IOException e) { throw new RuntimeException("Error loading DB file", e); } try { Class.forName(props.getProperty("driverName")); } catch (ClassNotFoundException e) { throw new RuntimeException("DB Driver not found:", e); } try { connection = DriverManager.getConnection(props .getProperty("connectionURL")); } catch (SQLException e) { throw new RuntimeException("Cannot get DB Connection:", e); } } return connection; }
How I can fix this? if I can specify my external database (mysql, h2, db2 for example) only using properties in database.file.properties, where driver files should go?
After hours of works I wrote this class
public class MyDataBaseAttributeLocator extends DatabaseResourceAttributeLocator { @Override protected Connection getConnection() { Connection connection = null; if (dsJNDIName != null) { try { Context ctx = new InitialContext(); DataSource ds = (DataSource) ctx.lookup(dsJNDIName); connection = ds.getConnection(); } catch (Exception e) { // log section } } if (connection == null && dbFileName != null) { Properties props = new Properties(); ClassLoader tcl = SecurityActions.getContextClassLoader(); try { props.load(tcl.getResourceAsStream(dbFileName)); } catch (IOException e) { throw new RuntimeException("Error loading DB file", e); } try { Class.forName(props.getProperty("driverName"), true, tcl); } catch (ClassNotFoundException e) { throw new RuntimeException("DB Driver not found:", e); } try { connection = DriverManager.getConnection(props .getProperty("connectionURL")); } catch (SQLException e) { throw new RuntimeException("Cannot get DB Connection:", e); } } return connection; } }
the only change is in Class.forName method used.
Putting my driver in lib directory of web app everything is ok.
Is my solution correct? I mean, which classloader should be used to find out driver?
In this case ModuleClassLoader cannot find driver, but I have no limit about database type (or I can't find where this limit is written) and there is no reason to use ModuleClassLoader to load driver...am I wrong?
Please, If the section is wrong, tell me where my question should go.