Hi Chris,

On 2025/05/28 14:23:56 Christopher Schultz wrote:
> Michael,
> 
> On 5/26/25 9:14 AM, Michael Osipov wrote:
> > Hi folks,
> > 
> > I seek guidance on a larger problem I need to solve where I do have a few 
> > ideas,
> > but am also considering to what degree it would make sense to add code to 
> > the
> > Tomcat codebase for the common good:
> > 
> > I have a realm impl called MyRealm which sources from "store A", is has 
> > roles
> > (groups) in a specific format and user attributes. It returns MyPrincipal.
> > Consider you have a webapp which has logical roles "user", "editor", 
> > "admin",
> > etc. and also uses those specific attributes. The webapp context maps the
> > roles from "store A" into the logical roles with the 
> > PropertiesRoleMappingListener.
> > 
> > Now an additional MyRealm with "store B" comes into play. Of course, the
> > CombinedRealm works perfectly, but "store B" has different role names and
> > different attribute names.
> > 
> > The problem: Both "String Context#findRoleMapping(String)" and
> > "#addRoleMapping(String, String)" do not support 1:n mapping, e.g.,
> > "user" role maps to "store_a_role_1" and "store_b_role_5".
> > This would require changing/extending the interface and other classes.
> > The other problem is, of course, realm-specific. Say "store A" has attribute
> > "gid" which is semantically identically identical "store B" attribute
> > "employeeID". From an application PoV this is a consolidation nightmare
> > to touch every single spot to accommodate that.
> > 
> > My idea is going from:
> > 
> > <CombinedRealm>
> >    <MyRealm source="store A" />
> >    <MyRealm source="store B" />
> > </CombinedRealm>
> > 
> > to
> > 
> > <TransformingRealm roleMapper=... attributeMapper=...>
> >    <CombinedRealm>
> >      <MyRealm source="store A" />
> >      <MyRealm source="store B" />
> >    </CombinedRealm>
> > </TransformingRealm>
> > 
> > While the attributeMapper cannot be part of Tomcat because it is 
> > realm-specific,
> > do you see a benefit of modifying Context to accommodating 1:n mappings and 
> > of
> > course the aftermath?
> > Let me know your opinion whether this is of good use for the Tomcat code 
> > base.
> > 
> > For the same of completeness, I cannot add "user1", etc. to the application
> > because it will require some hefty code changes as well.
> 
> I must admit I've never used the role-mapping capabilities of the 
> servlet context before; I've only written applications that use the 
> one-and-only-one set of roles exposed by my user database. So perhaps my 
> comments come from a position of ignorance to your particular situation.
> 
> It seems to me that this can be entirely fixed by using a custom 
> Principal object: one that is already under the control of the Realm.
> 
> public class MyRealm extends RealmBase {
>    public Principal authenticate(...) {
>      ...
>      return new CustomPrincipal(...);
>    }
> 
>    public boolean isInRole(Wrapper wrapper, Principal principal, String 
> role) {
>      if(principal instanceof CustomPrincipal
>         && ((CustomPrincipal)principal).isMine(this) {
>        return super.isInRole(reverseMapRole(role));
>      } else {
>        // Principal is not from this Realm
> 
>        return false;
>      }
>    }
> 
>    protected String reverseMapRole(String role) {
>      if("user".equals(role)) {
>        // Obviously, implement this as a configurable Map
>        return "CN=users,OU=groups,DC=example,DC=org";
>      } else {
>        return role;
>    }
> 
>    public class CustomPrincipal extends GenericPrincipal {
>      private boolean isMine(MyRealm realm) {
>        return realm == MyRealm.this;
>      }
>      ...
>    }
> }
> 
> You can use the same class MyRealm for both of your Realms, each with a 
> different configuration. Since Tomcat already supports any attribute you 
> want to configure, just do something like:
> 
>     <Realm class="com.example.authn.MyRealm"
>        roleMappings="user=CN=users,OU=groups,DC=example,DC=org; 
> editor=CN=editors,OU=groups,DC=example,DC=org"; and so on" />
> 
> Would what I have above work for you? It doesn't work for an application 
> that tries to manually perform reverse-role-mapping (because the Context 
> doesn't know about these mappings), but without changes to Jakarta EE 
> APIs, the application will /never/ be able to do this.

Thanks for your input. I have actually ended up doing the following:
> <Realm 
> className="com.innomotics.dynamowerk.tomcat.realm.PrincipalTransformingRealm">
>       <Realm className="net.sf.michaelo.tomcat.realm.ActiveDirectoryRealm" 
> connectionPoolSize="5"
>               dirContextSourceName="gc/ad001.siemens.net" 
> additionalAttributes="displayName,siemens-gid" />
>       <Realm className="net.sf.michaelo.tomcat.realm.ActiveDirectoryRealm" 
> connectionPoolSize="5"
>               dirContextSourceName="gc/innomotics.net" 
> additionalAttributes="displayName,extensionAttribute6" />
> </Realm>

and the realm is:
https://gist.github.com/michael-o/39dff88679427badf2e617bf2285b437

I will look later into Tomcat code whether the one-to-many mapping can be 
added. The benefit is that if you have many groups for the same role they can 
be managed by individual groups from different departments in a central portal. 
All you need is to add them one to your application and the rest is 
self-service. The app will treat both equally.

Michael

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to