Bug 55477

Summary: Add a solution to map a realm name to a security role
Product: Tomcat 7 Reporter: Stefan Mayr <stefan>
Component: CatalinaAssignee: Tomcat Developers Mailing List <dev>
Status: NEW ---    
Severity: enhancement CC: michaelo
Priority: P2 Keywords: PatchAvailable
Version: trunk   
Target Milestone: ---   
Hardware: All   
OS: All   
Bug Depends on: 63636    
Bug Blocks:    
Attachments: Prototype of a nestable realm
Edition with inline configuration for the role mapping
MappingRealm incl. docs

Description Stefan Mayr 2013-08-23 22:14:25 UTC
Created attachment 30759 [details]
Prototype of a nestable realm

Sometimes it would be quite handy to translate role names of a configured realm to the specifed security roles used in applications (web.xml). This would be especially comfortable with the JNDIRealm.

Example: 
#1 dev environment
map ldap group developers to security role manager-jmx

#2 production environment
map ldap group developers to security role manager-status

I've already created a prototype of a nestable realm using a simple properties file (mapping.properties) for translation. I'm no programmer, so it might need some cleanup.

Configuration could look like this (not tested with JNDI yet):
<Realm className="org.apache.catalina.realm.MappingRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
</Realm>
Comment 1 Christopher Schultz 2013-08-26 21:19:33 UTC
I haven't looked at the patch yet, but I wonder if configuring the wrapper-realm could be done directly in the context.xml like this:

<Realm class="...MappingRealm"
   map="realmGroupName->securityGroupName, otherName->3rdName">
   ...
</Realm>

Thoughts?
Comment 2 Stefan Mayr 2013-08-26 22:05:51 UTC
Should be possible. Where to find the rules about the security role naming conventions? The parsing of such an attribute might be tricky. Although this could be controlled by extra parameters (delimiter,assignation) if the defaults collide with names.

Is it possible to access XML-Elements under the defined Realm? I think of something like

<Realm class="...MappingRealm">
   <map security-role="r1" group-name="g1" />
   <map security-role="r2" group-name="g2" />
   ...
</Realm>

An alternative could be using a ressource. Is it possible to use a map as ressource?
Comment 3 Christopher Schultz 2013-08-27 14:06:47 UTC
Yeah, you can access sub-elements (we use Digester, so it just needs to be configured, but I'd prefer not to modify the digester configuration if it's not necessary).

I was a little worried about the delimiter stuff, and no, there aren't any rules against what a security role's name could be. I wanted to avoid commas because obviously LDAP group names are littered with commas. The map would be a nicer way to go. We could look to see if there's anything already recognized under <Realm> that could be used, here, or if something new is more appropriate.
Comment 4 Stefan Mayr 2013-08-27 21:58:30 UTC
Usual bean settings (like for a custom resource) which can be expressed in sub xml elements are attributes in the server.xml file.

configuration in beans:
<property name="map">
    <props key="role1">value1</props>
    <props key="role2">value2</props>
</property>

Tomcat: map="???"

Any pointer what I should search for?
Comment 5 Christopher Schultz 2013-08-28 14:40:26 UTC
I'm not sure I understand your statement. Can you explain further?
Comment 6 Stefan Mayr 2013-08-28 17:12:15 UTC
I thought about defining a custom ressource to make an inline configuration possible without messing with the Digester rules. So I searched and found http://tomcat.apache.org/tomcat-7.0-doc/jndi-resources-howto.html#Adding_Custom_Resource_Factories

If I understand this correct each attribute in the xml-Element resource will be accessible by my resource object (com.mycompany.MyBean).
e.g.

From the example:
  <Resource name="bean/MyBeanFactory" auth="Container"
            type="com.mycompany.MyBean"
            factory="com.mycompany.MyBeanFactory"
            bar="23"/>

here we can access to "bar" and its value "23". Some more google searches later I found collection elements in spring beans: http://static.springsource.org/spring/docs/1.2.9/reference/beans.html#beans-collection-elements . There the bean attributes are configured using sub xml elements. But I cannot find tomcat examples where some sort of collection is written as attribute value (like bar="{collection-element-1}{collection-element-2}") in the server.xml. I doubt this is even possible.
So I'm again with an external file, messing with strings or the digester rules.

Sorry if this is all a bit twisted. For me as a sysadmin programming is a not so easy
Comment 7 Stefan Mayr 2013-08-31 10:42:10 UTC
Created attachment 30788 [details]
Edition with inline configuration for the role mapping

I added the possibility to configure the mapping inline with the string mangling solution

