How to change a user's tomcat password in serv

2019-07-21 09:42发布

Our web application is deployed on Tomcat, currently using the UserDatabaseRealm for security. We want to supply a page in the application where the user can change their password - a simple, common web application function. I cannot find any example servlet code to do this. The Tomcat description of the UserDatabaseRealm implies that it can be updated programmatically after loading the XML when the server starts, and it can also save changes back to the XML file. There is a brief mention of JMX as a means, but no details.

Our goal is to have no database in this application, so we really don't want to use the JDBC Realm. What does the Java servlet code look like to change a user's password (and for an admin, to add/remove users)?

Thanks for the clues, here is my working Tomcat MemoryUserDatabase servlet (minus any encryption, password verification, error handling, etc):

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    try {
        // Get current password for currently authenticated user
        String username =  request.getRemoteUser();
        MBeanServer server = ManagementFactory.getPlatformMBeanServer();

        ObjectName userObjName = new ObjectName("Users:type=User,username=\""+username+"\",database=UserDatabase");
        Object password = server.getAttribute(userObjName, "password");
        System.out.println("Current Password = "+password.toString());

        // Get new password from request parms and update the DB
        String newPw = request.getParameter("newpw");
        server.setAttribute(userObjName, new Attribute("password", newPw));

        // Password is updated in-memory, now write to file.
        // Note Tomcat MemoryUserDatabase.save() implementation does not synchronize this 
        // operation, so it can fail badly if multiple users do this at the same time. 
        // Ugh. Should do this in a static synchronized method.
        server.invoke(
                new ObjectName("Users:type=UserDatabase,database=UserDatabase"),
                "save",
                new Object[0],
                new String[0]);

        // If no exception, save was OK (it returns VOID, so there is no return value to check)
    }
    catch (Throwable t) {
        // Should return proper HTTP error code...
        t.printStackTrace(System.err);
    }
}

1条回答
仙女界的扛把子
2楼-- · 2019-07-21 10:06

I just figures this out.

first you have to update the server.xml and add readonly=false to:

<Resource auth="Container" readonly="false" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/>

then in a jsp file:

 <%!public static boolean changePasswd(String user, String passwd, MBeanServer mbeanServer, JspWriter out) throws Throwable{ 
try {
String userFDN = "Users:type=User,username=\""+user+"\",database=UserDatabase"; 
ObjectName userObjName = new ObjectName(userFDN);
MBeanInfo info = mbeanServer.getMBeanInfo(userObjName);

Attribute attr=new Attribute("password",passwd);
mbeanServer.setAttribute(userObjName, attr);
ObjectName databaseObjName=new ObjectName("Users:type=UserDatabase,database=UserDatabase");
Object result= mbeanServer.invoke(databaseObjName,"save",new Object[0],new String[0]); 
out.println("<b>Changed password and, Saved: "+result+"</b>");
return true;    
} catch (Throwable t) {
out.print("<font color='red'>WHY: </font>" + t);
} 
return false; 
}%>

  <%MBeanServer mbeanServer = (MBeanServer) list.get(0); 
  //ObjectName obname = new ObjectName(   "Catalina:type=Resource,resourcetype=Global,class=org.apache.catalina.UserDatabase,name=\"UserDatabase\"" );
   ArrayList list = MBeanServerFactory.findMBeanServer(null);  
   MBeanServer mbeanServer = (MBeanServer) list.get(0);
   changePasswd("user","passwd",mbeanServer,out);

/N

查看更多
登录 后发表回答