Path: blob/master/test/jdk/com/sun/security/sasl/ntlm/NTLMTest.java
41154 views
/*1* Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 6911951 715009226* @library /test/lib27* @summary NTLM should be a supported Java SASL mechanism28* @modules java.base/sun.security.util29* java.security.sasl30*/31import java.io.IOException;32import javax.security.sasl.*;33import javax.security.auth.callback.*;34import java.util.*;35import jdk.test.lib.hexdump.HexPrinter;3637public class NTLMTest {3839private static final String MECH = "NTLM";40private static final String REALM = "REALM";41private static final String PROTOCOL = "jmx";42private static final byte[] EMPTY = new byte[0];4344private static final String USER1 = "dummy";45private static final char[] PASS1 = "bogus".toCharArray();46private static final String USER2 = "foo";47private static final char[] PASS2 = "bar".toCharArray();4849private static final Map<String,char[]> maps =50new HashMap<String,char[]>();51static {52maps.put(USER1, PASS1);53maps.put(USER2, PASS2);54}5556static char[] getPass(String d, String u) {57if (!d.equals(REALM)) return null;58return maps.get(u);59}6061public static void main(String[] args) throws Exception {6263checkAuthOnly();64checkClientNameOverride();65checkClientDomainOverride();66checkVersions();67checkClientHostname();68}6970static void checkVersions() throws Exception {71// Server accepts all version72checkVersion(null, null);73checkVersion("LM/NTLM", null);74checkVersion("LM", null);75checkVersion("NTLM", null);76checkVersion("NTLM2", null);77checkVersion("LMv2/NTLMv2", null);78checkVersion("LMv2", null);79checkVersion("NTLMv2", null);8081// Client's default version is LMv282checkVersion(null, "LMv2");8384// Also works if they specified identical versions85checkVersion("LM/NTLM", "LM");86checkVersion("LM", "LM");87checkVersion("NTLM", "LM");88checkVersion("NTLM2", "NTLM2");89checkVersion("LMv2/NTLMv2", "LMv2");90checkVersion("LMv2", "LMv2");91checkVersion("NTLMv2", "LMv2");9293// But should not work if different94try {95checkVersion("LM/NTLM", "LMv2");96throw new Exception("Should not succeed");97} catch (SaslException se) {98// OK99}100try {101checkVersion("LMv2/NTLMv2", "LM");102throw new Exception("Should not succeed");103} catch (SaslException se) {104// OK105}106107}108109/**110* A test on version matching111* @param vc ntlm version specified for client112* @param vs ntlm version specified for server113* @throws Exception114*/115private static void checkVersion(String vc, String vs) throws Exception {116Map<String,Object> pc = new HashMap<>();117pc.put("com.sun.security.sasl.ntlm.version", vc);118Map<String,Object> ps = new HashMap<>();119ps.put("com.sun.security.sasl.ntlm.version", vs);120SaslClient clnt = Sasl.createSaslClient(121new String[]{MECH}, USER1, PROTOCOL, REALM, pc,122new CallbackHandler() {123public void handle(Callback[] callbacks)124throws IOException, UnsupportedCallbackException {125for (Callback cb: callbacks) {126if (cb instanceof PasswordCallback) {127((PasswordCallback)cb).setPassword(PASS1);128}129}130}131});132133SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, REALM, ps,134new CallbackHandler() {135public void handle(Callback[] callbacks)136throws IOException, UnsupportedCallbackException {137String domain = null, name = null;138PasswordCallback pcb = null;139for (Callback cb: callbacks) {140if (cb instanceof NameCallback) {141name = ((NameCallback)cb).getDefaultName();142} else if (cb instanceof RealmCallback) {143domain = ((RealmCallback)cb).getDefaultText();144} else if (cb instanceof PasswordCallback) {145pcb = (PasswordCallback)cb;146}147}148if (pcb != null) {149pcb.setPassword(getPass(domain, name));150}151}152});153154handshake(clnt, srv);155}156157private static void checkClientHostname() throws Exception {158Map<String,Object> pc = new HashMap<>();159pc.put("com.sun.security.sasl.ntlm.hostname", "this.is.com");160SaslClient clnt = Sasl.createSaslClient(161new String[]{MECH}, USER1, PROTOCOL, REALM, pc,162new CallbackHandler() {163public void handle(Callback[] callbacks)164throws IOException, UnsupportedCallbackException {165for (Callback cb: callbacks) {166if (cb instanceof PasswordCallback) {167((PasswordCallback)cb).setPassword(PASS1);168}169}170}171});172173SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, REALM, null,174new CallbackHandler() {175public void handle(Callback[] callbacks)176throws IOException, UnsupportedCallbackException {177String domain = null, name = null;178PasswordCallback pcb = null;179for (Callback cb: callbacks) {180if (cb instanceof NameCallback) {181name = ((NameCallback)cb).getDefaultName();182} else if (cb instanceof RealmCallback) {183domain = ((RealmCallback)cb).getDefaultText();184} else if (cb instanceof PasswordCallback) {185pcb = (PasswordCallback)cb;186}187}188if (pcb != null) {189pcb.setPassword(getPass(domain, name));190}191}192});193194handshake(clnt, srv);195if (!"this.is.com".equals(196srv.getNegotiatedProperty("com.sun.security.sasl.ntlm.hostname"))) {197throw new Exception("Hostname not trasmitted to server");198}199}200201/**202* Client realm override, but finally overridden by server response203*/204private static void checkClientDomainOverride() throws Exception {205SaslClient clnt = Sasl.createSaslClient(206new String[]{MECH}, USER1, PROTOCOL, "ANOTHERREALM", null,207new CallbackHandler() {208public void handle(Callback[] callbacks)209throws IOException, UnsupportedCallbackException {210for (Callback cb: callbacks) {211if (cb instanceof RealmCallback) {212((RealmCallback)cb).setText(REALM);213} else if (cb instanceof PasswordCallback) {214((PasswordCallback)cb).setPassword(PASS1);215}216}217}218});219220SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, REALM, null,221new CallbackHandler() {222public void handle(Callback[] callbacks)223throws IOException, UnsupportedCallbackException {224String domain = null, name = null;225PasswordCallback pcb = null;226for (Callback cb: callbacks) {227if (cb instanceof NameCallback) {228name = ((NameCallback)cb).getDefaultName();229} else if (cb instanceof RealmCallback) {230domain = ((RealmCallback)cb).getDefaultText();231} else if (cb instanceof PasswordCallback) {232pcb = (PasswordCallback)cb;233}234}235if (pcb != null) {236pcb.setPassword(getPass(domain, name));237}238}239});240241handshake(clnt, srv);242}243244/**245* Client side user name provided in callback.246* @throws Exception247*/248private static void checkClientNameOverride() throws Exception {249SaslClient clnt = Sasl.createSaslClient(250new String[]{MECH}, "someone", PROTOCOL, REALM, null,251new CallbackHandler() {252public void handle(Callback[] callbacks)253throws IOException, UnsupportedCallbackException {254for (Callback cb: callbacks) {255if (cb instanceof NameCallback) {256NameCallback ncb = (NameCallback) cb;257ncb.setName(USER1);258} else if (cb instanceof PasswordCallback) {259((PasswordCallback)cb).setPassword(PASS1);260}261}262}263});264265SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, "FAKE", null,266new CallbackHandler() {267public void handle(Callback[] callbacks)268throws IOException, UnsupportedCallbackException {269String domain = null, name = null;270PasswordCallback pcb = null;271for (Callback cb: callbacks) {272if (cb instanceof NameCallback) {273name = ((NameCallback)cb).getDefaultName();274} else if (cb instanceof RealmCallback) {275domain = ((RealmCallback)cb).getDefaultText();276} else if (cb instanceof PasswordCallback) {277pcb = (PasswordCallback)cb;278}279}280if (pcb != null) {281pcb.setPassword(getPass(domain, name));282}283}284});285286handshake(clnt, srv);287}288289private static void checkAuthOnly() throws Exception {290Map<String,Object> props = new HashMap<>();291props.put(Sasl.QOP, "auth-conf");292try {293Sasl.createSaslClient(294new String[]{MECH}, USER2, PROTOCOL, REALM, props, null);295throw new Exception("NTLM should not support auth-conf");296} catch (SaslException se) {297// Normal298}299}300301private static void handshake(SaslClient clnt, SaslServer srv)302throws Exception {303if (clnt == null) {304throw new IllegalStateException(305"Unable to find client impl for " + MECH);306}307if (srv == null) {308throw new IllegalStateException(309"Unable to find server impl for " + MECH);310}311312byte[] response = (clnt.hasInitialResponse()313? clnt.evaluateChallenge(EMPTY) : EMPTY);314System.out.println("Initial:");315HexPrinter.simple().format(response);316byte[] challenge;317318while (!clnt.isComplete() || !srv.isComplete()) {319challenge = srv.evaluateResponse(response);320response = null;321if (challenge != null) {322System.out.println("Challenge:");323HexPrinter.simple().format(challenge);324response = clnt.evaluateChallenge(challenge);325}326if (response != null) {327System.out.println("Response:");328HexPrinter.simple().format(response);329}330}331332if (clnt.isComplete() && srv.isComplete()) {333System.out.println("SUCCESS");334if (!srv.getAuthorizationID().equals(USER1)) {335throw new Exception("Not correct user");336}337} else {338throw new IllegalStateException(339"FAILURE: mismatched state:"340+ " client complete? " + clnt.isComplete()341+ " server complete? " + srv.isComplete());342}343344if (!clnt.getNegotiatedProperty(Sasl.QOP).equals("auth") ||345!srv.getNegotiatedProperty(Sasl.QOP).equals("auth") ||346!clnt.getNegotiatedProperty(347"com.sun.security.sasl.ntlm.domain").equals(REALM)) {348throw new Exception("Negotiated property error");349}350clnt.dispose();351srv.dispose();352}353}354355356