Currently I’m working on a project which uses the authentication in JBoss. I would say that’s not a very large project but it’s not an hello-world-project. In this project I was confronted with some issues. The most problematic is that there isn’t much documentation in the web which covers the issues beyond a standard JAAS Authentication. I mean such points as: securing an Queue, Topic, Service, how to connect to these from an messagedriven- or sessionbean (and of course: what works and what doesn’t). Based upon these experiences I thought of a small series of articles which might help others. To make a long story short – here is the first part:
When using JBoss security you’re typically confronted with JAAS: The Java Authentication and Authorization Service. This service is the standard mechanism to secure JavaEE applications in an applicationserver. Of course you can try to use spring-security to achieve this goal too but a) this can’t be used to secure the whole process in the applicationserver (for example: webapp->slsb->queue->mdb) and b) this is out of scope.
At first you’ll need an JBossAS 5.1.0. You can download it here. I’m currently using the 5.1 in my project so my experiences (especially the issues/pitfalls) base on this version. The issues which I’m reporting about might be in other versions as well or might already be fixed in following versions. The most explanations are more general so I expect that they’ll be correct for other versions of the JBoss as well.
After downloading the archive you’ll find a file called login-conf.xml in the [jboss_home]/server/default/conf/ directory. This file contains the security-domains which are available on the AS, such as: web-console, jmx-console and many others.
my-users.properties my-roles.properties
This example entry is an application-policy. This policy contains the login-module UsersRolesLoginModule. This module is responsible for authenticating a user based on the provided password. It also provides the roles based on the authenticated principle. A principal is the provided username in the terminology of jaas, it is also named identity. There are some login-modules provided by JBoss, for example a DatabaseLoginModule, which authenticates/authorizes against a database. Some other allows a ldap-server as a backend or the authentication using certificates.
This UserRolesLoginModule uses files to authenticate and authorize the user. One is the my-users.properties and the other the my-roles.properties. Both are standard properties files with the format key = value. The first of them, the my-users.properties expects that the entries look like username = password:
myuser = 123456
The second one expects the following format: username = role1,role2,role3,…,rolen
myuser = testrole1, testrole2
These both files have to be located in the [jboss_home]/server/default/conf/. The entries for the files in the login-conf.xml can be changed, but keep in mind that they’re relative to the …/conf/ directory.
If you put this entry in login-conf.xml and the files in place you can start the JBossAS. If everything is okay you shouldn’t see any stacktraces. If there are errors have a look into the login-conf.xml. When the exception occures when starting the AS it’s only the login-conf.xml which could be wrong. The other both files are only accessed when an secured resource is accessed and related credentials are provided.
Now we have a JBossAS with a configured security domain. But we’ve got nothing to protect. The simplest way is to deploy a simple session bean with the needed annotations. At first we’ll create a standard and not secured sessionbean to see that everything works as expected:
Our sessionbean will just take one argument (your name) and will return a string “Hello [your_name]“.
The sessionbean:
import javax.ejb.Remote;
import javax.ejb.Stateless;
@Stateless
@Remote(SayHello.class)
public class SayHelloBean {
public String sayHello(String name) {
return "Hello " + name;
}
}
The related remote interface:
public interface SayHello {
public String sayHello(String name);
}
After deploying the bean and the interface in a jar to the deploy directory of the AS, it should show no exceptions.
The log or the console of the AS should show something similar to this:
23:52:06,370 INFO [JndiSessionRegistrarBase] Binding the following Entries in Global JNDI: SayHelloBean/remote - EJB3.x Default Remote Business Interface SayHelloBean/remote-myea.beans.SayHello - EJB3.x Remote Business Interface
Now that your Bean is deployed successful we’ll switch to the client.
...
public static void main(String[] args) throws Exception {
Properties env = new Properties();
env.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
env.setProperty(Context.URL_PKG_PREFIXES, "org.jnp.interfaces.NamingContextFactory");
env.setProperty(Context.PROVIDER_URL, "jnp://localhost:1099/");
InitialContext ctx = new InitialContext(env);
SayHello h = (SayHello) ctx.lookup("SayHelloBean/remote");
System.out.println(h.sayHello("Marc"));
}
...
This code should produce “Hello Marc”. If there are any failures please check if all the needed libraries are in the classpath or the settings are correct. Especially have a look on the PROVIDER_URL the wrong address is often a problem. Most people bind JBossAS to another IP-address to avoid binding errors for the 1099 port on windows systems which are connected to a domain.
If that’s successful we’ll try it ‘with security’. The sessionbean have to be changed:
The sessionbean with security:
import javax.annotation.security.RolesAllowed;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import org.jboss.ejb3.annotation.SecurityDomain;
@Stateless
@Remote(SayHello.class)
@SecurityDomain("my-security")
@RolesAllowed({"testrole2"})
public class SayHelloBean {
public String sayHello(String name) {
return "Hello " + name;
}
}
The only changes are the both annotations: @SecurityDomain(“my-security”) and @RolesAllowed({“testrole2″}). The first activates security for this bean and connects to the “my-security” authentication-module. The next annotation define which roles have access to this class. It’s written in {} because it can contain several roles comma-seperated: {“testrole1″,”testrole2″}
If you’re using an IDE it might be the case that the IDE can’t find the annotation SecurityDomain. This is an extension aside the ejb3-spec made by JBoss. To use it you have to add the jboss-ejb3-ext-api.jar from the [jboss_home]/commons/lib/ folder. This jar contains several other very useful extensions to the ejb3-spec. But be warned, since this point you’re leaving the compliance to the ee-spec and you’ll tie yourself/your project to the JBossAS.
When you now try to connect using the client above it will result in this:
Exception in thread "main" javax.ejb.EJBAccessException: Caller unauthorized ... (some more stacktrace) ...
Now we’ve got to modify the client as well:
public static void main(String[] args) throws Exception {
Properties env = new Properties();
env.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
env.setProperty(Context.URL_PKG_PREFIXES, "org.jnp.interfaces.NamingContextFactory");
env.setProperty(Context.PROVIDER_URL, "jnp://localhost:1099/");
SecurityClient client = SecurityClientFactory.getSecurityClient();
client.setSimple("myuser", "123456");
client.login();
InitialContext ctx = new InitialContext(env);
SayHello h = (SayHello) ctx.lookup("SayHelloBean/remote");
System.out.println(h.sayHello("Marc"));
}
This client should produce the same output like the client without authorization. In this case I’ve used a very simple way to manage the authentication. Within one of the next parts of this article series I’ll show you the different ways to connect to a secured JBossAS.
Now you’ve made the first step in JBoss & Security.
Pingback: JAAS & JBoss: Client Authentication » beyond – e blog