You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2018/09/14 12:36:59 UTC

svn commit: r1840917 - in /tomcat/trunk: java/org/apache/catalina/users/ webapps/docs/

Author: markt
Date: Fri Sep 14 12:36:58 2018
New Revision: 1840917

URL: http://svn.apache.org/viewvc?rev=1840917&view=rev
Log:
Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=58590
Monitor the source for a MemoryUserdatabase (typically tomcat-users.xml) and re-load it it a change is detected.

Modified:
    tomcat/trunk/java/org/apache/catalina/users/LocalStrings.properties
    tomcat/trunk/java/org/apache/catalina/users/MemoryUserDatabase.java
    tomcat/trunk/java/org/apache/catalina/users/MemoryUserDatabaseFactory.java
    tomcat/trunk/webapps/docs/changelog.xml
    tomcat/trunk/webapps/docs/jndi-resources-howto.xml

Modified: tomcat/trunk/java/org/apache/catalina/users/LocalStrings.properties
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/users/LocalStrings.properties?rev=1840917&r1=1840916&r2=1840917&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/users/LocalStrings.properties [UTF-8] (original)
+++ tomcat/trunk/java/org/apache/catalina/users/LocalStrings.properties [UTF-8] Fri Sep 14 12:36:58 2018
@@ -20,6 +20,8 @@ memoryUserDatabase.nullGroup=Null or zer
 memoryUserDatabase.nullRole=Null or zero length role name specified. The role will be ignored.
 memoryUserDatabase.nullUser=Null or zero length user name specified. The user will be ignored.
 memoryUserDatabase.readOnly=User database has been configured to be read only. Changes cannot be saved
+memoryUserDatabase.reload=Reloading memory user database [{0}] from updated source [{1}]
+memoryUserDatabase.reloadError=Error reloading memory user database [{0}] from updated source [{1}]
 memoryUserDatabase.renameOld=Cannot rename original file to [{0}]
 memoryUserDatabase.renameNew=Cannot rename new file to [{0}]
 memoryUserDatabase.restoreOrig=Cannot restore [{0} to original file

Modified: tomcat/trunk/java/org/apache/catalina/users/MemoryUserDatabase.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/users/MemoryUserDatabase.java?rev=1840917&r1=1840916&r2=1840917&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/users/MemoryUserDatabase.java (original)
+++ tomcat/trunk/java/org/apache/catalina/users/MemoryUserDatabase.java Fri Sep 14 12:36:58 2018
@@ -22,6 +22,9 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.Map;
@@ -148,6 +151,9 @@ public class MemoryUserDatabase implemen
     private final Lock readLock = dbLock.readLock();
     private final Lock writeLock = dbLock.writeLock();
 
+    private volatile long lastModified = 0;
+    private boolean watchSource = true;
+
 
     // ------------------------------------------------------------- Properties
 
@@ -165,6 +171,7 @@ public class MemoryUserDatabase implemen
     }
 
 
+
     /**
      * @return the unique global identifier of this user database.
      */
@@ -212,6 +219,17 @@ public class MemoryUserDatabase implemen
     }
 
 
+    public boolean getWatchSource() {
+        return watchSource;
+    }
+
+
+
+    public void setWatchSource(boolean watchSource) {
+        this.watchSource = watchSource;
+    }
+
+
     /**
      * @return the set of {@link Role}s defined in this user database.
      */
@@ -406,7 +424,13 @@ public class MemoryUserDatabase implemen
             roles.clear();
 
             String pathName = getPathname();
