Issue Details (XML | Word | Printable)

Key: GLASSFISH-18096
Type: Bug Bug
Status: Resolved Resolved
Resolution: Fixed
Priority: Major Major
Assignee: Hong Zhang
Reporter: exabrial
Votes: 0
Watchers: 2
Operations

If you were logged in you would be able to see more operations.
glassfish

GlassFish ignores @Resource(authenticationType = AuthenticationType.CONTAINER) if no ejb-jar.xml is present in an EJB

Created: 29/Dec/11 06:11 PM   Updated: 05/Jan/12 08:25 PM   Resolved: 05/Jan/12 08:25 PM
Component/s: deployment
Affects Version/s: 3.1.1
Fix Version/s: 3.1.2_b17, 4.0

Time Tracking:
Original Estimate: 3 days
Original Estimate - 3 days
Remaining Estimate: 3 days
Remaining Estimate - 3 days
Time Spent: Not Specified
Time Spent - Not Specified

File Attachments: 1. Zip Archive glassfish-jca-problem.zip (26 kB) 03/Jan/12 04:06 PM - exabrial

Environment:

Windows xp x86, JDK6u30, gf v3.1.1


Tags: jca ejb resource injection 3_1_2-approved
Participants: exabrial, Hong Zhang and Jagadish


 Description  « Hide

Summary: GlassFish ignores @Resource(authenticationType = AuthenticationType.CONTAINER) if no ejb-jar.xml is present in an EJB

Setup: When creating a Connnector Connection Pool, GF has a Security Maps tab. Enter the following:

Principal: *
Backend Principal: uid/password

Create an EJB with an injection point:

