3
votes

I'm using jboss remoting 2.5.4.SP3 to provide remote access to EJBs in a JBoss 7.1 server from both a web app and other JBoss instances. I'm doing it manually because of issues with remote EJB access in JBoss 7.1, specifically (but not only) the inability to access the same (interface) bean on multiple servers simultaneously. I'm using remoting2 because remoting3 has no documentation.

I have remoting working using TransporterHandle/TransporterClient using the socket transport, but in methods called via this remote connection, the server wants to lookup the principal from the ejbContext. I can't find a way to manually set the principal, or other contextual security/identity information. At the limit I'd be happy just to set the principal when the ejb method is invoked - all incoming calls are to local EJB3 beans - or even to set it specifically for the EJBContext.

I've found a lot of information regarding Spring (which I'm not using), but nothing seems to match my particular context.

3

3 Answers

1
votes

And now, the correct way to do this:

On the client side I get the security context and package up the security domain and subject info for transport to the server along with the invocation. The SecurityDomain is a String and SubjectInfo is serializable:

Map m = new HashMap();
SecurityContext securityContext = SecurityContextAssociation.getSecurityContext();
if (securityContext != null) {
    m.put("SUBJECT-INFO", securityContext.getSubjectInfo());
    m.put("SECURITY-DOMAIN", securityContext.getSecurityDomain());
}
response = remotingClient.invoke(request, m);

The map m gets sent with the invocation over jboss remoting. On the server side, I extract the security information and set the context for the invocation like this:

SecurityContext oldContext = SecurityContextAssociation.getSecurityContext();
SubjectInfo si = (SubjectInfo) invocation.getRequestPayload().get("SUBJECT-INFO");
String domain = (String) invocation.getRequestPayload().get("SECURITY-DOMAIN");
if (si != null) {
    SecurityContext sc = new JBossSecurityContext(domain);
    sc.setSubjectInfo(si);
    SecurityContextAssociation.setSecurityContext(sc);
}
try {
    return super.invoke(invocation);
} finally {
    SecurityContextAssociation.setSecurityContext(oldContext);
}

Works like a charm!

0
votes

Have a look at the jboss-ejb-client.properties. There is also a quickstart example using a remote client to lookup an EJB.

0
votes

I've solved my underlying problem, although not in the general way I was hoping for.

I put a servlet filter on all incoming requests, recording request.getUserPrincipal in a thread local. I can then access this in non-EE code and find the principal making the request. Then when I make call to my app server I use JBoss Remoting's ability to attach metadata to each invocation to pass the Principal over the wire. I had to copy the TransporterClient to do this because it's private constructors et al don't allow for overriding the functionality required to attach per-request metadata (as opposed to per-connection). On the server side I take the incoming Principal and set it into a thread local. Then, in subsequent code that accesses EJBContext.getCallerPrincipal I also lookup the incoming Principal from the thread local, and if that isn't null (hence we are in a remote EJB call), I use that if the caller principal is anonymous. If it's not anonymous then it must have been set in some way after the incoming call, so I ignore the incoming Principal in that case.

All in all, a much more specialised solution than I was hoping for, and it doesn't shed any light on how I can do generic context propagation in JBoss 7.1 over the wire.