jdk/test/com/sun/security/sasl/ntlm/NTLMTest.java
changeset 6517 151856936fd8
child 6678 fd8832656675
equal deleted inserted replaced
6516:8c52bb671f3e 6517:151856936fd8
       
     1 /*
       
     2  * Copyright (c) 2010, 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.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 /*
       
    25  * @test
       
    26  * @bug 6911951
       
    27  * @summary NTLM should be a supported Java SASL mechanism
       
    28  */
       
    29 import java.io.IOException;
       
    30 import javax.security.sasl.*;
       
    31 import javax.security.auth.callback.*;
       
    32 import java.util.*;
       
    33 
       
    34 import com.sun.security.ntlm.NTLMException;
       
    35 
       
    36 public class NTLMTest {
       
    37 
       
    38     private static final String MECH = "NTLM";
       
    39     private static final String REALM = "REALM";
       
    40     private static final String PROTOCOL = "jmx";
       
    41     private static final byte[] EMPTY = new byte[0];
       
    42 
       
    43     private static final String USER1 = "dummy";
       
    44     private static final char[] PASS1 = "bogus".toCharArray();
       
    45     private static final String USER2 = "foo";
       
    46     private static final char[] PASS2 = "bar".toCharArray();
       
    47 
       
    48     private static final Map<String,char[]> maps =
       
    49             new HashMap<String,char[]>();
       
    50     static {
       
    51         maps.put(USER1, PASS1);
       
    52         maps.put(USER2, PASS2);
       
    53     }
       
    54 
       
    55     static char[] getPass(String d, String u) {
       
    56         if (!d.equals(REALM)) return null;
       
    57         return maps.get(u);
       
    58     }
       
    59 
       
    60     public static void main(String[] args) throws Exception {
       
    61 
       
    62         checkAuthOnly();
       
    63         checkClientNameOverride();
       
    64         checkServerDomainOverride();
       
    65         checkClientDomainOverride();
       
    66         checkVersions();
       
    67         checkClientHostname();
       
    68     }
       
    69 
       
    70     static void checkVersions() throws Exception {
       
    71         // Server accepts all version
       
    72         checkVersion(null, null);
       
    73         checkVersion("LM/NTLM", null);
       
    74         checkVersion("LM", null);
       
    75         checkVersion("NTLM", null);
       
    76         checkVersion("NTLM2", null);
       
    77         checkVersion("LMv2/NTLMv2", null);
       
    78         checkVersion("LMv2", null);
       
    79         checkVersion("NTLMv2", null);
       
    80 
       
    81         // Client's default version is LMv2
       
    82         checkVersion(null, "LMv2");
       
    83 
       
    84         // Also works if they specified identical versions
       
    85         checkVersion("LM/NTLM", "LM");
       
    86         checkVersion("LM", "LM");
       
    87         checkVersion("NTLM", "LM");
       
    88         checkVersion("NTLM2", "NTLM2");
       
    89         checkVersion("LMv2/NTLMv2", "LMv2");
       
    90         checkVersion("LMv2", "LMv2");
       
    91         checkVersion("NTLMv2", "LMv2");
       
    92 
       
    93         // But should not work if different
       
    94         try {
       
    95             checkVersion("LM/NTLM", "LMv2");
       
    96             throw new Exception("Should not succeed");
       
    97         } catch (SaslException se) {
       
    98             NTLMException ne = (NTLMException)se.getCause();
       
    99             if (ne.errorCode() != NTLMException.AUTH_FAILED) {
       
   100                 throw new Exception("Failed false");
       
   101             }
       
   102         }
       
   103         try {
       
   104             checkVersion("LMv2/NTLMv2", "LM");
       
   105             throw new Exception("Should not succeed");
       
   106         } catch (SaslException se) {
       
   107             NTLMException ne = (NTLMException)se.getCause();
       
   108             if (ne.errorCode() != NTLMException.AUTH_FAILED) {
       
   109                 throw new Exception("Failed false");
       
   110             }
       
   111         }
       
   112 
       
   113     }
       
   114 
       
   115     /**
       
   116      * A test on version matching
       
   117      * @param vc ntlm version specified for client
       
   118      * @param vs ntlm version specified for server
       
   119      * @throws Exception
       
   120      */
       
   121     private static void checkVersion(String vc, String vs) throws Exception {
       
   122         Map<String,Object> pc = new HashMap<>();
       
   123         pc.put("com.sun.security.sasl.ntlm.version", vc);
       
   124         Map<String,Object> ps = new HashMap<>();
       
   125         ps.put("com.sun.security.sasl.ntlm.version", vs);
       
   126         SaslClient clnt = Sasl.createSaslClient(
       
   127                 new String[]{MECH}, USER1, PROTOCOL, null, pc,
       
   128                 new CallbackHandler() {
       
   129                     public void handle(Callback[] callbacks)
       
   130                             throws IOException, UnsupportedCallbackException {
       
   131                         for (Callback cb: callbacks) {
       
   132                             if (cb instanceof NameCallback) {
       
   133                                 NameCallback ncb = (NameCallback)cb;
       
   134                                 ncb.setName(ncb.getDefaultName());
       
   135                             } else if (cb instanceof PasswordCallback) {
       
   136                                 ((PasswordCallback)cb).setPassword(PASS1);
       
   137                             }
       
   138                         }
       
   139                     }
       
   140                 });
       
   141 
       
   142         SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, REALM, ps,
       
   143                 new CallbackHandler() {
       
   144                     public void handle(Callback[] callbacks)
       
   145                             throws IOException, UnsupportedCallbackException {
       
   146                         String domain = null, name = null;
       
   147                         PasswordCallback pcb = null;
       
   148                         for (Callback cb: callbacks) {
       
   149                             if (cb instanceof NameCallback) {
       
   150                                 name = ((NameCallback)cb).getDefaultName();
       
   151                             } else if (cb instanceof RealmCallback) {
       
   152                                 domain = ((RealmCallback)cb).getDefaultText();
       
   153                             } else if (cb instanceof PasswordCallback) {
       
   154                                 pcb = (PasswordCallback)cb;
       
   155                             }
       
   156                         }
       
   157                         if (pcb != null) {
       
   158                             pcb.setPassword(getPass(domain, name));
       
   159                         }
       
   160                     }
       
   161                 });
       
   162 
       
   163         handshake(clnt, srv);
       
   164     }
       
   165 
       
   166     private static void checkClientHostname() throws Exception {
       
   167         Map<String,Object> pc = new HashMap<>();
       
   168         pc.put("com.sun.security.sasl.ntlm.hostname", "this.is.com");
       
   169         SaslClient clnt = Sasl.createSaslClient(
       
   170                 new String[]{MECH}, USER1, PROTOCOL, null, pc,
       
   171                 new CallbackHandler() {
       
   172                     public void handle(Callback[] callbacks)
       
   173                             throws IOException, UnsupportedCallbackException {
       
   174                         for (Callback cb: callbacks) {
       
   175                             if (cb instanceof NameCallback) {
       
   176                                 NameCallback ncb = (NameCallback)cb;
       
   177                                 ncb.setName(ncb.getDefaultName());
       
   178                             } else if (cb instanceof PasswordCallback) {
       
   179                                 ((PasswordCallback)cb).setPassword(PASS1);
       
   180                             }
       
   181                         }
       
   182                     }
       
   183                 });
       
   184 
       
   185         SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, REALM, null,
       
   186                 new CallbackHandler() {
       
   187                     public void handle(Callback[] callbacks)
       
   188                             throws IOException, UnsupportedCallbackException {
       
   189                         String domain = null, name = null;
       
   190                         PasswordCallback pcb = null;
       
   191                         for (Callback cb: callbacks) {
       
   192                             if (cb instanceof NameCallback) {
       
   193                                 name = ((NameCallback)cb).getDefaultName();
       
   194                             } else if (cb instanceof RealmCallback) {
       
   195                                 domain = ((RealmCallback)cb).getDefaultText();
       
   196                             } else if (cb instanceof PasswordCallback) {
       
   197                                 pcb = (PasswordCallback)cb;
       
   198                             }
       
   199                         }
       
   200                         if (pcb != null) {
       
   201                             pcb.setPassword(getPass(domain, name));
       
   202                         }
       
   203                     }
       
   204                 });
       
   205 
       
   206         handshake(clnt, srv);
       
   207         if (!"this.is.com".equals(
       
   208                 srv.getNegotiatedProperty("com.sun.security.sasl.ntlm.hostname"))) {
       
   209             throw new Exception("Hostname not trasmitted to server");
       
   210         }
       
   211     }
       
   212 
       
   213     /**
       
   214      * Client realm override, but finally overridden by server response
       
   215      */
       
   216     private static void checkClientDomainOverride() throws Exception {
       
   217         SaslClient clnt = Sasl.createSaslClient(
       
   218                 new String[]{MECH}, USER1, PROTOCOL, "ANOTHERREALM", null,
       
   219                 new CallbackHandler() {
       
   220                     public void handle(Callback[] callbacks)
       
   221                             throws IOException, UnsupportedCallbackException {
       
   222                         for (Callback cb: callbacks) {
       
   223                             if (cb instanceof NameCallback) {
       
   224                                 NameCallback ncb = (NameCallback)cb;
       
   225                                 ncb.setName(ncb.getDefaultName());
       
   226                             } else if(cb instanceof RealmCallback) {
       
   227                                 RealmCallback dcb = (RealmCallback)cb;
       
   228                                 dcb.setText("THIRDDOMAIN");
       
   229                             } else if (cb instanceof PasswordCallback) {
       
   230                                 ((PasswordCallback)cb).setPassword(PASS1);
       
   231                             }
       
   232                         }
       
   233                     }
       
   234                 });
       
   235 
       
   236         SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, REALM, null,
       
   237                 new CallbackHandler() {
       
   238                     public void handle(Callback[] callbacks)
       
   239                             throws IOException, UnsupportedCallbackException {
       
   240                         String domain = null, name = null;
       
   241                         PasswordCallback pcb = null;
       
   242                         for (Callback cb: callbacks) {
       
   243                             if (cb instanceof NameCallback) {
       
   244                                 name = ((NameCallback)cb).getDefaultName();
       
   245                             } else if (cb instanceof RealmCallback) {
       
   246                                 domain = ((RealmCallback)cb).getDefaultText();
       
   247                             } else if (cb instanceof PasswordCallback) {
       
   248                                 pcb = (PasswordCallback)cb;
       
   249                             }
       
   250                         }
       
   251                         if (pcb != null) {
       
   252                             pcb.setPassword(getPass(domain, name));
       
   253                         }
       
   254                     }
       
   255                 });
       
   256 
       
   257         handshake(clnt, srv);
       
   258     }
       
   259 
       
   260     /**
       
   261      * Client side user name provided in callback.
       
   262      * @throws Exception
       
   263      */
       
   264     private static void checkClientNameOverride() throws Exception {
       
   265         SaslClient clnt = Sasl.createSaslClient(
       
   266                 new String[]{MECH}, null, PROTOCOL, null, null,
       
   267                 new CallbackHandler() {
       
   268                     public void handle(Callback[] callbacks)
       
   269                             throws IOException, UnsupportedCallbackException {
       
   270                         for (Callback cb: callbacks) {
       
   271                             if (cb instanceof NameCallback) {
       
   272                                 NameCallback ncb = (NameCallback)cb;
       
   273                                 ncb.setName(USER1);
       
   274                             } else if (cb instanceof PasswordCallback) {
       
   275                                 ((PasswordCallback)cb).setPassword(PASS1);
       
   276                             }
       
   277                         }
       
   278                     }
       
   279                 });
       
   280 
       
   281         SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, REALM, null,
       
   282                 new CallbackHandler() {
       
   283                     public void handle(Callback[] callbacks)
       
   284                             throws IOException, UnsupportedCallbackException {
       
   285                         String domain = null, name = null;
       
   286                         PasswordCallback pcb = null;
       
   287                         for (Callback cb: callbacks) {
       
   288                             if (cb instanceof NameCallback) {
       
   289                                 name = ((NameCallback)cb).getDefaultName();
       
   290                             } else if (cb instanceof RealmCallback) {
       
   291                                 domain = ((RealmCallback)cb).getDefaultText();
       
   292                             } else if (cb instanceof PasswordCallback) {
       
   293                                 pcb = (PasswordCallback)cb;
       
   294                             }
       
   295                         }
       
   296                         if (pcb != null) {
       
   297                             pcb.setPassword(getPass(domain, name));
       
   298                         }
       
   299                     }
       
   300                 });
       
   301 
       
   302         handshake(clnt, srv);
       
   303     }
       
   304 
       
   305     /**
       
   306      * server side domain provided in props.
       
   307      * @throws Exception
       
   308      */
       
   309     private static void checkServerDomainOverride() throws Exception {
       
   310         SaslClient clnt = Sasl.createSaslClient(
       
   311                 new String[]{MECH}, USER1, PROTOCOL, null, null,
       
   312                 new CallbackHandler() {
       
   313                     public void handle(Callback[] callbacks)
       
   314                             throws IOException, UnsupportedCallbackException {
       
   315                         for (Callback cb: callbacks) {
       
   316                             if (cb instanceof NameCallback) {
       
   317                                 NameCallback ncb = (NameCallback)cb;
       
   318                                 ncb.setName(ncb.getDefaultName());
       
   319                             } else if (cb instanceof PasswordCallback) {
       
   320                                 ((PasswordCallback)cb).setPassword(PASS1);
       
   321                             }
       
   322                         }
       
   323                     }
       
   324                 });
       
   325 
       
   326         Map<String,Object> ps = new HashMap<>();
       
   327         ps.put("com.sun.security.sasl.ntlm.domain", REALM);
       
   328         SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, null, ps,
       
   329                 new CallbackHandler() {
       
   330                     public void handle(Callback[] callbacks)
       
   331                             throws IOException, UnsupportedCallbackException {
       
   332                         String domain = null, name = null;
       
   333                         PasswordCallback pcb = null;
       
   334                         for (Callback cb: callbacks) {
       
   335                             if (cb instanceof NameCallback) {
       
   336                                 name = ((NameCallback)cb).getDefaultName();
       
   337                             } else if (cb instanceof RealmCallback) {
       
   338                                 domain = ((RealmCallback)cb).getDefaultText();
       
   339                             } else if (cb instanceof PasswordCallback) {
       
   340                                 pcb = (PasswordCallback)cb;
       
   341                             }
       
   342                         }
       
   343                         if (pcb != null) {
       
   344                             pcb.setPassword(getPass(domain, name));
       
   345                         }
       
   346                     }
       
   347                 });
       
   348 
       
   349         handshake(clnt, srv);
       
   350     }
       
   351 
       
   352     private static void checkAuthOnly() throws Exception {
       
   353         Map<String,Object> props = new HashMap<>();
       
   354         props.put(Sasl.QOP, "auth-conf");
       
   355         try {
       
   356             Sasl.createSaslClient(
       
   357                     new String[]{MECH}, USER2, PROTOCOL, REALM, props, null);
       
   358             throw new Exception("NTLM should not support auth-conf");
       
   359         } catch (SaslException se) {
       
   360             // Normal
       
   361         }
       
   362     }
       
   363 
       
   364     private static void handshake(SaslClient clnt, SaslServer srv)
       
   365             throws Exception {
       
   366         if (clnt == null) {
       
   367             throw new IllegalStateException(
       
   368                     "Unable to find client impl for " + MECH);
       
   369         }
       
   370         if (srv == null) {
       
   371             throw new IllegalStateException(
       
   372                     "Unable to find server impl for " + MECH);
       
   373         }
       
   374 
       
   375         byte[] response = (clnt.hasInitialResponse()
       
   376                 ? clnt.evaluateChallenge(EMPTY) : EMPTY);
       
   377         System.out.println("Initial:");
       
   378         new sun.misc.HexDumpEncoder().encodeBuffer(response, System.out);
       
   379         byte[] challenge;
       
   380 
       
   381         while (!clnt.isComplete() || !srv.isComplete()) {
       
   382             challenge = srv.evaluateResponse(response);
       
   383             response = null;
       
   384             if (challenge != null) {
       
   385                 System.out.println("Challenge:");
       
   386                 new sun.misc.HexDumpEncoder().encodeBuffer(challenge, System.out);
       
   387                 response = clnt.evaluateChallenge(challenge);
       
   388             }
       
   389             if (response != null) {
       
   390                 System.out.println("Response:");
       
   391                 new sun.misc.HexDumpEncoder().encodeBuffer(response, System.out);
       
   392             }
       
   393         }
       
   394 
       
   395         if (clnt.isComplete() && srv.isComplete()) {
       
   396             System.out.println("SUCCESS");
       
   397             if (!srv.getAuthorizationID().equals(USER1)) {
       
   398                 throw new Exception("Not correct user");
       
   399             }
       
   400         } else {
       
   401             throw new IllegalStateException(
       
   402                     "FAILURE: mismatched state:"
       
   403                     + " client complete? " + clnt.isComplete()
       
   404                     + " server complete? " + srv.isComplete());
       
   405         }
       
   406 
       
   407         if (!clnt.getNegotiatedProperty(Sasl.QOP).equals("auth") ||
       
   408                 !srv.getNegotiatedProperty(Sasl.QOP).equals("auth") ||
       
   409                 !clnt.getNegotiatedProperty(
       
   410                     "com.sun.security.sasl.ntlm.domain").equals(REALM)) {
       
   411             throw new Exception("Negotiated property error");
       
   412         }
       
   413         clnt.dispose();
       
   414         srv.dispose();
       
   415     }
       
   416 }