[jcifs] Problems with getOutputStream for a jCIFS client

eglass1 at comcast.net eglass1 at comcast.net
Thu Apr 29 20:00:32 GMT 2004



> Since the encryptionKey is created with new byte[] in
> SmbComNegotiateReponse every time the client negotiates this should ensure
> that no session setup can be performed with an invalid challange. Was this
> what you were thinking when we spoke previously about this? I don't
> recall. Do you have a better suggestion?
> 

I don't remember either; I'll have to look back at the list archives to
recall what this was about.  From what I can remember, that *seems* right...

> Also, can the error described below by Jan Christian Herlitz be attributed
> to our NtlmHttpURLConnection?

I think so (I've been pretty busy, so I haven't had a chance to track this
down).  My theory is this:

Normally, when you create an HttpURLConnection for PUT (or POST, for that
matter), you connect, get the output stream and write.  With the
NtlmHttpURLConnection, we connect, then check the status header (i.e., for a
401 w/NTLM) then create a new underlying connection(s) to complete the
handshake.  That is, our connection wraps multiple underlying transactions
to get the handshake done.

I *think* the problem is when we read the status from the final underlying
connection, in doConnect():


	private synchronized void doConnect() throws IOException {
		connection.connect();
		int response = parseResponseCode();
		if (response != HTTP_UNAUTHORIZED && response != HTTP_PROXY_AUTH) {
			return;  <-- everything is okay, return to caller
		}
        ..... again later on .....
            connection.setRequestProperty(authProperty, method + ' ' +
                    Base64.encode(type3.toByteArray()));
            connection.connect(); // send type 3
            response = parseResponseCode();
            if (response != HTTP_UNAUTHORIZED && response != HTTP_PROXY_AUTH) {
                return;  <-- auth completed successfully, return to caller
            }


We check that the status is good and return to the caller, but we've already
read from the connection (to get the status); so now when the caller does
getOutputStream to write, they get an error.

I'll have to think about the best way to solve this.  All the approaches I
can think of have drawbacks.  Currently, we loop until the status is "good"
using a stateless approach.  We could do this:

1) check for a 401
2) send the type 1 message
3) check for a 401 w/type 2 challenge
4) send the type 3 message
5) don't check the status, just return (even if authentication failed).

Basically factoring out the while loop and letting the caller handle failure.
This would take care of some instances; however if no authentication was
required in the first place (i.e., step 1 above gets a 200 status) then we
would see the same issue (because we've read the status header).

The other option would be similar, but *always* initiate a handshake:

1) send the type 1 message, even without the server asking
2) check for a 401 w/type 2 challenge
3) send the type 3 message
4) don't check the status, just return (even if authentication failed).

This should trigger the server to complete the handshake, and leave it in
a consistent state for the caller.  This would mean an extra round trip
for every HTTP request, however.  Also, if the server doesn't support
NTLM at all, I'm not sure what behavior would be observed.

My "gut approach" would be to alter doConnect() as follows:

1) first check connection.getRequestMethod(); only POST and PUT should need
to be changed.  The current behavior is correct for GET etc.  There may be
some other WebDAV methods that would need to write to the server (if Julian
Reschke is still watching this list, I bet he could answer this off the top
of his head).

2) if it's a POST/PUT, send the type 1 message proactively.

3) check for a 401 w/type 2 challenge.  If we get something else, reconnect
*without* the type 1 message, and return without checking the status
(punt to the caller).

4) if we *did* get a type 2 message, reconnect and send the type 3.  Don't
check the status on the response, just return.

I might not have a chance to take a closer look at this until next week
sometime, but this would probably be a good first approach.

On a side note, this may explain why IE proactively initiates NTLM handshakes
when POSTing (as this is fairly similar to their behavior).


Eric


More information about the jcifs mailing list