You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Carsten Klein <c....@datagis.com> on 2021/04/08 20:08:07 UTC

Getting additional attributes for logged on users

Hi there,

from a servlet, the logged on user is represented by a Principal 
instance, which has a getName() to get the logon name of that user. In 
most cases, that is a more or less cryptic name like c.klein or m.scott.

Some of our customers like the name of the currently logged on user be 
displayed in the application's GUI. We all know that from many popular 
applications.

While relying on the Servlet specs only, we can just show that 
non-user-friendly logon name. Our customers prefer seeing the user's 
display name. Other attributes of the user, like e-mail address, phone 
number, department etc., is often welcome (if not required) information 
during an application's lifetime.

It's not too hard to hook into session initialization and get the 
required extra information, for example through JDBC or JNDI, if the 
user database is actually an Active Directory Server. That information 
can then be stored in the user's session attributes map.

However, one has to implement that information retrieval "by hand" for 
every application and/or customer. Even worse, typically credentials are 
required to access the storage in which that information lives. If it's 
in the application's 'standard' database, there's a good chance to have 
a Tomcat connection pool. However, in general, you need credentials and 
access data to get these additional attributes (credentials and JDBC URL 
may be configured in Context or Servlet parameters).

Does anybody know a more general way to get such extra user attributes?


My proposal:

Typically, those desired extra attributes are stored in the user's 
record in the user database. That may be a SQL database or may be an 
Active Directory Server (or any other directory), which is already used 
for authentication and authorization.

Wouldn't it be cool to make the Realm get us that extra information?

Why the realm?

First, in order to perform authentication, the Realm already has access 
to the user database. So, access data and credentials must not be 
configured twice at different places.

Second, the Realm knows how to query the user database and does that 
already for retrieving roles and passwords. Getting some more fields 
shouldn't be a big deal.

Third, the Realm actually creates and initializes the Principal instance 
so, it should be easy to store these extra user attributes in an 
extended version of the TomcatPrincipal class. A simple Map<String, 
String> should be sufficient, but for the sake of uniformity, the well 
known methods getAttribute, getAttributeNames, removeAttribute and 
setAttribute may be a better option.

That's clearly something not all Realms can/shall support. Likely 
JAASRealm will not, since it uses custom Principal classes. But 
JNDIRealm, JDBCRealm and DataSourceRealm (not yet sure about 
UserDatabaseRealm) could easily support that feature.

In its simplest form, these Realms get a new configuration property 
'extraAttributes', which takes a comma separated list of field names to 
retrieve. Implicitly, for an SQL-based Realm, these fields are queried 
from the 'userTable' table. The JNDIRealm tries to find these attributes 
from the user's entry in the directory, of course.

More complex configurations are possible (but likely not needed).

I'm curious what you think about it :)

Carsten

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


Re: Getting additional attributes for logged on users

Posted by Carsten Klein <c....@datagis.com>.
Hi there,

are there other comments on that? I'd like to implement this and want to 
provide a CR On GitHub, if there is a fair chance, that this enhancement 
will make it into Tomcat :)

Trying to summarize what has been discussed so far: (read the other 
posts for more information)

