| /* |
| * 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.File; |
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.net.URI; |
| import java.security.Principal; |
| 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.tomcat.util.file.ConfigFileLoader; |
| import org.apache.tomcat.util.file.ConfigurationSource; |
| |
| 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>"); |
| } |
| |
| // MemoryUserDatabase requires the use of ConfigFileLoader/ConfigurationSource |
| ConfigFileLoader.setSource(new ConfigurationSource() { |
| protected final File userDir = new File(System.getProperty("java.io.tmpdir")); |
| protected final URI userDirUri = userDir.toURI(); |
| @Override |
| public Resource getResource(String name) throws IOException { |
| File f = new File(name); |
| if (!f.isAbsolute()) { |
| f = new File(userDir, name); |
| } |
| if (f.isFile()) { |
| return new Resource(new FileInputStream(f), f.toURI()); |
| } else { |
| throw new FileNotFoundException(name); |
| } |
| } |
| @Override |
| public URI getURI(String name) { |
| File f = new File(name); |
| if (!f.isAbsolute()) { |
| f = new File(userDir, name); |
| } |
| if (f.isFile()) { |
| return f.toURI(); |
| } |
| return userDirUri.resolve(name); |
| } |
| }); |
| |
| db = new MemoryUserDatabase(); |
| db.setPathname(TEST_FILE.getAbsolutePath()); |
| 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()); |
| } |
| |
| private void assertPrincipalNames(String[] expectedNames, Iterator<? extends Principal> i) |
| { |
| HashSet<String> names = new HashSet<>(expectedNames.length); |
| for(String name : expectedNames) |
| names.add(name); |
| |
| int j=0; |
| while(i.hasNext()) { |
| Assert.assertTrue(names.contains(i.next().getName())); |
| j++; |
| } |
| |
| Assert.assertEquals(expectedNames.length, j); |
| } |
| } |