In this release of JBoss EAP 6, the error `javax.resource.ResourceException: No matching credentials in Subject!` is presented when multiple datasources are defined backed by the same security domain.
The workaround is to disable caching on the security domain if it must be shared among datasources. Otherwise, a separate security domain should be used for each datasource.
Description of problem:
Where multiple datasources are defined backed by the same security domain the following error is seen: -
Caused by: javax.resource.ResourceException: No matching credentials in Subject!
Debugging the connection attempt I see the Subject being compared was as a result of calling the security domain, i.e. not a Subject pulled off the AccessControlContext.
The comparison fails because the PasswordCredential IronJacamar finds contains a reference to the ManagedConnectionFactory.
What I believe is something has got out of sync when it comes to the intended use of security domains with datasources and a previous call has been cached hence a datasource now receiving a Principal intended for another datasource.
See the following for the underlying issue: -
Created attachment 901502 [details]
I am attaching a test war that replicates the problem. It is a simple WAR with a single servlet .java class file. The .java source is in the WAR next to the .class files so you can see the code and debug it.
Here's a quick summary of the replication procedures - I will provide more details after this summary:
SUMMARY TO REPLICATE:
1) Add a single security-domain for the the H2 database's "sa" credentials.
2) Add two datasources - one <datasource>, one <xa-datasource> that share the above security domain. Point the datasources to the H2 database that comes with the EAP build.
3) Copy the attached test-service.war to the EAP's standalone/deployments directory.
4) Run bin/standalone.sh
5) Point your browser to http://localhost:8080/test-service/BugTestServlet
At this point, you should see the exceptions in the server log. If you don't see the error, make another browser request until you see the exception. I've had to make at most two browser requests in order to see the error happen. It is easy to replicate.
DETAILS TO REPLICATE:
To run, you need to add these to your standalone.xml first:
1) Add a single security-domain that our test datasources will share - the password you see here is the obscured "sa" password of the H2 test database that comes with the default EAP build:
<security-domain name="BugTest-policy" cache-type="default">
<login-module code="SecureIdentity" flag="required">
<module-option name="username" value="sa"/>
<module-option name="password" value="9fdd42c2a7390d3"/>
2) Add two new datasources that share the above security domain - one is a datasource, the other a XA datasource - YOU MUST HAVE BOTH TYPES. This bug does NOT show itself if you use two <datasource> entries - I think they must be different types of datasources for the bug to show up!!!:
<datasource jndi-name="java:jboss/datasources/BugTestDS1" pool-name="BugTestDS1" enabled="true" use-java-context="true">
<xa-datasource jndi-name="java:jboss/datasources/BugTestDS2" pool-name="BugTestDS2" enabled="true" use-java-context="true">
Now, copy the attached test-service.war to an EAP 6.3 standalone/deployments directory, and run the server normally via standalone.sh.
The servlet will run two queries - one with each datasource - during its init() method during startup - this was done to show that running the queries over both datasources *sequentially* works fine.
But then, make a request to the servlet so its doGet runs those same two queries concurrently on separate threads. You do this by pointing your browser to http://localhost:8080/test-service/BugTestServlet - if the failure doesn't show up on the first request, make another request. I have consistently reproduced this bug on either the first or second browser request I've made - it is very easy to make the bug occur.
I think this one needs re-categorising to be a documentation issue only.
Essentially it is an aspect of the JCA specification that makes it mandatory that the PasswordCredential that is obtained is then associated with the ManagedConnectionFactory it is used with.
So if a security domain is to be used with multiple datasources then no caching should be enabled for that domain, this means that each time the PasswordCredential is obtained from the security domain it will be a new instance and the association / checking of the existing ManagedConnectionFactory will not cause any errors.
However if caching of the security domain call is desirable then one security domain will be required per datasource, this way the obtained PasswordCredential can be cached but at there is a 1:1 mapping of domain to datasource there will not be a conflict when it comes to the ManagedConnectionFactory association.
Verified in A&C guide revision 6.4.0-37