This is an automated email from the ASF dual-hosted git repository. michaelo pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/main by this push: new c3edf43 Add support for additional user attributes in TomcatPrincipal c3edf43 is described below commit c3edf437da20af0f11edc0ad6d893399b01e6287 Author: Carsten Klein <c.kl...@datagis.com> AuthorDate: Wed Jan 12 15:06:42 2022 +0100 Add support for additional user attributes in TomcatPrincipal This closes #463 --- java/org/apache/catalina/TomcatPrincipal.java | 28 +++++++++++++ .../apache/catalina/realm/GenericPrincipal.java | 46 ++++++++++++++++++---- java/org/apache/catalina/realm/JNDIRealm.java | 2 +- webapps/docs/changelog.xml | 5 +++ webapps/examples/jsp/security/protected/index.jsp | 44 +++++++++++++++++++++ 5 files changed, 117 insertions(+), 8 deletions(-) diff --git a/java/org/apache/catalina/TomcatPrincipal.java b/java/org/apache/catalina/TomcatPrincipal.java index 83f9035..1e3d9f6 100644 --- a/java/org/apache/catalina/TomcatPrincipal.java +++ b/java/org/apache/catalina/TomcatPrincipal.java @@ -17,6 +17,8 @@ package org.apache.catalina; import java.security.Principal; +import java.util.Collections; +import java.util.Enumeration; import org.ietf.jgss.GSSCredential; @@ -47,4 +49,30 @@ public interface TomcatPrincipal extends Principal { * exception to LoginContext */ void logout() throws Exception; + + /** + * Returns the value of the named attribute as an <code>Object</code>, or + * <code>null</code> if no attribute of the given name exists, or if + * <code>null</code> has been specified as the attribute's name. + * <p> + * Only the servlet container may set attributes to make available custom + * information about a Principal or the user it represents. + * + * @param name a <code>String</code> specifying the name of the attribute + * @return an <code>Object</code> containing the value of the attribute, or + * <code>null</code> if the attribute does not exist, or if + * <code>null</code> has been specified as the attribute's name + */ + Object getAttribute(String name); + + /** + * Returns an <code>Enumeration</code> containing the names of the + * attributes available to this Principal. This method returns an empty + * <code>Enumeration</code> if the Principal has no attributes available to + * it. + * + * @return an <code>Enumeration</code> of strings containing the names of + * the Principal's attributes + */ + Enumeration<String> getAttributeNames(); } diff --git a/java/org/apache/catalina/realm/GenericPrincipal.java b/java/org/apache/catalina/realm/GenericPrincipal.java index 7260da4..584c104 100644 --- a/java/org/apache/catalina/realm/GenericPrincipal.java +++ b/java/org/apache/catalina/realm/GenericPrincipal.java @@ -19,7 +19,10 @@ package org.apache.catalina.realm; import java.io.Serializable; import java.security.Principal; import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; import java.util.List; +import java.util.Map; import javax.security.auth.login.LoginContext; @@ -120,7 +123,7 @@ public class GenericPrincipal implements TomcatPrincipal, Serializable { */ public GenericPrincipal(String name, List<String> roles, Principal userPrincipal, LoginContext loginContext) { - this(name, roles, userPrincipal, loginContext, null); + this(name, roles, userPrincipal, loginContext, null, null); } /** @@ -140,7 +143,7 @@ public class GenericPrincipal implements TomcatPrincipal, Serializable { @Deprecated public GenericPrincipal(String name, String password, List<String> roles, Principal userPrincipal, LoginContext loginContext) { - this(name, roles, userPrincipal, loginContext, null); + this(name, roles, userPrincipal, loginContext, null, null); } /** @@ -154,10 +157,12 @@ public class GenericPrincipal implements TomcatPrincipal, Serializable { * @param loginContext - If provided, this will be used to log out the user * at the appropriate time * @param gssCredential - If provided, the user's delegated credentials + * @param attributes - If provided, additional attributes associated with + * this Principal */ public GenericPrincipal(String name, List<String> roles, Principal userPrincipal, LoginContext loginContext, - GSSCredential gssCredential) { + GSSCredential gssCredential, Map<String, Object> attributes) { super(); this.name = name; this.userPrincipal = userPrincipal; @@ -171,6 +176,7 @@ public class GenericPrincipal implements TomcatPrincipal, Serializable { } this.loginContext = loginContext; this.gssCredential = gssCredential; + this.attributes = attributes != null ? Collections.unmodifiableMap(attributes) : null; } @@ -193,7 +199,7 @@ public class GenericPrincipal implements TomcatPrincipal, Serializable { public GenericPrincipal(String name, String password, List<String> roles, Principal userPrincipal, LoginContext loginContext, GSSCredential gssCredential) { - this(name, roles, userPrincipal, loginContext, gssCredential); + this(name, roles, userPrincipal, loginContext, gssCredential, null); } @@ -254,6 +260,11 @@ public class GenericPrincipal implements TomcatPrincipal, Serializable { this.gssCredential = gssCredential; } + /** + * The additional attributes associated with this Principal. + */ + protected final Map<String, Object> attributes; + // ---------------------------------------------------------- Public Methods @@ -304,10 +315,28 @@ public class GenericPrincipal implements TomcatPrincipal, Serializable { } + @Override + public Object getAttribute(String name) { + if (attributes == null || name == null) { + return null; + } + return attributes.get(name); + } + + + @Override + public Enumeration<String> getAttributeNames() { + if (attributes == null) { + return Collections.emptyEnumeration(); + } + return Collections.enumeration(attributes.keySet()); + } + + // ----------------------------------------------------------- Serialization private Object writeReplace() { - return new SerializablePrincipal(name, roles, userPrincipal); + return new SerializablePrincipal(name, roles, userPrincipal, attributes); } private static class SerializablePrincipal implements Serializable { @@ -316,9 +345,10 @@ public class GenericPrincipal implements TomcatPrincipal, Serializable { private final String name; private final String[] roles; private final Principal principal; + private final Map<String, Object> attributes; public SerializablePrincipal(String name, String[] roles, - Principal principal) { + Principal principal, Map<String, Object> attributes) { this.name = name; this.roles = roles; if (principal instanceof Serializable) { @@ -326,10 +356,12 @@ public class GenericPrincipal implements TomcatPrincipal, Serializable { } else { this.principal = null; } + this.attributes = attributes; } private Object readResolve() { - return new GenericPrincipal(name, Arrays.asList(roles), principal); + return new GenericPrincipal(name, Arrays.asList(roles), principal, null, null, + attributes); } } } diff --git a/java/org/apache/catalina/realm/JNDIRealm.java b/java/org/apache/catalina/realm/JNDIRealm.java index a9dac4a..e971439 100644 --- a/java/org/apache/catalina/realm/JNDIRealm.java +++ b/java/org/apache/catalina/realm/JNDIRealm.java @@ -2516,7 +2516,7 @@ public class JNDIRealm extends RealmBase { } if (user != null) { - return new GenericPrincipal(user.getUserName(), roles, null, null, gssCredential); + return new GenericPrincipal(user.getUserName(), roles, null, null, gssCredential, null); } return null; diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 3a22409..bd2a124 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -123,6 +123,11 @@ is not supported by the configured providers as will be the case for a FIPS compliant configuration. (markt) </fix> + <add> + <pr>463</pr>: Add support for additional user attributes to + <code>TomcatPrincipal</code> and <code>GenericPrincipal</code>. + Patch provided by Carsten Klein. (michaelo) + </add> <fix> <pr>469</pr>: Include the Jakarata Annotations API in the classes that Tomcat will not load from web applications. Pull request provided by diff --git a/webapps/examples/jsp/security/protected/index.jsp b/webapps/examples/jsp/security/protected/index.jsp index 31122eb..75ac4bc 100644 --- a/webapps/examples/jsp/security/protected/index.jsp +++ b/webapps/examples/jsp/security/protected/index.jsp @@ -15,6 +15,8 @@ limitations under the License. --%> <%@ page import="java.util.Enumeration" %> +<%@ page import="java.security.Principal" %> +<%@ page import="org.apache.catalina.TomcatPrincipal" %> <% if (request.getParameter("logoff") != null) { session.invalidate(); @@ -73,6 +75,48 @@ enter it here: </form> <br><br> +<% + Principal p = request.getUserPrincipal(); + if (!(p instanceof TomcatPrincipal)) { +%> +<p>The principal does not support attributes.</p> +<% + } else { + TomcatPrincipal principal = (TomcatPrincipal) p; +%> +<p>The principal contains the following attributes:</p> +<table> +<tr><th>Name</th><th>Value</th><th>Type</th></tr> +<% + Enumeration<String> names = principal.getAttributeNames(); + while (names.hasMoreElements()) { + String name = names.nextElement(); + Object value = principal.getAttribute(name); + String type = value != null ? value.getClass().getName() : "unknown"; + if (value instanceof Object[]) { + Object[] values = (Object[]) value; + value = ""; + for (int i = 0; i < values.length; i++) { + value += values[i] + "<br/>"; + } + if (values.length > 0) { + type = values[0].getClass().getName() + "[]"; + } else { + type = "unknown"; + } + } + type = type.replaceFirst("^java\\.lang\\.", ""); +%> +<tr><td><%= name %></td><td><%= value %></td><td><%= type %></td> +<% + } +%> +</table> +<% + } +%> +<br><br> + To add some data to the authenticated session, enter it here: <form method="GET" action='<%= response.encodeURL("index.jsp") %>'> <input type="text" name="dataName"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org