Bug 55477

Summary: Add a solution to map an 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    
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.