Skip to main content

JDBCRealm: Can I map users/groups to roles using database?

13 replies [Last post]
pwardrip
Offline
Joined: 2008-12-09

I'm trying to migrate a project from Tomcat 6 to Sun Application Server 9.1 U2. I can't figure out the JDBCRealm implementation. Here's the question: how do I map users (or groups) to roles using a database? This needs to work for in the web.xml and HttpServletRequest.isUserInRole().

The Catalina DataSourceRealm I've been extending expects 2 tables: one with usernames and passwords, the other mapping users to roles. Our users belong to groups, and roles are assigned to the groups, not directly to the users. We use a view to connect the user to roles for that group and use this in the Tomcat Realm as "userRoleTable".

The Glassfish version of JDBCRealm doesn't map users to roles, but it does map users to groups. From what I can tell, the groups are Principals like the user and need some other mapping to link them to roles. How can I use my database as the source of this mapping? I tried ignoring my groups and pointing "group-table" at my user_role view, with activate-default-principal-to-role-mapping="true" but that didn't seem to work. I've seen a bunch of sun-web.xml examples where people are creating groups named exactly the same as their roles and mapping them one-to-one ... I'm *really* hoping we've missed something here. This seems a little too redundant to be intentional.

Our application has very fine grained security roles, there are lots of them! The customers using our application create users and assign them to groups. They also have the ability to create/modify groups and assign roles to them (there are 8 roles associated with the screens I just mentioned). I have to continue supporting this and I'm stuck. I already need to extend AppsrvRealm, so I'm hoping there is some other abstract class and domain.xml entry I'm not aware of that will solve this problem.

Any help would be appreciated!

----------------------------------------------------------
Group Name: [Administrators ]

Users
[x] View [x] Create [x] Modify [x] Delete

Groups
[x] View [x] Create [x] Modify [x] Delete

[SAVE]
----------------------------------------------------------

Thank you!

------------
Paul Wardrip
Software Engineer
TANDBERG Television | Part of the Ericsson Group

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
pwardrip
Offline
Joined: 2008-12-09

Here's an update on my progress, unfortunately I still don't have a working solution:

I created a JACCRoleMapper implementation, placed my jar file and the inmemory.jacc.provider.jar in SUNWAppserver/lib. I added the simple JACC provider to domain.xml, configured it and added the jvm-option: -Dsimple.jacc.provider.JACCRoleMapper.class=com.ttv.ui.security.TTVRoleMapper

The behavior I'm experiencing is the same as the issue I mentioned above, when I tried defining a one to one mapping in sun-web.xml. My role mapper *does* work, but I still get a false return value from request.isUserInRole()... even though I can access a page that uses the same role in a web.xml .

I found someone talking about similar issues, although they seem specific to EJB so I'm not sure if it is related: https://glassfish.dev.java.net/issues/show_bug.cgi?id=6800

I wanted to see what would happen in Glassfish V3, so I installed it on my system. I have a completely different issue here. No matter where I put the jar that contains my RoleMapper class I end up with some kind of classpath issue. I've tried putting it in just about every directory, from the domain lib, the global one, the modules folder where the inmemory.jacc.provider.jar is and I get one of the following depending on where I put my jar file:

java.lang.RuntimeException: java.lang.NoClassDefFoundError: com/sun/enterprise/security/jacc/provider/JACCRoleMapper
at com.sun.enterprise.security.jacc.provider.SimplePolicyConfiguration.(SimplePolicyConfiguration.java:141)

-- OR --

java.lang.RuntimeException: java.lang.ClassNotFoundException: com.ttv.ui.security.TTVRoleMapper
at com.sun.enterprise.security.jacc.provider.SimplePolicyConfiguration.(SimplePolicyConfiguration.java:141)

-- OR --

java.lang.RuntimeException: java.lang.ClassNotFoundException: com.sun.enterprise.security.jacc.provider.SimplePolicyProvider
at com.sun.enterprise.security.PolicyLoader.loadPolicy(PolicyLoader.java:175)

I'm not sure how to proceed from this point.

pwardrip
Offline
Joined: 2008-12-09

Okay I have figured out what was wrong in my 9.1 U2 deployment. Tomcat was letting us get away with not listing all the roles using in the web.xml. In Glassfish if the roles aren't listed the HttpServletRequest.isUserInRole() will return false, but will still work. Another case of Tomcat allowing applications to violate the specs.

kumarjayanti
Offline
Joined: 2003-12-10

Hi,

