001: /* jcifs smb client library in Java
002: * Copyright (C) 2002 "Michael B. Allen" <jcifs at samba dot org>
003: * "Jason Pugsley" <jcifs at samba dot org>
004: * "skeetz" <jcifs at samba dot org>
005: * "Eric Glass" <jcifs at samba dot org>
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */
021:
022: package jcifs.http;
023:
024: import java.io.*;
025: import java.util.Enumeration;
026: import java.net.UnknownHostException;
027: import javax.servlet.*;
028: import javax.servlet.http.*;
029: import jcifs.*;
030: import jcifs.smb.SmbSession;
031: import jcifs.smb.NtlmChallenge;
032: import jcifs.smb.NtlmPasswordAuthentication;
033: import jcifs.smb.SmbAuthException;
034: import jcifs.util.Base64;
035: import jcifs.util.LogStream;
036: import jcifs.netbios.NbtAddress;
037:
038: /**
039: * This servlet Filter can be used to negotiate password hashes with
040: * MSIE clients using NTLM SSP. This is similar to <tt>Authentication:
041: * BASIC</tt> but weakly encrypted and without requiring the user to re-supply
042: * authentication credentials.
043: * <p>
044: * Read <a href="../../../ntlmhttpauth.html">jCIFS NTLM HTTP Authentication and the Network Explorer Servlet</a> for complete details.
045: */
046:
047: public class NtlmHttpFilter implements Filter {
048:
049: private static LogStream log = LogStream.getInstance();
050:
051: private String defaultDomain;
052: private String domainController;
053: private boolean loadBalance;
054: private boolean enableBasic;
055: private boolean insecureBasic;
056: private String realm;
057:
058: public void init(FilterConfig filterConfig) throws ServletException {
059: String name;
060: int level;
061:
062: /* Set jcifs properties we know we want; soTimeout and cachePolicy to 10min.
063: */
064: Config.setProperty("jcifs.smb.client.soTimeout", "300000");
065: Config.setProperty("jcifs.netbios.cachePolicy", "1200");
066:
067: Enumeration e = filterConfig.getInitParameterNames();
068: while (e.hasMoreElements()) {
069: name = (String) e.nextElement();
070: if (name.startsWith("jcifs.")) {
071: Config.setProperty(name, filterConfig
072: .getInitParameter(name));
073: }
074: }
075: defaultDomain = Config.getProperty("jcifs.smb.client.domain");
076: domainController = Config
077: .getProperty("jcifs.http.domainController");
078: if (domainController == null) {
079: domainController = defaultDomain;
080: loadBalance = Config.getBoolean("jcifs.http.loadBalance",
081: true);
082: }
083: enableBasic = Boolean.valueOf(
084: Config.getProperty("jcifs.http.enableBasic"))
085: .booleanValue();
086: insecureBasic = Boolean.valueOf(
087: Config.getProperty("jcifs.http.insecureBasic"))
088: .booleanValue();
089: realm = Config.getProperty("jcifs.http.basicRealm");
090: if (realm == null)
091: realm = "jCIFS";
092:
093: if ((level = Config.getInt("jcifs.util.loglevel", -1)) != -1) {
094: LogStream.setLevel(level);
095: }
096: if (log.level > 2) {
097: try {
098: Config.store(log, "JCIFS PROPERTIES");
099: } catch (IOException ioe) {
100: }
101: }
102: }
103:
104: public void destroy() {
105: }
106:
107: public void doFilter(ServletRequest request,
108: ServletResponse response, FilterChain chain)
109: throws IOException, ServletException {
110: HttpServletRequest req;
111: HttpServletResponse resp;
112: UniAddress dc;
113: String msg;
114:
115: NtlmPasswordAuthentication ntlm = null;
116: req = (HttpServletRequest) request;
117: resp = (HttpServletResponse) response;
118: msg = req.getHeader("Authorization");
119: boolean offerBasic = enableBasic
120: && (insecureBasic || req.isSecure());
121:
122: if (msg != null
123: && (msg.startsWith("NTLM ") || (offerBasic && msg
124: .startsWith("Basic ")))) {
125: if (msg.startsWith("NTLM ")) {
126: HttpSession ssn = req.getSession();
127: byte[] challenge;
128:
129: if (loadBalance) {
130: NtlmChallenge chal = (NtlmChallenge) ssn
131: .getAttribute("NtlmHttpChal");
132: if (chal == null) {
133: chal = SmbSession.getChallengeForDomain();
134: ssn.setAttribute("NtlmHttpChal", chal);
135: }
136: dc = chal.dc;
137: challenge = chal.challenge;
138: } else {
139: dc = UniAddress.getByName(domainController, true);
140: challenge = SmbSession.getChallenge(dc);
141: }
142:
143: if ((ntlm = NtlmSsp.authenticate(req, resp, challenge)) == null) {
144: return;
145: }
146: /* negotiation complete, remove the challenge object */
147: ssn.removeAttribute("NtlmHttpChal");
148: } else {
149: String auth = new String(Base64
150: .decode(msg.substring(6)), "US-ASCII");
151: int index = auth.indexOf(':');
152: String user = (index != -1) ? auth.substring(0, index)
153: : auth;
154: String password = (index != -1) ? auth
155: .substring(index + 1) : "";
156: index = user.indexOf('\\');
157: if (index == -1)
158: index = user.indexOf('/');
159: String domain = (index != -1) ? user
160: .substring(0, index) : defaultDomain;
161: user = (index != -1) ? user.substring(index + 1) : user;
162: ntlm = new NtlmPasswordAuthentication(domain, user,
163: password);
164: dc = UniAddress.getByName(domainController, true);
165: }
166: try {
167:
168: SmbSession.logon(dc, ntlm);
169:
170: if (log.level > 2) {
171: log.println("NtlmHttpFilter: " + ntlm
172: + " successfully authenticated against "
173: + dc);
174: }
175: } catch (SmbAuthException sae) {
176: if (log.level > 1) {
177: log.println("NtlmHttpFilter: "
178: + ntlm.getName()
179: + ": 0x"
180: + jcifs.util.Hexdump.toHexString(sae
181: .getNtStatus(), 8) + ": " + sae);
182: }
183: if (sae.getNtStatus() == sae.NT_STATUS_ACCESS_VIOLATION) {
184: /* Server challenge no longer valid for
185: * externally supplied password hashes.
186: */
187: HttpSession ssn = req.getSession(false);
188: if (ssn != null) {
189: ssn.removeAttribute("NtlmHttpAuth");
190: }
191: }
192: resp.setHeader("WWW-Authenticate", "NTLM");
193: if (offerBasic) {
194: resp.addHeader("WWW-Authenticate", "Basic realm=\""
195: + realm + "\"");
196: }
197: resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
198: resp.flushBuffer();
199: return;
200: }
201: req.getSession().setAttribute("NtlmHttpAuth", ntlm);
202: } else {
203: HttpSession ssn = req.getSession(false);
204: if (ssn == null
205: || (ntlm = (NtlmPasswordAuthentication) ssn
206: .getAttribute("NtlmHttpAuth")) == null) {
207: resp.setHeader("WWW-Authenticate", "NTLM");
208: if (offerBasic) {
209: resp.addHeader("WWW-Authenticate", "Basic realm=\""
210: + realm + "\"");
211: }
212: resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
213: resp.flushBuffer();
214: return;
215: }
216: }
217:
218: chain.doFilter(new NtlmHttpServletRequest(req, ntlm), response);
219: }
220:
221: // Added by cgross to work with weblogic 6.1.
222: public void setFilterConfig(FilterConfig f) {
223: try {
224: init(f);
225: } catch (Exception e) {
226: e.printStackTrace();
227: }
228: }
229:
230: public FilterConfig getFilterConfig() {
231: return null;
232: }
233: }
|