1 /*
   2  * Copyright 2002-2005 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package sun.net.www.protocol.http;
  27 
  28 import java.io.IOException;
  29 import java.net.InetAddress;
  30 import java.net.PasswordAuthentication;
  31 import java.net.UnknownHostException;
  32 import java.net.URL;
  33 import sun.net.www.HeaderParser;
  34 
  35 /**
  36  * NTLMAuthentication:
  37  *
  38  * @author Michael McMahon
  39  */
  40 
  41 class NTLMAuthentication extends AuthenticationInfo {
  42 
  43     private static final long serialVersionUID = 100L;
  44 
  45     private String hostname;
  46     private static String defaultDomain; /* Domain to use if not specified by user */
  47 
  48     static {
  49         defaultDomain = java.security.AccessController.doPrivileged(
  50             new sun.security.action.GetPropertyAction("http.auth.ntlm.domain",
  51                                                       "domain"));
  52     };
  53 
  54     private void init0() {
  55 
  56         hostname = java.security.AccessController.doPrivileged(
  57             new java.security.PrivilegedAction<String>() {
  58             public String run() {
  59                 String localhost;
  60                 try {
  61                     localhost = InetAddress.getLocalHost().getHostName().toUpperCase();
  62                 } catch (UnknownHostException e) {
  63                      localhost = "localhost";
  64                 }
  65                 return localhost;
  66             }
  67         });
  68         int x = hostname.indexOf ('.');
  69         if (x != -1) {
  70             hostname = hostname.substring (0, x);
  71         }
  72     }
  73 
  74     String username;
  75     String ntdomain;
  76     String password;
  77 
  78     /**
  79      * Create a NTLMAuthentication:
  80      * Username may be specified as domain<BACKSLASH>username in the application Authenticator.
  81      * If this notation is not used, then the domain will be taken
  82      * from a system property: "http.auth.ntlm.domain".
  83      */
  84     public NTLMAuthentication(boolean isProxy, URL url, PasswordAuthentication pw) {
  85         super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
  86               AuthScheme.NTLM,
  87               url,
  88               "");
  89         init (pw);
  90     }
  91 
  92     private void init (PasswordAuthentication pw) {
  93         this.pw = pw;
  94         if (pw != null) {
  95             String s = pw.getUserName();
  96             int i = s.indexOf ('\\');
  97             if (i == -1) {
  98                 username = s;
  99                 ntdomain = defaultDomain;
 100             } else {
 101                 ntdomain = s.substring (0, i).toUpperCase();
 102                 username = s.substring (i+1);
 103             }
 104             password = new String (pw.getPassword());
 105         } else {
 106             /* credentials will be acquired from OS */
 107             username = null;
 108             ntdomain = null;
 109             password = null;
 110         }
 111         init0();
 112     }
 113 
 114    /**
 115     * Constructor used for proxy entries
 116     */
 117     public NTLMAuthentication(boolean isProxy, String host, int port,
 118                                 PasswordAuthentication pw) {
 119         super(isProxy?PROXY_AUTHENTICATION:SERVER_AUTHENTICATION,
 120               AuthScheme.NTLM,
 121               host,
 122               port,
 123               "");
 124         init (pw);
 125     }
 126 
 127     /**
 128      * @return true if this authentication supports preemptive authorization
 129      */
 130     boolean supportsPreemptiveAuthorization() {
 131         return false;
 132     }
 133 
 134     /**
 135      * @return true if NTLM supported transparently (no password needed, SSO)
 136      */
 137     static boolean supportsTransparentAuth() {
 138         return true;
 139     }
 140 
 141     /**
 142      * @return the name of the HTTP header this authentication wants set
 143      */
 144     String getHeaderName() {
 145         if (type == SERVER_AUTHENTICATION) {
 146             return "Authorization";
 147         } else {
 148             return "Proxy-authorization";
 149         }
 150     }
 151 
 152     /**
 153      * Not supported. Must use the setHeaders() method
 154      */
 155     String getHeaderValue(URL url, String method) {
 156         throw new RuntimeException ("getHeaderValue not supported");
 157     }
 158 
 159     /**
 160      * Check if the header indicates that the current auth. parameters are stale.
 161      * If so, then replace the relevant field with the new value
 162      * and return true. Otherwise return false.
 163      * returning true means the request can be retried with the same userid/password
 164      * returning false means we have to go back to the user to ask for a new
 165      * username password.
 166      */
 167     boolean isAuthorizationStale (String header) {
 168         return false; /* should not be called for ntlm */
 169     }
 170 
 171     /**
 172      * Set header(s) on the given connection.
 173      * @param conn The connection to apply the header(s) to
 174      * @param p A source of header values for this connection, not used because
 175      *          HeaderParser converts the fields to lower case, use raw instead
 176      * @param raw The raw header field.
 177      * @return true if all goes well, false if no headers were set.
 178      */
 179     synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
 180 
 181         try {
 182             NTLMAuthSequence seq = (NTLMAuthSequence)conn.authObj;
 183             if (seq == null) {
 184                 seq = new NTLMAuthSequence (username, password, ntdomain);
 185                 conn.authObj = seq;
 186             }
 187             String response = "NTLM " + seq.getAuthHeader (raw.length()>6?raw.substring(5):null);
 188             conn.setAuthenticationProperty(getHeaderName(), response);
 189             return true;
 190         } catch (IOException e) {
 191             return false;
 192         }
 193     }
 194 
 195 }