>
> I don't know how the
> default-principal-to-role-mapping gets the list of
> groups it creates roles for. If it only happens at
> initial deployment before ServletContextListeners are
> triggered, then this would be an issue. I can also
> envision install issues should one of our modules
> fail to deploy properly. I get the general feeling
> that this one-to-one mapping of a group to a role is
> a workaround, not desired behavior, and that this
> particular server property is a hack, designed to
> facilitate somewhat simpler migrations from other
> application servers. I think there are a few issues
> that would prevent me from using it this way.
>

The Java EE model is that an Application developer declares Roles. This is done either using Annotations or in web.xml

And at deployment time the roles be mapped to groups/principals. This is done in sun-web.xml where you map groups to roles. Principal to role mapping as you already noted does not scale.

So the default-principal-to-role-mapping feature saves you from having to write a sun-web.xml if the groups in the backend have the same names as the roles defined.

But if the set of groups is dynamic (i.e. new groups are created over the lifetime of the app) then your app is not compatible with the default JACC provider in GF V2. It would need redeployment since GF JACC Provider uses a static policy file. What can ofcourse change is what users exist, and what groups (of the static set) they are members of.

So can you clarify what you mean by : "our customers have runtime control over users, groups and the roles assigned to them." ?. Which things can change dynamically over the lifetime of the app.

1. Number of Users would change and their group memberships can change
2. Does the set of groups defined change or is it a static set. Will there be a increase or decrease in the number of groups ?
3. Does the set of roles keep changing or is it a static set ?. And i guess you are also saying that the set of groups with are in a given role also changes is that correct ?.

>
> 2] I really want to override the RoleMapper somehow
> through configuration. I'm trying to determine if
> this is possible without having to modify the source
> and recompile Glassfish itself. I doubt I could get
> the green light from my supervisors to deploy to
> production like this. It seems to me that there
> should be three parts to a custom realm
> implementation: Realm, LoginModule and RoleMapper. I
> already need to create my own AppsrvRealm to tweak a
> couple of things (and I was disappointed to discover
> that
> com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm
> is marked "public final").

So it is possible to override the RoleMapper although not with the default JACC provider. There is a new In-Memory JACC Provider introduced in V3 Prelude. It is implemented as a pluggable module and it provides a way to plugin your RoleMapper. You can plugin this provider into your GF V2 system.

And if you wish you can also write your own JACC provider to handle your usecase. The In Memory JACC Provider can help you as a starting point for doing that.

I discussed at length with our architect and he actually wanted me to do some experiment before replying to you, but since you raised the issue of overriding RoleMapper through configuration, i thought i might as well reply.

If you want more details about the In Memory JACC Provider see this blog from Ron :
http://blogs.sun.com/monzillo/

> [3] I could just migrate away from container managed
> security using some third party framework, but this
> is definitely not minimal impact.
>
>
> I just don't understand this implementation. The
> appserv-rt.jar contains
> org.apache.catalina.realm.JDBCRealm but I'm not able
> to use it, because I need an AppsrvRealm derived
> class. Catalina realms understand roles, AppsrvReamls
> understand groups ... at first this seemed like a
> real win for the AppsrvRealm, but not having a way to
> map roles to the users/groups in the database is a
> big downfall. It would be really cool to have this
> ability.
>

The Realm is just a little more than a JAAS LoginModule in the sense that it understands groups, and is a backend entity which ideally should not have anything to do with Roles which are application specific.

But your point about having configurability for the RoleMapper is taken. We would like to help you to make sure your usecase can be handled well with GF. Let us know what we can do to help the situation.

Thanks.

pwardrip
Offline
Joined: 2008-12-09

Before I started this thread, I noticed the JACC provider was configurable in domain.xml. I made a note to look into it and glanced over some of the code for the default one, but it was a little intimidating. I couldn't find much information about it and I wasn't sure if it was key to solving this or not. The In-Memory provider sounds promising. I'll have a closer look at it next week, thank you for pointing it out!

To answer your questions:

1. Yes, the users and their group memberships do change.

