[jcifs] Davenport Locking

eglass1 at comcast.net eglass1 at comcast.net
Wed Mar 3 10:21:45 GMT 2004



> The solution will likely involve destroying objects cached in the HTTP
> session when the SmbTransport closes but until I util I determine how that

I'm not sure that would be possible (or recommended); the request and
associated objects are only guaranteed to be valid during the servicing of
the request (i.e. during the lifetime of the associated Servlet.service()
invocation).  The underlying session storage provided by the container would
exist between calls, but you wouldn't (or shouldn't) be able to do
HttpSession.removeAttribute() if the SmbTransport expired outside of an
active HTTP request.

One approach might be to null out the hashes in all associated NPA objects
when the transport closes; you could then add (to NtlmPasswordAuthentication)
something like:

    public boolean isValid() {
        return hashesExternal ? (ansiHash != null || unicodeHash != null) :
                true;
    }

    public void setAnsiHash(byte[] ansiHash) {
        if (hashesExternal) this.ansiHash = ansiHash;
    }

    public void setUnicodeHash(byte[] unicodeHash) {
        if (hashesExternal) this.unicodeHash = unicodeHash;
    }


So expiring the NPA would be:

    npa.setAnsiHash(null);
    npa.setUnicodeHash(null);

which would have no effect if the NPA had the password available (which is
good).  The filter, etc. would then add an additional check to NPAs retrieved
from the HttpSession:

    HttpSession ssn = req.getSession(false);
    if (ssn == null || (ntlm = (NtlmPasswordAuthentication)
            ssn.getAttribute("NtlmHttpAuth")) == null || !ntlm.isValid()) {
        resp.setHeader( "WWW-Authenticate", "NTLM" );
        if (offerBasic) {
            resp.addHeader( "WWW-Authenticate", "Basic realm=\"" +
                    realm + "\"");
        }
        resp.setHeader( "Connection", "close" );
        resp.setStatus( HttpServletResponse.SC_UNAUTHORIZED );
        resp.flushBuffer();
        return;
    }

and NtlmSsp.java would do something like:

    NtlmPasswordAuthentication ntlm = null;
    HttpSession session = req.getSession(false);
    NtlmPasswordAuthentication ntlm = (session != null) ?
            (NtlmPasswordAuthentication) req.getAttribute("NtlmHttpAuth") :
                    null;
    if (ntlm != null) {
        ntlm.setAnsiHash(lmResponse);
        ntlm.setUnicodeHash(ntResponse);
    } else {
        ntlm = new NtlmPasswordAuthentication(type3.getDomain(),
                type3.getUser(), lmResponse, ntResponse);
    }
    return ntlm;

The big trick (I think) would be invalidating the NPAs when the transport
closes.  One approach would be to register the NPAs with the transport in
SmbSession.logon:

    public static void logon(UniAddress dc, NtlmPasswordAuthentication auth)
            throws SmbException {
        SmbTransport transport = SmbTransport.getSmbTransport(dc, 0);
        transport.getSmbSession(auth).getSmbTree("IPC$",
                null).treeConnect(null, null);
        // register now that we know it's good
        transport.register(auth);
    }

SmbTransport would keep a HashSet of registered NPAs:

    private HashSet npas = new HashSet();

    void register(NtlmPasswordAuthentication auth) {
        synchronized (npas) {
            npas.add(auth);
        }
    }

and invalidate them on close:

    // server closed transport
    synchronized (npas) {
        Iterator invalidated = npas.iterator();
        while (invalidated.hasNext()) {
            NtlmPasswordAuthentication auth =
                    (NtlmPasswordAuthentication) invalidated.next();
            auth.setAnsiHash(null);
            auth.setUnicodeHash(null);
        }
    }


Eric


More information about the jcifs mailing list