Okay, so I checked out Tomcat 8.0.32 from source control. I then reverted MemoryRealm's authenticate method to how it was in 7.0.26 and built Tomcat and now my authentication works. This of course is not a solution, but it obviates most of my other questions. I guess the important question is: how do I set the CredentialHandler on the MemoryRealm?
=================================================================== --- MemoryRealm.java (revision 1734183) +++ MemoryRealm.java (working copy) @@ -115,16 +115,16 @@ GenericPrincipal principal = principals.get(username); - boolean validated; - if (principal == null) { - validated = false; - } else { - if (credentials == null || principal.getPassword() == null) { - if (log.isDebugEnabled()) - log.debug(sm.getString("memoryRealm.authenticateFailure", username)); - return (null); + boolean validated = false; + if (principal != null && credentials != null) { + if (hasMessageDigest()) { + // Hex hashes should be compared case-insensitive + validated = (digest(credentials) + .equalsIgnoreCase(principal.getPassword())); + } else { + validated = + (digest(credentials).equals(principal.getPassword())); } - validated = getCredentialHandler().matches(credentials, principal.getPassword()); } if (validated) { On Tue, Mar 8, 2016 at 3:43 PM, Jason Overland <jasonoverl...@gmail.com> wrote: > Hi, I'm upgrading an existing Vaadin 6 application from Tomcat 7.0.26 > to Tomcat 8.0.32 and have some questions. I'm using Windows 7 and > debugging in Eclipse. > > For authentication our configuration is using a MemoryRealm with > digest="SHA". We are storing usernames and passwords in a > tomcat-users.xml file. We are using a jaas.config which specifies to > use a org.apache.catalina.realm.JAASMemoryLoginModule. We have our > own implementation of a CallbackModule. For the upgrade I have added > a CredentialHandler node inside our Realm as suggested in the > documentation. > > server.xml: > > <GlobalNamingResources> > <!-- Editable user database that can also be used by > UserDatabaseRealm to authenticate users > --> > <Resource auth="Container" 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"/> > </GlobalNamingResources> > > ... > > <Realm className="org.apache.catalina.realm.MemoryRealm" digest="SHA"> > <CredentialHandler algorithm="SHA" > className="org.apache.catalina.realm.MessageDigestCredentialHandler"/> > </Realm> > > > jaas.config: > /** JAAS Login Configuration for the Application **/ > > JAASTomcat { > org.apache.catalina.realm.JAASMemoryLoginModule required debug=true; > }; > > our LoginController: > > callbackHandler = new LoginFormCallBackHandler(user); > tomcatLoginContext = new LoginContext("JAASTomcat", callbackHandler); > ... > tomcatLoginContext.login(); > > > our CallbackHandler: > public class LoginFormCallBackHandler implements CallbackHandler, > Serializable { > > private static final long serialVersionUID = 1L; > private LoginEvent logins = null; > private User user; > public LoginFormCallBackHandler(User user) > { > this.user = user; > } > > public void setLogins(LoginEvent loginEvent) { > logins = loginEvent; > } > > public void handle(Callback[] callbacks) throws IOException, > UnsupportedCallbackException { > boolean gotName = false; > for (int i = 0; i < callbacks.length; i++) { > if (callbacks[i] instanceof NameCallback) { > // get the username from the loginform event > NameCallback nc = (NameCallback) callbacks[i]; > > nc.setName(logins.getLoginParameter(LoginView.LOGINFORM_PARAMETER_USERNAME)); > user.username = nc.getName(); > gotName = true; > } else if (callbacks[i] instanceof TextInputCallback) { > TextInputCallback cb = (TextInputCallback) callbacks[i]; > if (cb.getPrompt().equals("catalinaBase")) { > cb.setText(System.getenv("CATALINA_BASE");); > } > } else if (callbacks[i] instanceof PasswordCallback) { > // get the password from the loginform event > PasswordCallback pc = (PasswordCallback) callbacks[i]; > try { > MessageDigest md = MessageDigest.getInstance("SHA"); > > md.update(logins.getLoginParameter(LoginView.LOGINFORM_PARAMETER_PASSWORD).getBytes()); > user.password = String.format("%x", new > BigInteger(1, md.digest())); > } > catch (NoSuchAlgorithmException nsae) > { > user.password = > logins.getLoginParameter(LoginView.LOGINFORM_PARAMETER_PASSWORD); > } > pc.setPassword(user.password.toCharArray()); > } else { > System.out.println("Unrecognized Callback: " + callbacks[i]); > } > } > if (gotName) > logins = null; > } > } > > This all worked in Tomcat 7 but unfortunately isn't working in Tomcat > 8. I was getting "WARNING: Unable to determine Catalina base to load > file conf/tomcat-users.xml" and so I had to start responding to > TextInputCallback "catalinaBase" as required by the new > getCatalinaBase method on JAASMemoryLoginModule. > > I got past that and now I'm getting a NullPointerException: > Authentication failed: java.lang.NullPointerException > at org.apache.catalina.realm.MemoryRealm.authenticate(MemoryRealm.java:127) > at > org.apache.catalina.realm.JAASMemoryLoginModule.login(JAASMemoryLoginModule.java:288) > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) > at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) > at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) > at java.lang.reflect.Method.invoke(Unknown Source) > at javax.security.auth.login.LoginContext.invoke(Unknown Source) > at javax.security.auth.login.LoginContext.access$000(Unknown Source) > at javax.security.auth.login.LoginContext$4.run(Unknown Source) > at javax.security.auth.login.LoginContext$4.run(Unknown Source) > at java.security.AccessController.doPrivileged(Native Method) > at javax.security.auth.login.LoginContext.invokePriv(Unknown Source) > at javax.security.auth.login.LoginContext.login(Unknown Source) > at com.lizardtech.es.adminui.vaadin.jaas.LoginController.onLogin(Unknown > Source) > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) > at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) > at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) > at java.lang.reflect.Method.invoke(Unknown Source) > at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:510) > at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:164) > at com.vaadin.ui.AbstractComponent.fireEvent(AbstractComponent.java:1219) > at com.vaadin.ui.LoginForm$2.handleParameters(LoginForm.java:103) > at com.vaadin.ui.Window.handleParameters(Window.java:515) > at > com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:528) > at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) > at > org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292) > at > org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) > at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) > at > org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) > at > org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) > at > org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212) > at > org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) > at > org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) > at > org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141) > at > org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) > at > org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616) > at > org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) > at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522) > at > org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095) > at > org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672) > at > org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500) > at > org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456) > at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) > at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) > at > org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) > at java.lang.Thread.run(Unknown Source) > > Where the nullpointerexception happens on the following line in > MemoryRealm.java: > validated = getCredentialHandler().matches(credentials, > principal.getPassword()); > > Debugging in Eclipse shows that credentialHandler is NULL here. I've > tried all combinations I can think of using the "digest" attribute on > MemoryRealm and having a nested CredentialHandler and it's always > NULL. > > I don't see anything interesting in my error logs. > > I have a couple questions: > 1) How can I set the CredentialHandler on the MemoryRealm to avoid the > NullPointerException? I thought this would be set as a result of our > server.xml having a CredentialHandler nested inside our MemoryRealm. > From looking at the code of RealmBase (from which MemoryRealm > inherits), I'm not even sure how it's possible to have a null > credentialHandler as it's set in startInternal, if nothing else. I > don't know what startInternal is but it sounds like something that > should be getting called. > 2) Is JAASMemoryLoginModule part of a public API intended to be used > by applications? We are using it but I don't see it mentioned in the > Tomcat docs. Its javadoc says it's used "primarily for testing". > 3) Is our existing configuration something that is supported in Tomcat 7/8? > 4) I've been referring to the Tomcat documentation "Realm > Configuration HOW-TO". Both the 7 and 8 versions of the docs suggest > that I need to use a JAASRealm and implement my own LoginModule. Is > this preferred over the configuration I currently have? > 5) Is there a better way to do what I'm doing? > > Sorry for such a long email, but thanks for reading if you made it > through. Hope I'm not missing something glaringly obvious, but that's > always a distinct possibility. --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org