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