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

Reply via email to