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 <r...@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-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org