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

Reply via email to