The basic idea is to obtain additional user attributes and providing 
these to the application through an "attributes" map of the Principal 
class (e. g. the user's display name, e-mail address, etc.).

Since such user (-related) data is often available in data stores also 
used for authentication, it shall be up to the Realm to query these 
extra attributes. (Additionally, the Realm already has access data and 
credentials to access that data store and also creates and populates the 
Principal instance.)

The provided extra user information is not crucial for the Realm and its 
authentication and authorization process.

Olaf Kock was suggesting to agree upon a set of "standard" additional 
user attributes, which the Realm should query for by default. However, 
for at least these reasons, I believe that this is just not possible:

1. Every application's needs are different
2. Every user data store is different
3. Cultural differences may require different attributes to form names 
or addresses, for example

In contrast to that, my initial idea was to specify the desired extra 
user attributes as a comma separated list though a new configuration 
option of the Realm (called "extraAttributes" or "userAttributes"). This 
list is nearly equivalent to a SELECT clause in SQL. However, that 
"SELECT clause" shall work as well with Realms not based on SQL.

Not all Realms can/shall support that optional new feature. For example, 
JAASRealm, which is merely a wrapper around an arbitrary authentication 
and authorization process behind the curtain, likely cannot participate 
in this.

The queried attributes shall be provided to the application through a 
new "attributes" map of the Principal instance. Accessors to this map 
should be declared in either TomcatPrincipal or GenericPrincipal. Still 
to discuss, what accessors to implement:

Map<String, Object> getUserAttributesMap() {}

vs.

Object getUserAttribute(String name)
String[] getUserAttributeNames()
void setUserAttribute(String name, Object o)
void removeUserAttribute(String name)

The attribute names specified in the configuration option (SELECT 
clause) must be the actual field names of the attribute, of course. 
These also form the names/keys of the attributes in the Principal's 
attribute map (could/should be prefixed with a namespace or prefix):

Realm-Configuration:
userAttributes="attr1, displayName, dept_no"

Using the attributes:
String s1 = principal.getUserAttribute("attr1")

// with a namespace/prefix (configurable and with a default value?)
String s2 = principal.getUserAttribute("realm.usrattr.displayName")


I believe that implementing the discussed enhancement is not too 
difficult, since only (some of) the Realm classes as well as the 
Principal implementation must be modified (TomcatPrincipal and/or 
GenericPrincipal). Also, I do not see any security related risks.

Carsten

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


Re: Getting additional attributes for logged on users

Posted by Carsten Klein <c....@datagis.com>.
Hi Olaf,

also, I only picked your statements for an answer.

> On 08.04.21 13:53, Olaf Kock wrote:
> 
> It would be cool, absolutely.
> 
> Even cooler if "the desired extra attributes" could be agreed upon - or
> even what would be desirable in user management (is user + roles enough?
> That requires redeployment any time the system gets more picky with
> permissions.
> 
> Personally, I work with Liferay, where roles are runtime-configurable
> and map to permissions. The permissions are what's checked in the
> application code, and the applications couldn't care less about number
> of roles or path through which a permission is assigned to a user.

I'm not sure whether I got you right. For my mind, my idea has nothing 
to do with authorization, roles and permissions. Also, I don't think 
that the set of desired extra attributes is something that could be 
agreed upon. It's rather very specific for a project and/or customer.

The basic idea is just to get some of the user's attributes/properties 
for (any/free) usage by the application. Actually this proposal only
(ab)uses the Realm, since it already has configured access to a storage, 
that one might call the 'user database'.

However, these attributes are only used by the application. These are 
not used for authorization or grant of permissions.

> 
> You first state "its simplest form", then state that more complex
> solutions are likely not needed.
> 
> I'd argue that the current form is "the simplest form", as it provides
> identifiers that can be used to look up extra information according to
> the application's need.

What can be simpler than a comma separated list of field names? If we 
can agree upon the set of desired user attributes (which we can't 
surely), no configuration will be required. That's would be simpler but 
won't work, since every user database is different and desires are too.

> 
> I don't want to tear down your idea - only reflect that "only a little
> bit more" will be barely enough for the next person coming around, and
> end up being a really complex beast. And if you look at all the
> different available attributes for users that make sense in some, but
> not in other countries/cultures, you'll soon be implementing your own
> anyway:
> 
> * What makes up the name? First/Last Name? Including middle name (common
> in US, almost nonsensical in Germany)? There are cultures with just a
> single name
> * Gender: How many choices and what will they be named (by law, Germany
> now has 3 genders)
> * Address: I've recently sent out letters to international addresses,
> and boy was it hard to ask for the right information to go to the
> address sticker.
> * Department: Makes sense in a business environment, not at all in a
> community environment

That's why I recommend that the desired attributes must be specified in 
a list. That list can be seen as the SELECT clause of an SQL statement 
(but this will work with an Active Directory Server and likely 
tomcat-users.xml as well).

In one of our projects, we authenticate users against the customer's 
Active Directory Server. The sAMAccountName attribute is used as the 
user's logon name. That's what the principal returns in its getName() 
method. For example, we output that name in the footer of printed 
reports. On reports created by me, 'c.klein' is shown.

In the ADS, my user class also has these attributes: (among many others)

displayName: ext. Klein, Carsten
givenName:   Carsten
name:        ext. Klein, Carsten
sn:          Klein

(ext. = I'm an external user)

So, in order to show a more user-friendly name on the reports, I'd 
configure the extraAttributes list to contain attribute 'displayName'. 
Since our reports are template driven, I could as well retrieve fields 
'givenNamen' and 'sn' and build my on report specific display name like 
'${givenName} ${sn}' (with the knowledge in mind, that it's a German 
customer and names in Germany typically are written that way).


> While you name some samples that sound agreeable on first sight, I don't
> think that they're agreeable enough to impose them on people unless
> provided voluntarily and under arbitrary names. Which ends up with the
> cost of a huge framework in order to potentially save a single database
> request per log in.

I guess, we will never find a bunch of attributes everybody can agree 
with in all countries, companies and projects. So, there will likely 
never be a mechanism that provides extra user attributes voluntarily. 
But that was never announced. Some minimal and simple configuration is 
still required.

For the same reason these attributes cannot be provided under arbitrary 
names. But we could simply use the configured field names (which must be 
the actual field names):

Config:
extraAttributes="displayName, givenName, sn"

Code: (no safe type checks here)
Principal p = ((TomcatPrincipal) request.getUserPrincipal());
out.writeln(p.getAttribute("displayName"));


It's not about saving a single database request per log in (at least not 
from a performance point of view, technically, the request must be made 
anyway).

But, it's about a simple, safe and reproducible way to get additional 
fields from the user's record in the user database by just specifying 
field names in a simple list. This can be done (and later changed) by 
configuration only. No class has to be written. No extra configuration 
for accessing the user database must be provided. No knowledge of SQL or 
LDAP queries is required.

That's what this proposal offers: generic configurable retrieval of 
extra attributes from the user's record in the user database. Nothing 
more and nothing less. There's no room for an Extrawurst. If someone 
want's "only a little bit more", he's free to leave the Relam's 
attribute 'extraAttributes' empty and run his own mechanism.

Finally, I don't think that implementing this requires too much work (I 
don't see the beast in it nor do I see a huge framework). If we stick to 
the above offering, it's only about some additions to the Realm classes, 
the TomcatPrincipal interface (optionally) and the GenericPrincipal class.


Carsten

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


Re: Getting additional attributes for logged on users

Posted by Olaf Kock <to...@olafkock.de>.
Hi Carsten,

I'll be limiting my answer to the most notable lines and quote only those.

(anybody else reading this without following the mails live: Go to the
archive to see Carsten's full post)


On 08.04.21 22:08, Carsten Klein wrote:
>
> Typically, those desired extra attributes are stored in the user's
> record in the user database. That may be a SQL database or may be an
> Active Directory Server (or any other directory), which is already
> used for authentication and authorization.
>
> Wouldn't it be cool to make the Realm get us that extra information?

It would be cool, absolutely.

Even cooler if "the desired extra attributes" could be agreed upon - or
even what would be desirable in user management (is user + roles enough?
That requires redeployment any time the system gets more picky with
permissions.

Personally, I work with Liferay, where roles are runtime-configurable
and map to permissions. The permissions are what's checked in the
application code, and the applications couldn't care less about number
of roles or path through which a permission is assigned to a user.

> In its simplest form, these Realms get a new configuration property
> 'extraAttributes', which takes a comma separated list of field names
> to retrieve. Implicitly, for an SQL-based Realm, these fields are
> queried from the 'userTable' table. The JNDIRealm tries to find these
> attributes from the user's entry in the directory, of course.
>
> More complex configurations are possible (but likely not needed).

You first state "its simplest form", then state that more complex
solutions are likely not needed.

I'd argue that the current form is "the simplest form", as it provides
identifiers that can be used to look up extra information according to
the application's need.

I don't want to tear down your idea - only reflect that "only a little
bit more" will be barely enough for the next person coming around, and
end up being a really complex beast. And if you look at all the
different available attributes for users that make sense in some, but
not in other countries/cultures, you'll soon be implementing your own
anyway:

* What makes up the name? First/Last Name? Including middle name (common
in US, almost nonsensical in Germany)? There are cultures with just a
single name
* Gender: How many choices and what will they be named (by law, Germany
now has 3 genders)
* Address: I've recently sent out letters to international addresses,
and boy was it hard to ask for the right information to go to the
address sticker.
* Department: Makes sense in a business environment, not at all in a
community environment

While you name some samples that sound agreeable on first sight, I don't
think that they're agreeable enough to impose them on people unless
provided voluntarily and under arbitrary names. Which ends up with the
cost of a huge framework in order to potentially save a single database
request per log in.

E.g.: It would be cool, but I don't see it worth the price.

my 2 (Euro) Cent

Olaf



>
> I'm curious what you think about it :)
>
> Carsten
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>

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