On 14/4/20 6:53 pm, logo wrote:
Brian,

see down below....

Am 2020-04-14 08:34, schrieb Brian Burch:
I thought it would be helpful to start this issue on the users list
because it will contain a lot of helpful search terms.

I am upgrading a stable production tomcat 7.0.52 system to tomcat
8.5.54. Both were built from source code (tc8 cloned from git) and
compiled under openjdk8.

Many users have pre-hashed SHA-1 passwords stored in the LDAP
directory. My SSO login jsp uses Form authentication. Because the only
Connector services https on port 443, there is no security exposure
from sending the user-entered cleartext password "over the wire" to
tomcat.

The working tomcat 7 Engine has the following Realm definition:-

      <Realm className="org.apache.catalina.realm.LockOutRealm"
             cacheSize="1000"
             failureCount="4"
             lockOutTime="1200"
             cacheRemovalWarningTime="86400" >

          <!-- This is the real Realm, which uses our apacheds LDAP directory.            User roles are defined as user attributes, not as group membership.
            -->
          <Realm className="org.apache.catalina.realm.JNDIRealm"
                 connectionName="uid=tomcatAuthenticate,ou=Special
Users,o=pingtoo.com"
                 connectionPassword="<redacted>"
                 connectionURL="ldap://ldap.pingtoo.com:10389";
                 userBase="ou=people,o=pingtoo.com"
                 userSubtree="false"
                 userSearch="(uid={0})"
                 userRoleName="tomcatRole"
                 userPassword="userPassword"
                 digest="SHA" />
      </Realm>

... and the Host has the following:-

        <Valve className="org.apache.catalina.valves.ExtendedAccessLogValve"
               directory="logs"
               prefix="access." suffix=".txt"
               pattern="c-ip x-H(authType) x-H(remoteUser) date time
cs-method cs-uri sc-status bytes"
               resolveHosts="false"/>

        <!-- activate single signon so a user only needs to authenticate
             once to have access to all applications on this virtual host
             under the same set of credentials. -->
        <Valve className="org.apache.catalina.authenticator.SingleSignOn"/>

As I said earlier, but without sounding like I am complaining, this
environment worked as intended (by me, the webadmin) with
tomcat7.0.52.

I am aware of the following information on the tomcat 8 Documentation:-

https://tomcat.apache.org/tomcat-8.0-doc/realm-howto.html

and

https://tomcat.apache.org/tomcat-8.0-doc/config/realm.html#JNDI_Directory_Realm_-_org.apache.catalina.realm.JNDIRealm

It states the "algorithm attribute is deprecated. Set the algorithm on
a nested CredentialHandler element instead."

I deleted the algorithm attribute from the tomcat8 JNDIRealm
definition, and nested three different versions for different test
runs:-

<CredentialHandler
className="org.apache.catalina.realm.MessageDigestCredentialHandler"
                           algorithm="SHA" />

It made no difference whether I used "SHA-1" or "SHA-256".

Under a netbeans remote debugging session with the tomcat8 server, I
initially set a breakpoint in FormAuthenticator.doAuthenticate, then
instruction stepped to drill down into the JNDI authentication logic.

JNDIREalm.compareCredentials executes:-

return getCredentialHandler().matches(credentials, password);

.. where the calling parameters are the {SHA}<base64> password from
the LDAP directory and the cleartext password string from the logon
Form.

MessageDigestCredentialHandler.matches immediately calls its own
getAlgorithm method, which returns null. Without a correct digest
handler, the two password parameters are compared as simple strings.
This means the authentication fails!

To prove my point, I pasted the hashed copy of the LDAP userpassword
(as plain text) into the FormAuthenticator field. Naturally, without a
valid hash algorithm the authentication is successful simply because
the two strings match exactly.

I searched for usages of MessageDigestCredentialHandler.setAlgorithm,
but only found it used once - within TestJNDIRealm. I did not find any
occurrences within tomcat mainline code, but would not be surprised if
the algorithm was intended to be set within code which used
introspection at runtime.