@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class EchoServiceBean implements EchoService {

@Resource(
name = "view/EchoService",
type = ViewManagerClientFactory.class,
authenticationType = AuthenticationType.CONTAINER)
ViewManagerClientFactory clientFactory;

GlassFish will not pass the backend principal to the @Resource.

To make this work, put the same information in the ejb-jar.xml:
<session>
<ejb-name>EchoServiceBean</ejb-name>
<resource-ref>
<res-ref-name>view/EchoService</res-ref-name>
<res-type>com.argushealth.enterprise.viewmanager.ViewManagerClientFactory</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</session>

The problem is in ConnectionManagerImpl. It uses pure XML to determine whether or not container managed authentication is required:

if (ref == null) {

if(getLogger().isLoggable(Level.FINE)) { getLogger().log(Level.FINE, "poolmgr.no_resource_reference", jndiNameToUse); }

return internalGetConnection(mcf, defaultPrin, cxRequestInfo,

resourceShareable, jndiNameToUse, conn, true);

}

String auth = ref.getAuthorization();

This should also examine the @Resource annotation, rather than just doing a null-check if a the resource reference descriptor is null.

More info: http://www.java.net/forum/topic/glassfish/glassfish/gf-bug-getting-empty-credentials-jca-adapter



Jagadish added a comment - 02/Jan/12 06:29 AM

The code in ConnectionManagerImpl retrieves the resource-reference which is a merged version of Annotation and Descriptor.
So, in all cases (eg: annotation alone is specified), we would still get the resource-reference.

connector-security-map is used to map the credentials from application server's security domain to EIS security domain.

Please refer the sample test that uses security-map in an RAR and the settings in web.xml.
https://svn.java.net/svn/glassfish~svn/trunk/v2/appserv-tests/devtests/connector/v3/securitymapweb

  • Refer "create-users" target in build.xml
  • Refer "create-security-maps" target in build.xml
  • Refer web.xml where the roles are defined for the web-component (it will be similar for ejb-component also)
    <security-constraint>
    <web-resource-collection>
    <web-resource-name>basic secuity test</web-resource-name>
    <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
    <role-name>employee</role-name>
    <role-name>contractor</role-name>
    <role-name>management</role-name>
    </auth-constraint>
    </security-constraint>
    ..
    ..
    ..
    <security-role>
    <role-name>employee</role-name>
    </security-role>
    <security-role>
    <role-name>contractor</role-name>
    </security-role>
    <security-role>
    <role-name>management</role-name>
    </security-role>

So, a role by name "employee" will be translated into "map3/map3" principal/password in EIS security domain via connector-security-map.


exabrial added a comment - 02/Jan/12 04:10 PM

Jagadish,

I think you missed the entire point of me logging this bug. If you specify the settings in XML, it works, if you use annotations, it doesn't work.

So your statements: "ConnectionManagerImpl retrieves the resource-reference which is a merged version of Annotation and Descriptor." is not true. I'm trying to log a bug and tell you the "merging" is not working.

-Jonathan


Jagadish added a comment - 02/Jan/12 05:42 PM

Yes, I did try a pure annotation based resource injection and it worked fine.
eg:
@Resource(mappedName="jdbc/__default", shareable=false, authenticationType = AuthenticationType.APPLICATION)
DataSource ds1;
ds1.getConnection() //succeeded.

Please attach a sample (eg: a sample based on jdbc or jms resource is also fine) if you see the issue.


Jagadish added a comment - 02/Jan/12 05:45 PM

Actual annotation was :
@Resource(mappedName="jdbc/__default", shareable=false, authenticationType = AuthenticationType.Container)
DataSource ds1;


exabrial added a comment - 02/Jan/12 05:56 PM

I just confirmed it works fine for me as well on JDBC resources... The problem seems to occur on custom resource adapters.

I can create you a code example, but do you have a custom RAR laying around? If not, let me know and I'll create you an example.

Otherwise, set a breakpoint on this method:
public ManagedConnection createManagedConnection(Subject subject, ConnectionRequestInfo cxRequestInfo) throws ResourceException;

My implementation is as follows:

public ViewManagerConnection getConnection(Subject subject, ConnectionRequestInfo cxRequestInfo)
throws ResourceException {
String operatorId = null;
String operatorPassword = null;

if (overrideUserName != null) { operatorId = overrideUserName; operatorPassword = overridePassword; } else {
for (PasswordCredential cred : subject.getPrivateCredentials(PasswordCredential.class)) {
operatorId = cred.getUserName();
operatorPassword = new String(cred.getPassword());

if (operatorId != null && operatorPassword != null) { break; }
}
}
....


exabrial added a comment - 02/Jan/12 09:52 PM

Ok, I've spent 2 hours creating a test case for this bug and can easily reproduce it. Can we open the bug back up so I can add an attachment?


Jagadish added a comment - 03/Jan/12 02:22 AM

re-opening the issue so as to attach the test-case.


exabrial added a comment - 03/Jan/12 04:06 PM

JCA example


exabrial added a comment - 03/Jan/12 04:18 PM - edited

To recreate the problem:

  1. run "mvn clean install" on all the projects in this order:
    1. glassfish-jca-problem
    2. glassfish-jca-problem-ejb
    3. glassfish-jca-problem-jca
    4. glassfish-jca-problem-ear
  2. deploy the resulting EAR to glassfish
  3. create a new pool using the rar in the ear
  4. create a security map for the rar. the security map should be * for the front end principal and put a test username/password in the backend principal
  5. create the following jndi reference to the pool: jca/MyJCA
  6. click this link, then click the doSomethingAwesome button: http://localhost:8080/MyJCAWebServiceService/MyJCAWebService?Tester

Notice the username and password are empty

To fix the problem, thus proving that an ejb-jar.xml must be present:

  1. rename this file: /glassfish-jca-problem-ejb/src/main/resources/META-INF/RENAME TO ejb-jar_XML to /glassfish-jca-problem-ejb/src/main/resources/META-INF/ejb-jar.xml
  2. run "mvn clean install" on all the projects in this order:
    1. glassfish-jca-problem
    2. glassfish-jca-problem-ejb
    3. glassfish-jca-problem-jca
    4. glassfish-jca-problem-ear
  3. redeploy the ear
  4. click this link, then click the doSomethingAwesome button: http://localhost:8080/MyJCAWebServiceService/MyJCAWebService?Tester

Notice that a username and password are present


Jagadish added a comment - 04/Jan/12 04:08 PM

Thanks Jonathan. I am able to reproduce the issue.
It looks like resource-env-ref is getting generated instead of resource-ref for @Resource annotation where type is a non standard class (eg: not one of javax.sql.DataSource/javax.jms.Queue/javax.jms.Topic etc.,). I shall investigate further and update the issue.


exabrial added a comment - 04/Jan/12 04:37 PM

Thanks Jagadish, I really appreciate your time.

Incidentally, and I'm not sure if this is related, but you cannot inject a java.lang.String as a @Resource. Not sure if that is part of the specification, but it could be related. String injection does work if the String is a resource-env-ref, but does not work if it's a resource-ref.


Hong Zhang added a comment - 05/Jan/12 06:12 PM
  • What is the impact on the customer of the bug?
    Not a regression, but this is something specified in the JSR 250 (common annotation spec) but we missed in the initial implementation.
  • What is the cost/risk of fixing the bug?
    The fix is available (and checked into trunk). The risk is small to medium.
  • Is there an impact on documentation or message strings?
    No.
  • Which tests should QA (re)run to verify the fix did not destabilize GlassFish?
    Regular set of the tests.
  • Which is the targeted build of 3.1.2 for this fix?
    The next promoted build of 3.1.2.

Hong Zhang added a comment - 05/Jan/12 06:22 PM

exabrial: Jagadish and I looked at the issue, it seems it's something we missed in the initial implementation (that a @Resource with a connection factory that's defined in resource adapter should be mapped to resource-ref and not resource-env-ref). Thanks for reporting this and providing the test case! I have checked in the fix into trunk (v4) and submitted a change request for approval to check the fix into 3.1.2 branch.
For @Resource with String type, based on the spec (JSR250), it should be mapped to env-entry and the current implementation is consistent with that.


Hong Zhang added a comment - 05/Jan/12 08:25 PM

fixed checked into both trunk and 3.1.2 branch.