Hi Mark,

thanks for sharing your ideas :)

On 26/05/2021 19:56, Mark Thomas wrote:

Given that the attributes may well be security related, you would need to make sure neither the Map nor any of the keys/values could be modified. Protecting the Map is easy. Protecting the keys/values is a little trickier. For that reason I'd lean towards the solution below.

Oh yes, these attributes should likely be immutable. Since I still believe that Enumerations are kind of uncomfortable (and outdated?), what about strictly relying on Collections.unmodifiableMap?

But, I'm ok with getAttribute(String name) and getAttributeNames() pair as well. You decide :)

My first idea was to allow users to put their own attributes as well. But then, we'd need to track Realm-sourced attribute names and make those read-only in a setAttribute method. Since users could as well put their stuff into session attributes, making the whole map immutable is possible and clearly much simpler.

2. Should I add attributes-related public methods to the TomcatPrincipal interface as well?

Yes. So far the only Tomcat specific extensions are for SPNEGO but this is in the same category. The other option would be a new interface but I don't see a need for that.

Since UserDatabasePrincipal is a private inner class of UserDatabaseRealm, no instanceof checks are possible to determine whether attributes may be available or not. So, I was thinking of a new interface

public interface AttributedPrincipal extends Principal {

  public Object getAttribute(String name);

  Enumeration<String> getAttributeNames();

}

That interface has a slightly more meaningful name for consumers of additional user attributes. But adding these methods to TomcatPrincipal is good as well.


3. Class UserDatabasePrincipal in UserDatabaseRealm

Why does UserDatabaseRealm pass a userPrincipal of type UserDatabasePrincipal? Can't we just drop that and do it like JNDIRealm or DataSourceRealm?

I don't see any obvious reason. I'll do some digging in the source history to see if I can find out why. Absent a good reason, I'd say drop it.

There is a good reason for it, but I think it should be possible to drop it.

It is there because the UserDatabaseRealm supports the concepts of groups. Users can have roles assigned directly or users can be assigned to a group and inherit the roles of the group. This means hasRole() is a little more complicated and the UserDatabasePrincipal is used to determine if this additional processing is required.

I think this could be replaced by a "org.apache.catalina.realm.UserDatabaseRealm.groups" attribute which would remove the need for the dedicated UserDatabasePrincipal

Honestly, I don't see that in the code. What I see is, that UserDatabaseRealm resolves roles coming from groups up front in its getPrincipal method. After that, it just creates an ordinary GenericPrincipal instance with a single list of effective roles.

The associated UserDatabasePrincipal does nothing special with hasRole(). Its only method is getName(). So, it just removes or "hides" any special GenericPrincipal methods like hasRole() and getRoles() from the user (aka from the Servlet code, internally Tomcat still uses the surrounding GenericPrincipal, e. g. for authorization).

So, the only thing UserDatabasePrincipal does, is to hide the fact that groups have already been resolved to a single list of effective roles, the Principal is working with during its lifetime. Did I overlook something?

Actually, when declaring the attributes-related methods in a public interface (either TomcatPrincipal or AttributedPrincipal), adding that interface to UserDatabasePrincipal is not expensive. So, we could always decide to leave that UserDatabasePrincipal in place and let it implement that interface.

However, in order to not "pollute" UserDatabasePrincipal with unneeded methods, I'd vote for using a new org.apache.catalina.AttributedPrincipal interface.

Additionally, class UserDatabasePrincipal is NOT serializable. That means, it gets dropped when sessions and principals get persisted and reloaded. That applies to session persistence across restarts (with persistAuthentication set to true) and likely to clustering/HA. That's not fatal, but after a restart or when running on a different cluster node, users suddenly get a full-blown GenericPrincipal instance when they call Request.getUserPrincipal(). However, since nobody complained about it, the UserDatabasePrincipal is likely not so important :-p

Carsten

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

Reply via email to