You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2021/06/04 14:38:11 UTC

[tomcat] branch 8.5.x updated: Fix getPrincipal logic

This is an automated email from the ASF dual-hosted git repository.

remm pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/8.5.x by this push:
     new a3c4a7c  Fix getPrincipal logic
a3c4a7c is described below

commit a3c4a7cb22800af70a2169300687e0758405b061
Author: remm <re...@apache.org>
AuthorDate: Fri Jun 4 16:28:59 2021 +0200

    Fix getPrincipal logic
    
    Also improve tests.
---
 .../apache/catalina/realm/UserDatabaseRealm.java   |  27 +--
 .../catalina/realm/TestGenericPrincipal.java       |   7 -
 .../catalina/users/MemoryUserDatabaseTests.java    | 220 +++++++++++++++++++++
 3 files changed, 234 insertions(+), 20 deletions(-)

diff --git a/java/org/apache/catalina/realm/UserDatabaseRealm.java b/java/org/apache/catalina/realm/UserDatabaseRealm.java
index eb63a5c..8622975 100644
--- a/java/org/apache/catalina/realm/UserDatabaseRealm.java
+++ b/java/org/apache/catalina/realm/UserDatabaseRealm.java
@@ -164,7 +164,16 @@ public class UserDatabaseRealm extends RealmBase {
      */
     @Override
     protected Principal getPrincipal(String username) {
-        return new UserDatabasePrincipal(username);
+        UserDatabase database = getUserDatabase();
+        if (database == null) {
+            return null;
+        }
+        User user = database.findUser(username);
+        if (user == null) {
+            return null;
+        } else {
+            return new UserDatabasePrincipal(user);
+        }
     }
 
 
@@ -241,21 +250,13 @@ public class UserDatabaseRealm extends RealmBase {
         private static final long serialVersionUID = 1L;
         private final User user;
 
-        public UserDatabasePrincipal(String username) {
-            super(username, null, null);
-            UserDatabase database = getUserDatabase();
-            if (database == null) {
-                user = null;
-            } else {
-                user = database.findUser(username);
-            }
+        public UserDatabasePrincipal(User user) {
+            super(user.getName(), null, null);
+            this.user = user;
         }
 
         @Override
         public String[] getRoles() {
-            if (user == null) {
-                return super.getRoles();
-            }
             Set<String> roles = new HashSet<>();
             Iterator<Role> uroles = user.getRoles();
             while (uroles.hasNext()) {
@@ -282,7 +283,7 @@ public class UserDatabaseRealm extends RealmBase {
                 return false;
             }
             UserDatabase database = getUserDatabase();
-            if (user == null || database == null) {
+            if (database == null) {
                 return super.hasRole(role);
             }
             Role dbrole = database.findRole(role);
diff --git a/test/org/apache/catalina/realm/TestGenericPrincipal.java b/test/org/apache/catalina/realm/TestGenericPrincipal.java
index 9cd2e04..c1507de 100644
--- a/test/org/apache/catalina/realm/TestGenericPrincipal.java
+++ b/test/org/apache/catalina/realm/TestGenericPrincipal.java
@@ -57,13 +57,6 @@ public class TestGenericPrincipal {
         doTest(gpIn);
     }
 
-    @Test
-    public void testSerialize04() throws ClassNotFoundException, IOException {
-        UserDatabaseRealm realm = new UserDatabaseRealm();
-        GenericPrincipal gpIn = realm.new UserDatabasePrincipal(USER);
-        doTest(gpIn);
-    }
-
     private void doTest(GenericPrincipal gpIn)
             throws ClassNotFoundException, IOException {
         GenericPrincipal gpOut = serializeAndDeserialize(gpIn);
diff --git a/test/org/apache/catalina/users/MemoryUserDatabaseTests.java b/test/org/apache/catalina/users/MemoryUserDatabaseTests.java
new file mode 100644
index 0000000..f8e168f
--- /dev/null
+++ b/test/org/apache/catalina/users/MemoryUserDatabaseTests.java
@@ -0,0 +1,220 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.catalina.users;
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import org.apache.catalina.User;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.apache.catalina.realm.UserDatabaseRealm;
+
+public class MemoryUserDatabaseTests {
+    private static File TEST_FILE = new File(System.getProperty("java.io.tmpdir"), "tomcat-users.xml");
+
+    private static MemoryUserDatabase db;
+
+    @BeforeClass
+    public static void createSampleDB()
+        throws Exception {
+
+        try(BufferedWriter out = new BufferedWriter(new FileWriter(TEST_FILE))) {
+            out.write("<?xml version=\"1.0\" ?>"
+                    + "<tomcat-users xmlns=\"http://tomcat.apache.org/xml\""
+                    + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
+                    + " xsi:schemaLocation=\"http://tomcat.apache.org/xml/tomcat-users.xsd\""
+                    + " version=\"1.0\">"
+                    + "<role rolename=\"testrole\" />"
+                    + "<group groupname=\"testgroup\" />"
+                    + "<user username=\"admin\" password=\"sekr3t\" roles=\"testrole, otherrole\" groups=\"testgroup, othergroup\" />"
+                    + "</tomcat-users>");
+        }
+
+        db = new MemoryUserDatabase();
+        db.setPathname(TEST_FILE.toURI().toURL().toString());
+        db.open();
+    }
+
+    @AfterClass
+    public static void cleanup() {
+        Assert.assertTrue(TEST_FILE.delete());
+    }
+
+    @Test
+    public void testLoadUserDatabase()
+        throws Exception {
+        assertPrincipalNames(new String[] { "testrole", "otherrole"}, db.getRoles());
+        assertPrincipalNames(new String[] { "testgroup", "othergroup"}, db.getGroups());
+
+        Iterator<User> users = db.getUsers();
+
+        Assert.assertTrue("No users found", users.hasNext());
+
+        User user = users.next();
+
+        Assert.assertEquals("admin", user.getName());
+        Assert.assertNull(user.getFullName());
+        Assert.assertEquals("sekr3t", user.getPassword());
+
+        assertPrincipalNames(new String[] { "testrole", "otherrole"}, user.getRoles());
+        assertPrincipalNames(new String[] { "testgroup", "othergroup"}, user.getGroups());
+    }
+
+    public void testReloadUserDatabase()
+        throws Exception {
+        // Change the database on the disk and reload
+
+        try(BufferedWriter out = new BufferedWriter(new FileWriter(TEST_FILE))) {
+            out.write("<?xml version=\"1.0\" ?>"
+                    + "<tomcat-users xmlns=\"http://tomcat.apache.org/xml\""
+                    + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
+                    + " xsi:schemaLocation=\"http://tomcat.apache.org/xml/tomcat-users.xsd\""
+                    + " version=\"1.0\">"
+                    + "<role rolename=\"foo\" />"
+                    + "<group groupname=\"bar\" />"
+                    + "<user username=\"root\" password=\"sup3Rsekr3t\" roles=\"foo, bar\" groups=\"bar, foo\" />"
+                    + "</tomcat-users>");
+
+            db.open();
+        }
+
+        assertPrincipalNames(new String[] { "foo", "bar"}, db.getRoles());
+        assertPrincipalNames(new String[] { "bar", "foo"}, db.getGroups());
+
+        Iterator<User> users = db.getUsers();
+
+        Assert.assertTrue("No users found", users.hasNext());
+
+        User user = users.next();
+
+        Assert.assertEquals("root", user.getName());
+        Assert.assertNull(user.getFullName());
+        Assert.assertEquals("sup3Rsekr3t", user.getPassword());
+
+        assertPrincipalNames(new String[] { "foo", "bar"}, user.getRoles());
+        assertPrincipalNames(new String[] { "bar", "foo"}, user.getGroups());
+    }
+
+    @Test
+    public void testMultithreadedMutateUserDatabase()
+        throws Exception {
+        // Generate lots of concurrent load on the user database
+        Runnable job = new Runnable() {
+            @Override
+            public void run() {
+                for(int i=0; i<10; ++i) {
+                  db.createUser("newUser-" + Thread.currentThread().getName() + "-" + i, "x", null);
+                }
+            }
+        };
+
+        int numThreads = 100;
+        Thread[] threads = new Thread[numThreads + 1];
+        for(int i=0; i<numThreads; ++i) {
+          threads[i] = new Thread(job);
+        }
+
+        // Let's
+        threads[numThreads] = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                try { db.open(); }
+                catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        });
+
+        ++numThreads;
+
+        for(int i=0; i<numThreads; ++i) {
+          threads[i].start();
+        }
+
+        for(int i=0; i<numThreads; ++i) {
+          threads[i].join();
+        }
+
+        // Remove all those extra users
+        Iterator<User> users = db.getUsers();
+        for(; users.hasNext();) {
+            User user = users.next();
+            if(user.getUsername().startsWith("newUser")) {
+              db.removeUser(user);
+            }
+        }
+
+        users = db.getUsers();
+
+        Assert.assertTrue("No users found", users.hasNext());
+
+        User user = users.next();
+
+        Assert.assertEquals("admin", user.getName());
+        Assert.assertNull(user.getFullName());
+        Assert.assertEquals("sekr3t", user.getPassword());
+
+        assertPrincipalNames(new String[] { "testrole", "otherrole"}, user.getRoles());
+        assertPrincipalNames(new String[] { "testgroup", "othergroup"}, user.getGroups());
+    }
+
+    @Test
+    public void testSerializePrincipal()
+        throws Exception {
+        UserDatabaseRealm realm = new UserDatabaseRealm();
+        User user = db.findUser("admin");
+        GenericPrincipal gpIn = realm.new UserDatabasePrincipal(user);
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(bos);
+        oos.writeObject(gpIn);
+
+        byte[] data = bos.toByteArray();
+
+        ByteArrayInputStream bis = new ByteArrayInputStream(data);
+        ObjectInputStream ois = new ObjectInputStream(bis);
+        GenericPrincipal gpOut =  (GenericPrincipal) ois.readObject();
+
+        Assert.assertEquals("admin", gpOut.getName());
+        assertPrincipalNames(gpOut.getRoles(), user.getRoles());
+    }
+
+    private void assertPrincipalNames(String[] expectedNames, Iterator<? extends Principal> i) {
+        HashSet<String> names = new HashSet<>(Arrays.asList(expectedNames));
+
+        int j=0;
+        while(i.hasNext()) {
+            Assert.assertTrue(names.contains(i.next().getName()));
+            j++;
+        }
+
+        Assert.assertEquals(expectedNames.length, j);
+    }
+}

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