-            try (InputStream is = ConfigFileLoader.getInputStream(getPathname())) {
+            URI uri = ConfigFileLoader.getURI(pathName);
+            URL url = uri.toURL();
+            URLConnection uConn = url.openConnection();
+
+            try (InputStream is = uConn.getInputStream()) {
+                this.lastModified = uConn.getLastModified();
+
                 // Construct a digester to read the XML input file
                 Digester digester = new Digester();
                 try {
@@ -538,21 +562,21 @@ public class MemoryUserDatabase implemen
             fileNew = new File(System.getProperty(Globals.CATALINA_BASE_PROP), pathnameNew);
         }
 
-        try (FileOutputStream fos = new FileOutputStream(fileNew);
-                OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF8");
-                PrintWriter writer = new PrintWriter(osw)) {
-
-            // Print the file prolog
-            writer.println("<?xml version='1.0' encoding='utf-8'?>");
-            writer.println("<tomcat-users xmlns=\"http://tomcat.apache.org/xml\"");
-            writer.print("              ");
-            writer.println("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
-            writer.print("              ");
-            writer.println("xsi:schemaLocation=\"http://tomcat.apache.org/xml tomcat-users.xsd\"");
-            writer.println("              version=\"1.0\">");
+        writeLock.lock();
+        try {
+            try (FileOutputStream fos = new FileOutputStream(fileNew);
+                    OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF8");
+                    PrintWriter writer = new PrintWriter(osw)) {
+
+                // Print the file prolog
+                writer.println("<?xml version='1.0' encoding='utf-8'?>");
+                writer.println("<tomcat-users xmlns=\"http://tomcat.apache.org/xml\"");
+                writer.print("              ");
+                writer.println("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
+                writer.print("              ");
+                writer.println("xsi:schemaLocation=\"http://tomcat.apache.org/xml tomcat-users.xsd\"");
+                writer.println("              version=\"1.0\">");
 
-            writeLock.lock();
-            try {
                 // Print entries for each defined role, group, and user
                 Iterator<?> values = null;
                 values = getRoles();
@@ -570,23 +594,24 @@ public class MemoryUserDatabase implemen
                     writer.print("  ");
                     writer.println(((MemoryUser) values.next()).toXml());
                 }
-            } finally {
-                writeLock.unlock();
-            }
 
-            // Print the file epilog
-            writer.println("</tomcat-users>");
+                // Print the file epilog
+                writer.println("</tomcat-users>");
 
-            // Check for errors that occurred while printing
-            if (writer.checkError()) {
-                throw new IOException(sm.getString("memoryUserDatabase.writeException",
-                        fileNew.getAbsolutePath()));
-            }
-        } catch (IOException e) {
-            if (fileNew.exists() && !fileNew.delete()) {
-                log.warn(sm.getString("memoryUserDatabase.fileDelete", fileNew));
+                // Check for errors that occurred while printing
+                if (writer.checkError()) {
+                    throw new IOException(sm.getString("memoryUserDatabase.writeException",
+                            fileNew.getAbsolutePath()));
+                }
+            } catch (IOException e) {
+                if (fileNew.exists() && !fileNew.delete()) {
+                    log.warn(sm.getString("memoryUserDatabase.fileDelete", fileNew));
+                }
+                throw e;
             }
-            throw e;
+            this.lastModified = fileNew.lastModified();
+        } finally {
+            writeLock.unlock();
         }
 
         // Perform the required renames to permanently save this file
@@ -621,6 +646,34 @@ public class MemoryUserDatabase implemen
         }
     }
 
+
+    @Override
+    public void backgroundProcess() {
+        if (!watchSource) {
+            return;
+        }
+
+        URI uri = ConfigFileLoader.getURI(getPathname());
+        try {
+            URL url = uri.toURL();
+            URLConnection uConn = url.openConnection();
+
+            if (this.lastModified != uConn.getLastModified()) {
+                writeLock.lock();
+                try {
+                    if (this.lastModified != uConn.getLastModified()) {
+                        log.info(sm.getString("memoryUserDatabase.reload", id, uri));
+                        open();
+                    }
+                } finally {
+                    writeLock.unlock();
+                }
+            }
+        } catch (Exception ioe) {
+            log.error(sm.getString("memoryUserDatabase.reloadError", id, uri), ioe);
+        }
+    }
+
 
     /**
      * Return a String representation of this UserDatabase.

Modified: tomcat/trunk/java/org/apache/catalina/users/MemoryUserDatabaseFactory.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/users/MemoryUserDatabaseFactory.java?rev=1840917&r1=1840916&r2=1840917&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/users/MemoryUserDatabaseFactory.java (original)
+++ tomcat/trunk/java/org/apache/catalina/users/MemoryUserDatabaseFactory.java Fri Sep 14 12:36:58 2018
@@ -98,6 +98,11 @@ public class MemoryUserDatabaseFactory i
             database.setReadonly(Boolean.parseBoolean(ra.getContent().toString()));
         }
 
+        ra = ref.get("watchSource");
+        if (ra != null) {
+            database.setWatchSource(Boolean.parseBoolean(ra.getContent().toString()));
+        }
+
         // Return the configured database instance
         database.open();
         // Don't try something we know won't work

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1840917&r1=1840916&r2=1840917&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Fri Sep 14 12:36:58 2018
@@ -48,6 +48,13 @@
   <subsection name="Catalina">
     <changelog>
       <add>
+        <bug>58590</bug>: Add the ability for a UserDatabase to monitor the
+        backing XML file for changes and reload the source file if a change in
+        the last modified time is detected. This is enabled by default meaning
+        that changes to <code>$CATALINA_BASE/conf/tomcat-users.xml</code> will
+        now take effect a short time after the file is saved. (markt)
+      </add>
+      <add>
         <bug>61692</bug>: Add the ability to control which HTTP methods are
         handled by the CGI Servlet via a new initialization parameter
         <code>cgiMethods</code>. (markt)

Modified: tomcat/trunk/webapps/docs/jndi-resources-howto.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/jndi-resources-howto.xml?rev=1840917&r1=1840916&r2=1840917&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/jndi-resources-howto.xml (original)
+++ tomcat/trunk/webapps/docs/jndi-resources-howto.xml Fri Sep 14 12:36:58 2018
@@ -482,6 +482,12 @@ public class MyBean2 {
     is running as. Ensure that these are appropriate to maintain the security
     of your installation.</p>
 
+    <p>If referenced in a Realm, the UserDatabse will, by default, monitor
+    <code>pathname</code> for changes and reload the file if a change in the
+    last modified time is observed. This can be disabled by setting the
+    <code>watchSource</code> attribute to <code>false</code>.
+    </p>
+
     <h5>3.  Configure the Realm</h5>
 
     <p>Configure a UserDatabase Realm to use this resource as described in the



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