I'd be very grateful is someone could assist me with the following questions:
What are the differences between @RolesAllowed and @DeclareRoles annotations?
The @RolesAllowed
annotation is used to specify the list of roles that are actually allowed to access the business method. The behavior of the EJB at runtime, is affected by the presence of this annotation, for the EJB container actively verifies that the caller is present in an allowed role. Also, this annotation can be defined on both TYPE
s and METHOD
s allowing you to define the list of roles allowed at both the level of a class or a method. You can override the list of roles allowed for all methods of a class, at the level of an individual method.
The @DeclareRoles
annotation on the other hand is merely used to declare a list of roles; it is the equivalent of the security-role-ref
element in the ejb-jar.xml
file. The EJB container does not require knowledge of these roles to enforce access control checks on business methods of an EJB; instead, the bean provider/developer may use these roles in isCallerInRole
tests to ensure programmatic security.
The EJB 3.1 specification states the following about the @DeclareRoles
annotation:
17.2.5.3 Declaration of Security Roles Referenced from the Bean’s Code
The Bean Provider is responsible for using the DeclareRoles annotation or the security-role-ref elements of the deployment descriptor to declare all the security role names used in the enterprise bean code. The DeclareRoles annotation is specified on a bean class, where it serves to declare roles that may be tested by calling isCallerInRole from within the methods of the annotated class. Declaring the security roles allows the Bean Provider, Application Assembler, or Deployer to link these security role names used in the code to the security roles defined for an assembled application. In the absence of this linking step, any security role name as used in the code will be assumed to correspond to a security role of the same name.
The second part of your question states:
I developed a login function to check username and password against information in the database. However, I'd like to ask how I can assign a role to an authenticated user to use with the above annotations.
In this event, a general point to be noted is that my preferred approach is to not use progammatic security unless your use cases actually require it. In most events if one can achieve the requirements with declarative security, it is preferable to use it, for progammatic security requires you to keep track of isCallerInRole
method invocations, and the absence of such a call, may result in a security breach. Either way, in your case, you will need your container to first recognize the groups and principals in the database, as roles that maybe used for access control checks.
In simpler words, the EJB client (a Java SE application, or a servlet, or another EJB) must first authenticate itself against the container's security mechanisms, to establish the caller's Principal
. Successful use of Declarative or Progammatic security therefore relies on a successful authentication process. In your case, you will need to configure your container to recognize the groups and users in your database and translate those into Principal
objects that can be used to enforce access control in a declarative or programmatic manner. Most containers support one or more flavours of JAAS login modules for this purpose; Glassfish 3.1 for instance, allows this using a JDBCRealm, while JBoss 6.0 supports this with a DatabaseServerLoginModule. You will therefore need to determine whether your container supports such a login module, and configure it to use your database.
Note, that in some cases, the container provided login modules may prove to be insufficient in meeting your needs. In such a case, you'll need to write your own login module (and if required, against the container's interfaces).
Additionally, you'll also need to map the roles used by the application to the users and groups in the JAAS realm. For example, if your database used by the JAAS realm:
U1
, U2
, U3
, U4
and U5
, andG1
, G2
and G3
containing U1
, U2
, U3
respectively,R1
, R2
and R3
(defined through the @RolesAllowed
annotation) to access it's methods,then you'll need to map the roles to principals (users and groups) in the JAAS realm. The mapping must be done even in the case where the role names are the same as principal names; Glassfish simplifies this by supporting the default principal to role mapping that maps similarly named principals (users or groups) to roles directly. Also, the process of mapping is container specific and as you would have guessed, this mapping is performed in container specific deployment descriptors and not in the EJB deployment descriptor (ejb-jar.xml
).
To complete the answer, you'll need to assign a role to every user that is created. For the sake of simplicity, you may create a single user-group that all users may belong to. When the user authenticates himself against a JAAS realm, the Principal object would contain this group. The group in your JAAS realm may then be mapped to an EJB role, and the role name may be specified in a @RolesAllowed
annotation. Any user in the database that is not in this group, would be prevented from accessing the annotated method(s) by the EJB container.