Example:
<Realm className="org.apache.catalina.realm.MappingRealm"
       roleMappings="a=b;manager-gui=tomcat;c=d">
    <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
           resourceName="UserDatabase"/>
</Realm>

Other attributes and their default values:
assignment="="
separator=";"
pathname="conf/mapping.properties"

People using JDNIRealms with LDAP DNs will have to change assignment and separator (regex)strings. Maybe someone can come up with better default values.
Comment 8 Stefan Mayr 2013-08-31 11:02:31 UTC
Christopers version would be like this:

<Realm class="...MappingRealm"
    separator=",\s*"
    assignment="->"
    roleMappings="securityGroupName->innerRealmGroupName, otherName->3rdName"
   ....
/>
Comment 9 Stefan Mayr 2013-09-08 09:56:52 UTC
Created attachment 30805 [details]
MappingRealm incl. docs

MappingRealm comments were reworked and initial documentation has been added to docs/config/realm.xml and docs/realm-howto.xml (mostly copy & paste from existing sections)
Comment 10 Mark Thomas 2019-08-07 09:31:27 UTC
Context.addRoleMapping() does most of what is required (at least it will after bug 63636 is fixed). Just need a way to add the roles via configuration rather than JMX / code.
Comment 11 Christopher Schultz 2020-01-14 16:27:22 UTC
Given Context.addRoleMapping, it looks like MappingRealm just becomes a place for role mappings to be collected and set on the Context when the component is initialized. The code can be simplified greatly in this case.

While I think this implementation will work, I think it might be better-suited to add it to RealmBase to allow any realm to re-map roles. It will also make configuration slightly simpler because you only need one <Realm> instead of two.