2. The set of groups changes also. We install the application with only an administrative group and user. All other groups are defined by the customer using the application and the roles assigned to them are different at every install site. Giving the customer the ability to change the roles for a group is the key issue here. To allow it that relationship has to be dynamic (in our case, it's already represented in the database).

3. The set of available roles is static for each of the modules.

This is where things get a little more complicated. Our application has many different war/ear modules that deploy into a larger application framework, each one has a static set of roles relating to its functionality. When the application starts up a ContextListener registers each one with a central dashboard module (runs at the root context). In some cases, runtime settings can prevent a module from being deployed. If launch conditions aren't met, the module (and its roles) will not be registered. Once the application has fully started, the dashboard will have a master list of all the active roles.

Also, since each module is a different war/ear we have to use the SingleSignOn valve in Catalina. I read somewhere that Glassfish supports a similar behavior but I haven't tried to configure or test this yet. I can't get far enough into the application to even worry about it, if I can't get authorization to work. :)

--pw

josealvarezdelara
Offline
Joined: 2008-12-26

Hi,

At the end, did you find the solution?

I have developed the Duke's Bank on JBoss.
I used MySQL for this issue and it worked.

Now I am developing the app on GF v2ur2
and I need to know if it is posible.

Regards,
Jose Alvarez de Lara

pitchphork

glassfish-2 wrote:
>
> Our application has very fine grained security roles, there are lots of
> them! The customers using our application create users and assign them to
> groups. They also have the ability to create/modify groups and assign
> roles to them (there are 8 roles associated with the screens I just
> mentioned).
>

I'd like to add a voice to the original author's quandry. This is an issue
especially for application developers who intend to sell a shrink-wrapped
application to customers (in the form of an EAR or WAR or whatever) and the
customers should be able to deploy the archive on their J2EE engine, whether
it is JBoss or Glassfish or whatever. To illustrate:

Supposed my shrink-wrapped application (let's say an application for
managing bank accounts) has two roles:

Teller (provides the ability to process deposits and withdrawals up to
$10000)
Manager (process any sized deposit/withdrawal plus create/delete accounts)

Each of my customers (banks) should be able to deploy the application and
manage their users using whatever groups they see fit:

First Bank Of Smallville's strategy
Group Peons ---> gets Role Teller
Group CustomerService ---> gets Role Manager

First Bank of BigCity's strategy
Group BangaloreCallCenter --> gets Role Teller
Group CallCenterManager --> gets Role Manager
Group EastCoastTellers --> gets Role Teller
Group WestCoastTellers --> gets Role Teller
Group BoardOfDirectors --> gets Role Manager
etc

As I understand it, the only way to achieve this with Glassfish is for each
customer to open the EAR file and modify the sun-web.xml file before
deploying (hardly an agreeable proposition for commercial software). Other
J2EE engines (I am thinking of SAP NetWeaver but I'm sure there are others)
provide the administrator with a GUI for mapping users to groups at runtime.
I am new to Glassfish and really like it, but I was surprised that its
(excellent) GUI did not have this feature. It seems almost mandatory in
order to give the J2EE administrator and the application vendor a natural
way of dividing the responsibility of authorizing groups of users.

--
View this message in context: http://www.nabble.com/JDBCRealm%3A-Can-I-map-users-groups-to-roles-using...
Sent from the java.net - glassfish users mailing list archive at Nabble.com.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@glassfish.dev.java.net
For additional commands, e-mail: users-help@glassfish.dev.java.net

greeneyed
Offline
Joined: 2003-06-10

Through the years I've talked several leads of the servlet spec. and complained about the lack of vendor independent dynamic security, and the answer I've been given has always gone along the same lines "yes, it is lacking, but customers do not complain so it must be enough".

Long ago, I rolled my own solution and then I can deploy my applications on any container and as dynamic as I wish. With the downside that I have to keep the solution myself, but once it was done...

Version 3.0 won't fix it either, so still keep my own :).

monzillo
Offline
Joined: 2004-05-08

Daniel,

Roberto forwarded your msg to me, and I think Kumar had previously asked me questions about the problem discussed in this thread. On this thread, there has been discussion of the default (aka canonical) p2r mapping, and integration of a custom jacc provider, or of a custom principal-2-role mapper. I'll discuss the relative merits and capabilities of those suggestions if you think that appropriate.

You should be able to develop a custom jacc policy provider that you could subsequently deploy in any EE compatible container (which unfortunately does not include Tomcat), and that will be able to rely on principal-2-role mapping functionality inherent in your provider. The in-memory jacc provider was included in Glassfish to help people accomplish this, and we can try to talk that through at least to understand why such an approach would not satisfy your needs. I should also point out that the jacc spi, provides context handlers which can be used by the policy provider to get more context about the request being processed. This additional context could be applied to select sufficient roles, or to determine a corresponding principal 2 role mapping.

EE 6 will also require support for the jsr 196 spi (especially within the web container), which will provide an additional opportunity to integrate common security functionality in any EE (full platform) compatible web container.

I'll try to continue the discussion in response to the msg you sent to the spec feedback alias.

Ron

pwardrip
Offline
Joined: 2008-12-09

As I've stated, our customers have runtime control over users, groups and the roles assigned to them. Our software is embedded at many different remote sites, owned by different customers. Each site has its own unique groups with different privileges. I find it hard to believe that I'm the only user who needs to change the roles for a Principal at runtime. I'm looking for a solution with minimal impact and I must keep the customer facing part of this application completely intact.

I don't know how the default-principal-to-role-mapping gets the list of groups it creates roles for. If it only happens at initial deployment before ServletContextListeners are triggered, then this would be an issue. I can also envision install issues should one of our modules fail to deploy properly. I get the general feeling that this one-to-one mapping of a group to a role is a workaround, not desired behavior, and that this particular server property is a hack, designed to facilitate somewhat simpler migrations from other application servers. I think there are a few issues that would prevent me from using it this way.

The way I see it the options I have are:

[1] Create the sun-web.xml with the one-to-one group to role mappings, point the group-table at my user_role view and ignore my actual groups in the Realm configuration. This seems inefficient but possibly workable. Is it more burden on the security manager to check a list of 50 Principals for a single role than to check just one pair of user and group Principals for it, with the group having 50 roles? On some complex pages there could be 20 calls to HttpServletRequest.isUserInRole().

[2] I really want to override the RoleMapper somehow through configuration. I'm trying to determine if this is possible without having to modify the source and recompile Glassfish itself. I doubt I could get the green light from my supervisors to deploy to production like this. It seems to me that there should be three parts to a custom realm implementation: Realm, LoginModule and RoleMapper. I already need to create my own AppsrvRealm to tweak a couple of things (and I was disappointed to discover that com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm is marked "public final").

[3] I could just migrate away from container managed security using some third party framework, but this is definitely not minimal impact.

I just don't understand this implementation. The appserv-rt.jar contains org.apache.catalina.realm.JDBCRealm but I'm not able to use it, because I need an AppsrvRealm derived class. Catalina realms understand roles, AppsrvReamls understand groups ... at first this seemed like a real win for the AppsrvRealm, but not having a way to map roles to the users/groups in the database is a big downfall. It would be really cool to have this ability.

Thanks,
--pw

pwardrip
Offline
Joined: 2008-12-09

I am currently attempting the sun-web.xml approach [#1]

I have managed to get authorized to get past the web.xml entries and view pages. However, when my code makes calls to HttpServletRequest.isUserInRole() it returns false, even though I can navigate to a page with an that has the same role assigned. Our navigation system calls isUserInRole() ... this way the user doesn't see icons or links to pages they don't have permission to access.

I'm still confused, please help!
--pw

kumarjayanti
Offline
Joined: 2003-12-10

> I am currently attempting the sun-web.xml approach
> [#1]
>
> I have managed to get authorized to get past the
> web.xml entries and view pages.
> However, when my code makes calls to
> HttpServletRequest.isUserInRole() it returns false,
> even though I can navigate to a page with an
> that has the same role assigned.

That sounds like a bug, but we are not aware of any such bug with GF. If there is a Role inside an which applies to a webresource collection and you were able to access the resource then isUserInRole should not be false. Can you give us a smaller reproducable testcase for this.

Thanks.

Witold Szczerba

2008/12/10 :
> source of this mapping? I tried ignoring my groups
> and pointing "group-table" at my user_role view,
> with activate-default-principal-to-role-mapping="true"
> but that didn't seem to work. I've seen a bunch of
> sun-web.xml examples where people are creating

The default-principal-to-role-mapping option is used only at
deployment time. When you change that value after the application is
deployed - it will not work.

There is glassfish specific xml descriptor which maps groups to roles,
this is something you cannot change without redeploying application,
and as far as I am concerned - it can be specified only in that
descriptor. The JDBCRealm, however can dynamically map users to groups
(but not group to roles).

For example:
role name -- group name
can read customer -- user
can append customer -- user
can modify own customer -- user
can modify any customer -- principal
can modify anything -- admin

The roles is something you have to 'design' (for example specified in
the code, in annotations of beans/methods, etc...). Once you agree on
the mapping between roles-groups (this is something you have to do
together with your customer, because he or she is unable to egsamine
your code and know what exactly the roles are and how are they
respected) and put that mapping inside xml descriptor. After
deployment, your customer can by his or her own alter the user/group
database tables, but will not be able to change that mapping without
altering that file and redeploying application...

Regards,
Witold Szczerba

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@glassfish.dev.java.net
For additional commands, e-mail: users-help@glassfish.dev.java.net

kumarjayanti
Offline
Joined: 2003-12-10

In glassfish you can either map groups to roles inside sun-web.xml OR activate-default-principal-to-role-mapping="true". You never have to do both.

But activate-default-principal-to-role-mapping="true" will do the trivial mapping of same named group to same named role.

If your group to role table is many to one then i am afraid activate-default-principal-to-role-mapping="true" will not help.

Let me get back after speaking to our architect.