My initial code inspection makes me strongly suspect tomcat does not
initialise JNDIRealm and a nested CredentialHandler properly during
startup. However, I am not smart enough to attach my debugger to the
tomcat jvm until it is too late.

I had a smart idea... at a breakpoint I changed the value of the
algorithm instance variable from null to "SHA" before the comparison,
but I was slapped down with the following Exception:-

BB 2020-04-14T15:22:44,257 ERROR
[org.apache.catalina.core.ContainerBase.[Catalina].[www2.pingtoo.com]]
Exception Processing /staticPingToo/restricted/j_security_check
java.lang.IllegalStateException: Must call init() first
        at
org.apache.tomcat.util.security.ConcurrentMessageDigest.digest(ConcurrentMessageDigest.java:71)
~[tomcat-util.jar:8.5.54]
        at
org.apache.tomcat.util.security.ConcurrentMessageDigest.digest(ConcurrentMessageDigest.java:63)
~[tomcat-util.jar:8.5.54]
        at
org.apache.catalina.realm.MessageDigestCredentialHandler.matches(MessageDigestCredentialHandler.java:114)
~[catalina.jar:8.5.54]
        at
org.apache.catalina.realm.JNDIRealm.compareCredentials(JNDIRealm.java:1822)
~[catalina.jar:8.5.54]
        at
org.apache.catalina.realm.JNDIRealm.checkCredentials(JNDIRealm.java:1782)
~[catalina.jar:8.5.54]
        at
org.apache.catalina.realm.JNDIRealm.authenticate(JNDIRealm.java:1427)
~[catalina.jar:8.5.54]
        at
org.apache.catalina.realm.JNDIRealm.authenticate(JNDIRealm.java:1304)
~[catalina.jar:8.5.54]
        at
org.apache.catalina.realm.CombinedRealm.authenticate(CombinedRealm.java:197)
~[catalina.jar:8.5.54]
        at
org.apache.catalina.realm.LockOutRealm.authenticate(LockOutRealm.java:159)
~[catalina.jar:8.5.54]
        at
org.apache.catalina.authenticator.FormAuthenticator.doAuthenticate(FormAuthenticator.java:243)
~[catalina.jar:8.5.54]
        at
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:633)
~[catalina.jar:8.5.54]
        at
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
[catalina.jar:8.5.54]
        at
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
[catalina.jar:8.5.54]
        at
org.apache.catalina.authenticator.SingleSignOn.invoke(SingleSignOn.java:240)
[catalina.jar:8.5.54]
        at
org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
[catalina.jar:8.5.54]
        at
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
[catalina.jar:8.5.54]
        at
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
[catalina.jar:8.5.54]
        at
org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:615)
[tomcat-coyote.jar:8.5.54]
        at
org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
[tomcat-coyote.jar:8.5.54]
        at
org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:818)
[tomcat-coyote.jar:8.5.54]
        at
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1627)
[tomcat-coyote.jar:8.5.54]
        at
org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
[tomcat-coyote.jar:8.5.54]
        at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
[?:1.8.0_242]
        at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
[?:1.8.0_242]
        at
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
[tomcat-util.jar:8.5.54]
        at java.lang.Thread.run(Thread.java:748) [?:1.8.0_242]

Obviously, my smart idea wasn't smart enough!!!

So, if anyone has read this far, perhaps you can suggest my next best
course of action. Does this seem to be a bug in tomcat processing of
server.xml and initialisation of the JNDIReal nested
CredentialHandler's algorithm attribute? Is there a smart way to catch
the tc8 startup process and catch it early enough in my remote
debugger?


set in bin/setenv.sh

export JPDA_SUSPEND=y

this will stop tomcat startup until debugger is attached.

Wow! That is a neat trick. I will try it tomorrow and see what I can intercept.

Thanks very much for the tip,

Brian

Are the classes org.apache.catalina.storeconfig.RealmSF and
CredentialHandlerSF where I should be looking for a bug? Or perhaps I
have just coded my server.xml badly and the algorithm is being
silently ignored?

Hopefully...

Brian


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to