Stefan, are you still willing to pursue this patch?
Comment 12 Michael Osipov 2020-01-14 18:12:42 UTC
(In reply to Christopher Schultz from comment #11)
> Given Context.addRoleMapping, it looks like MappingRealm just becomes a
> place for role mappings to be collected and set on the Context when the
> component is initialized. The code can be simplified greatly in this case.
> 
> While I think this implementation will work, I think it might be
> better-suited to add it to RealmBase to allow any realm to re-map roles. It
> will also make configuration slightly simpler because you only need one
> <Realm> instead of two.
> 
> Stefan, are you still willing to pursue this patch?

I am not convinced by that approach. I have provided a possible idea which decoupled from the realm. I want to pick this up b/c I have am already using a mapping feature.
Comment 13 Christopher Schultz 2020-01-14 18:15:52 UTC
(In reply to Michael Osipov from comment #12)
> I am not convinced by that approach.

Which approach? RealmBase? Context.addRoleMapping?

> I have provided a possible idea which decoupled from the realm.

Is there a patch or PR somewhere? Or already committed?

> I want to pick this up b/c I have am already using a mapping feature.

Sounds good to me.
Comment 14 Michael Osipov 2020-01-14 18:28:47 UTC
(In reply to Christopher Schultz from comment #13)
> (In reply to Michael Osipov from comment #12)
> > I am not convinced by that approach.
> 
> Which approach? RealmBase? Context.addRoleMapping?
> 
> > I have provided a possible idea which decoupled from the realm.
> 
> Is there a patch or PR somewhere? Or already committed?
> 
> > I want to pick this up b/c I have am already using a mapping feature.
> 
> Sounds good to me.

I don't like the approach tying the mapping to the realm as depicted by you or Stefan. Consider that a realm is not always bound to a context, maybe also be in the server.xml.

I have been using this: http://mo-tomcat-ext.sourceforge.net/apidocs/net/sf/michaelo/tomcat/extras/listeners/PropertiesRoleMappingListener.html for years. I am not certain whether it should remain a listener or should be a new configuration element in the context.xml. I think this discussion must happen on the dev list.
Comment 15 Christopher Schultz 2020-01-14 22:41:01 UTC
(In reply to Michael Osipov from comment #14)
> (In reply to Christopher Schultz from comment #13)
> 
> I don't like the approach tying the mapping to the realm as depicted by you
> or Stefan. Consider that a realm is not always bound to a context, maybe
> also be in the server.xml.

Great point. Also, mapping roles "in a realm" ends up mapping them for the whole context, not just for that one realm.

> I have been using this:
> http://mo-tomcat-ext.sourceforge.net/apidocs/net/sf/michaelo/tomcat/extras/
> listeners/PropertiesRoleMappingListener.html for years. I am not certain
> whether it should remain a listener or should be a new configuration element
> in the context.xml. I think this discussion must happen on the dev list.

A listener seems fine to me. I'm happy to discuss on the dev@ list.
Comment 16 Stefan Mayr 2020-01-19 14:34:07 UTC
At the time I wrote this realm I did not know of any other role name mapping add-ons. I'm not sure if Michael's solution already was public. Although I don't need it anymore the use case is still valid.

Initial starting point:
- LDAP (e.g. MS Active Directory) with group names we have to use
- a third party application using fixed role names we cannot change either

To make a solution (realm, filter, listener, ...) solve the above problem it needs to be configurable in server.xml or [enginename]/[hostname]/[appname].xml (Context) with a mapping definition outside of the application. The point is to not change the application.

After a quick look into Michael's documentation I'm only concerned about the placement of the default config in WEB-INF/role-mapping.properties. As an admin I would expect to look for it in the conf folder.

When you have settled which approach is best let me know what I should do. As a non-programmer it will just take me some time until I get it done.
Comment 17 Michael Osipov 2020-01-19 17:36:18 UTC
(In reply to Stefan Mayr from comment #16)
> At the time I wrote this realm I did not know of any other role name mapping
> add-ons. I'm not sure if Michael's solution already was public. Although I
> don't need it anymore the use case is still valid.

Back then it did not even exist.

> Initial starting point:
> - LDAP (e.g. MS Active Directory) with group names we have to use
> - a third party application using fixed role names we cannot change either

I am using it actually with Active Directory. I am mapping group SIDs to friendly (application names)

> To make a solution (realm, filter, listener, ...) solve the above problem it
> needs to be configurable in server.xml or
> [enginename]/[hostname]/[appname].xml (Context) with a mapping definition
> outside of the application. The point is to not change the application.

One needs to investigate this, but this is likely not fully possible because you have to modify the context as such.

> After a quick look into Michael's documentation I'm only concerned about the
> placement of the default config in WEB-INF/role-mapping.properties. As an
> admin I would expect to look for it in the conf folder.

It is isn't a problem to file:// support or even property interpolation as Tomcat does for other elements in the context.xml. I simply never needed it because all group SID where known to me.

I will try to raise a discussion next week.
Comment 18 Christopher Schultz 2020-01-20 16:44:10 UTC
How applicable is <security-role-ref> in web.xml, here?

(In reply to Stefan Mayr from comment #16)
> After a quick look into Michael's documentation I'm only concerned about the
> placement of the default config in WEB-INF/role-mapping.properties. As an
> admin I would expect to look for it in the conf folder.

I would expect a file without any explicit path information to be in the application's WEB-INF/ directory if the component were to be configured in the applications' WEB-INF/web.xml file. If it is configured in conf/server.xml for the server, I might expect the config file to be found in the server's conf/ directory. I'm not sure it's possible to detect the difference between the two situations from within the code. Therefore, I'd prefer to default to relative-to-WEB-INF but also allow (as Michael suggests) arbitrary file:// URI support as well as allowing ${catalina.base} replacement in the path to make it easy to build an installation-relative path.
Comment 19 Michael Osipov 2020-01-21 22:54:44 UTC
(In reply to Christopher Schultz from comment #18)
> How applicable is <security-role-ref> in web.xml, here?

As far as I know, this is per-servlet which can be very tedious and cannot be externalized.

> (In reply to Stefan Mayr from comment #16)
> > After a quick look into Michael's documentation I'm only concerned about the
> > placement of the default config in WEB-INF/role-mapping.properties. As an
> > admin I would expect to look for it in the conf folder.
> 
> I would expect a file without any explicit path information to be in the
> application's WEB-INF/ directory if the component were to be configured in
> the applications' WEB-INF/web.xml file. If it is configured in
> conf/server.xml for the server, I might expect the config file to be found
> in the server's conf/ directory. I'm not sure it's possible to detect the
> difference between the two situations from within the code. Therefore, I'd
> prefer to default to relative-to-WEB-INF but also allow (as Michael
> suggests) arbitrary file:// URI support as well as allowing ${catalina.base}
> replacement in the path to make it easy to build an installation-relative
> path.

The only way to detect the difference between those two situations is that WEB-INF/role-mapping.properties is not availabe and conf/role-mapping.properties is tried. But note that no custom value has to be set.

If this component is set output of a webapp, one could set the default lookup space to catalina_base: instead of webapp:.
Comment 20 Christopher Schultz 2020-01-24 18:39:13 UTC
(In reply to Michael Osipov from comment #19)
> (In reply to Christopher Schultz from comment #18)
> > How applicable is <security-role-ref> in web.xml, here?
> 
> As far as I know, this is per-servlet which can be very tedious and cannot
> be externalized.

*facepalm*

I didn't realize that was per-servlet. Yes, definitely not a great solution.