jCIFS NTLM HTTP Authentication and the Network Explorer ServletThe jCIFS client is proving to be quite useful for adding functionality to websites on corporate intranets. Adding a link to a document on your LAN for example is a trivial exercise with jCIFS. With the introduction of the jcifs.http package in the 0.7 series a Filter for authenticating MSIE clients and a servlet for "exploring" SMB networks is provided. Microsoft Internet Explorer have the ability to negotiate NTLM password hashes over an HTTP session using base 64 encoded NTLMSSP messages. This is a staple feature of IIS but Java application servers too can use jCIFS to authenticate MSIE clients against a domain controller. This is a useful feature because many of the tasks surrounding user management now fall back to computer support and HR. It is not necessary to add and remove users as they join and leave the company. Perhaps most important from a user's perspective; they do not need to enter a username or password if their workstation is a member of the domain. The password hashes generated when they logged on to their workstation will be negotiated during the initial request for a session, passed through jCIFS, and validated against a PDC or BDC. This also makes the users domain, username, and password available for managing session information, profiles, preferences, etc.Note: This functionality is a non-conformant extension to HTTP conceived entirely by Microsoft. It inappropriately uses HTTP headers and therefore may not work with all Servlet containers or may stop working with a new release of your application server. Also, this flavor of password encryption is not very secure so under no circumstances should it be used to authenticate clients on the Internet. Installation and SetupPut the latest jCIFS jar file in the lib/ directory of your container or application and add filter and filter-mapping directives to the web.xml or container control file like the following:If the above filter-mapping is uncommented, this filter will require NTLM HTTP Authentication for all (/*) content of this web-app. The SMB server at 192.168.1.16 will be used to validate password hashes (and if it is a member of an NT domain, it will in turn query it's domain controller to validate those password hashes).<filter> <filter-name>NTLM HTTP Authentication Filter</filter-name> <filter-class>jcifs.http.NtlmHttpFilter</filter-class> <!-- For development, any SMB server is suitable for validating password hashes. --> <init-param> <param-name>jcifs.http.domainController</param-name> <param-value>192.168.1.16</param-value> </init-param> <!-- For production use a real domain controller and eliminate a middle-man server <init-param> <param-name>jcifs.smb.client.domain</param-name> <param-value>NYC-USERS</param-value> </init-param> <init-param> <param-name>jcifs.netbios.wins</param-name> <param-value>10.169.10.77</param-value> </init-param> --> </filter> <!-- NTLM HTTP Authentication only works with MSIE <filter-mapping> <filter-name>NTLM HTTP Authentication Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> --> In a production environment on a corporate WAN it is more likely that jcifs.smb.client.domain and jcifs.netbios.wins directives will be used with the jcifs.http.domainController directive commented out. If one well established domain controller is to be used, the IP address, NetBIOS name, or FQDN of that server may be specified with the jcifs.http.domainController property. To determine if the filter is working, a browser other than MSIE can be used to test the protected content although because the user is not prompted for a password and because other browsers (Mozilla a least) display nothing but a blank page, the NtlmHttpAuthExample in the examples directory is provided to instill confidence. Running this example with a working NTLM HTTP Filter should display something like the following:
The significance of the POST test is that after negotiating NTLM HTTP Authentication once, IE will not POST any form data until it has negotiated the password hashes again. If the NTLM HTTP Authentication Filter is not enabled something like the following will be displayed: null successfully logged inNotice the user was permitted access. Unlike this example, developers might add an additional check to make sure getRemoteUser does not return null. If you setup the filter and you see this message you did something wrong. Perhaps the url-pattern in your web.xml does not match the content you intended? Non MSIE clientsNTLM HTTP authentication is only supported by MSIE. For other clients like Mozilla it is possible to use basic authentictito pass NTLM password credentials. This is strongly discouraged if SSL is not being used because it sends these credentials in plain text. It would not be difficult for another user to download and install a program to "snoop" LAN traffic and obtain other user's passwords.Regardless, this functionality has been added to the NtlmHttpFilter and NtlmServlet (for pre 2.3 servlet containers) although it is disabled by default. To enable this capability set the jcifs.http.basicRealm, jcifs.http.enableBasic, and jcifs.http.insecureBasic properties described in the table below. jCIFS Properties Meaningful to NTLM HTTP AuthenticationAll parameters that begin with 'jcifs.' will be set as jCIFS properties which means that any jCIFS properties may be used as init parameters. These properties must be set before jCIFS classes are used. For a complete list of jCIFS properties refer to the overview page of the API documentation. Here is a select subset of jCIFS properties with additional notes in the context of NTLM HTTP Authentication.
The Network Explorer ServletAn obvious application of the jcifs.http package is a web based file viewer that uses the password hashes negotiated via NTLM HTTP Authentication to "explore" all SMB resources. The jcifs.http.NetworkExplorer servlet is precisely this. See the jCIFS Freshmeat project page for a screenshot.To enable the Network Explorer servlet, simply add a servlet mapping to the web.xml or container control file like the following: Please note the NTLM HTTP Authentication Filter cannot be used in conjunction with this servlet because it uses the NTLM negotiation to negotiate credentials for accessing SMB resources (in a future version it may be possible to negotiate credentials twice or trick the client into connecting twice over the same session). If you are also protecting content with the NtlmHttpFilter, create a different unfiltered subtree for NetworkExplorer. They will not work together. You will get Access denied.<servlet> <servlet-name>NetworkExplorer</servlet-name> <servlet-class>jcifs.http.NetworkExplorer</servlet-class> <!-- Only MSIE in a domain environment supports NTLM HTTP Auth. If all target machines are not members of the same domain or if non-MSIE browsers are used set these to the creds that should be used. Also, comment out the NTLM HTTP Authentication Filter and copy any pertinent NetworkExplorer init parameters here. <init-param> <param-name>jcifs.smb.client.domain</param-name> <param-value>NYC-USERS</param-value> </init-param> --> <init-param> <param-name>jcifs.smb.client.username</param-name> <param-value>miallen</param-value> </init-param> <init-param> <param-name>jcifs.smb.client.password</param-name> <param-value>logos96</param-value> </init-param> <!-- Set the broadcast address if you get: Unknown host: ..__MSBROWSE__.<01> --> <init-param> <param-name>jcifs.netbios.baddr</param-name> <param-value>192.168.1.255</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>NetworkExplorer</servlet-name> <url-pattern>/NetworkExplorer/*</url-pattern> </servlet-mapping> If you are using Mozilla or other non-MSIE browser, you can explicitly specify a username and password using init parameters as shown above (keep in mind anyone will be able to browse SMB resources using these credentials if they know the URL!). Also, only newer CSS compliant browsers like Mozilla, MSIE 5, and maybe Opera will render this content properly because it uses the display: block CSS property for hyperlinks rather than their default of inline. The appearance can be tailored to your site by simply editing the src/jcifs/http/ne.css stylesheet and rebuilding the jar however.
Important
More About NTLM HTTP Authentication with jCIFSThe NTLM HTTP Authentication process is described very well in this document:http://www.innovation.ch/java/ntlm.html The process can be summarized as a 3 request/response "handshake". So doGet() will be called three times. The first is the initial request. A 401 Unauthorized is sent back to which IE submits a special message encoded in a header. Another 401 Unauthorized is sent back after which IE submits the password hashes. This is where jCIFS comes in. The password hashes alone are useless. You must check their authenticity against the password database on a server somewhere (actually you can specify the IP of a plain workstation or any other SMB server). Otherwise a user who's workstation is not a member of the domain will get a password dialog into which they could put anything and it would let them in. This is what pretty much all the examples seen in various forums do. Don't be fooled.
|