1 /*
   2  * Copyright (c) 2009, 2011, Oracle and/or its affiliates. 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package sun.net.www.protocol.http;
  26 
  27 import java.net.URL;
  28 import java.net.PasswordAuthentication;
  29 import java.lang.reflect.Constructor;
  30 import java.lang.reflect.Method;
  31 import sun.util.logging.PlatformLogger;
  32 
  33 /**
  34  * Proxy class for loading NTLMAuthentication, so as to remove static
  35  * dependancy.
  36  */
  37 class NTLMAuthenticationProxy {
  38     private static Method supportsTA;
  39     private static Method isTrustedSite;
  40     private static final String clazzStr = "sun.net.www.protocol.http.ntlm.NTLMAuthentication";
  41     private static final String supportsTAStr = "supportsTransparentAuth";
  42     private static final String isTrustedSiteStr = "isTrustedSite";
  43 
  44     static final NTLMAuthenticationProxy proxy = tryLoadNTLMAuthentication();
  45     static final boolean supported = proxy != null ? true : false;
  46     static final boolean supportsTransparentAuth = supported ? supportsTransparentAuth() : false;
  47 
  48     private final Constructor<? extends AuthenticationInfo> threeArgCtr;
  49     private final Constructor<? extends AuthenticationInfo> fiveArgCtr;
  50 
  51     private NTLMAuthenticationProxy(Constructor<? extends AuthenticationInfo> threeArgCtr,
  52                                     Constructor<? extends AuthenticationInfo> fiveArgCtr) {
  53         this.threeArgCtr = threeArgCtr;
  54         this.fiveArgCtr = fiveArgCtr;
  55     }
  56 
  57 
  58     AuthenticationInfo create(boolean isProxy,
  59                               URL url,
  60                               PasswordAuthentication pw) {
  61         try {
  62             return threeArgCtr.newInstance(isProxy, url, pw);
  63         } catch (ReflectiveOperationException roe) {
  64             finest(roe);
  65         }
  66 
  67         return null;
  68     }
  69 
  70     AuthenticationInfo create(boolean isProxy,
  71                               String host,
  72                               int port,
  73                               PasswordAuthentication pw) {
  74         try {
  75             return fiveArgCtr.newInstance(isProxy, host, port, pw);
  76         } catch (ReflectiveOperationException roe) {
  77             finest(roe);
  78         }
  79 
  80         return null;
  81     }
  82 
  83     /* Returns true if the NTLM implementation supports transparent
  84      * authentication (try with the current users credentials before
  85      * prompting for username and password, etc).
  86      */
  87     private static boolean supportsTransparentAuth() {
  88         try {
  89             return (Boolean)supportsTA.invoke(null);
  90         } catch (ReflectiveOperationException roe) {
  91             finest(roe);
  92         }
  93 
  94         return false;
  95     }
  96 
  97     /* Transparent authentication should only be tried with a trusted
  98      * site ( when running in a secure environment ).
  99      */
 100     public static boolean isTrustedSite(URL url) {
 101         try {
 102             return (Boolean)isTrustedSite.invoke(null, url);
 103         } catch (ReflectiveOperationException roe) {
 104             finest(roe);
 105         }
 106 
 107         return false;
 108     }
 109 
 110     /**
 111      * Loads the NTLM authentiation implementation through reflection. If
 112      * the class is present, then it must have the required constructors and
 113      * method. Otherwise, it is considered an error.
 114      */
 115     @SuppressWarnings("unchecked")
 116     private static NTLMAuthenticationProxy tryLoadNTLMAuthentication() {
 117         Class<? extends AuthenticationInfo> cl;
 118         Constructor<? extends AuthenticationInfo> threeArg, fiveArg;
 119         try {
 120             cl = (Class<? extends AuthenticationInfo>)Class.forName(clazzStr, true, null);
 121             if (cl != null) {
 122                 threeArg = cl.getConstructor(boolean.class,
 123                                              URL.class,
 124                                              PasswordAuthentication.class);
 125                 fiveArg = cl.getConstructor(boolean.class,
 126                                             String.class,
 127                                             int.class,
 128                                             PasswordAuthentication.class);
 129                 supportsTA = cl.getDeclaredMethod(supportsTAStr);
 130                 isTrustedSite = cl.getDeclaredMethod(isTrustedSiteStr, java.net.URL.class);
 131                 return new NTLMAuthenticationProxy(threeArg,
 132                                                    fiveArg);
 133             }
 134         } catch (ClassNotFoundException cnfe) {
 135             finest(cnfe);
 136         } catch (ReflectiveOperationException roe) {
 137             throw new AssertionError(roe);
 138         }
 139 
 140         return null;
 141     }
 142 
 143     static void finest(Exception e) {
 144         PlatformLogger logger = HttpURLConnection.getHttpLogger();
 145         if (logger.isLoggable(PlatformLogger.FINEST)) {
 146             logger.finest("NTLMAuthenticationProxy: " + e);
 147         }
 148     }
 149 }