001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.mina.proxy; 021 022import static org.apache.mina.proxy.utils.ByteUtilities.asHex; 023import static org.junit.Assert.assertEquals; 024 025import java.io.PrintWriter; 026import java.io.UnsupportedEncodingException; 027import java.security.MessageDigest; 028import java.security.NoSuchAlgorithmException; 029 030import org.apache.mina.proxy.handlers.http.ntlm.NTLMResponses; 031import org.apache.mina.proxy.handlers.http.ntlm.NTLMUtilities; 032import org.apache.mina.proxy.utils.ByteUtilities; 033import org.junit.Test; 034import org.slf4j.Logger; 035import org.slf4j.LoggerFactory; 036 037/** 038 * NTLMTest.java - JUNIT tests of the NTLM authentication mechanism. 039 * 040 * @author <a href="http://mina.apache.org">Apache MINA Project</a> 041 * @since MINA 2.0.0-M3 042 */ 043public class NTLMTest { 044 private final static Logger logger = LoggerFactory.getLogger(NTLMTest.class); 045 046 /** 047 * Tests bytes manipulations. 048 */ 049 @Test 050 public void testEncoding() throws UnsupportedEncodingException { 051 assertEquals("d204", asHex(ByteUtilities.writeShort((short) 1234))); 052 assertEquals("d2040000", asHex(ByteUtilities.writeInt(1234))); 053 assertEquals("01000000", asHex(ByteUtilities.writeInt((short) 1))); 054 assertEquals("4e544c4d53535000", asHex(NTLMUtilities.NTLM_SIGNATURE)); 055 056 assertEquals("680065006c006c006f00", asHex(ByteUtilities.getUTFStringAsByteArray("hello"))); 057 assertEquals("48454c4c4f", asHex(ByteUtilities.getOEMStringAsByteArray("HELLO"))); 058 } 059 060 /** 061 * Tests conversions to and from network byte order. 062 */ 063 @Test 064 public void testMethods() { 065 byte[] buf = new byte[4]; 066 ByteUtilities.intToNetworkByteOrder(1234, buf, 0, 4); 067 assertEquals("000004d2", asHex(buf)); 068 assertEquals(1234, ByteUtilities.networkByteOrderToInt(buf, 0, 4)); 069 } 070 071 /** 072 * Tests security buffers. 073 */ 074 @Test 075 public void testSecurityBuffer() { 076 byte[] secBuf = new byte[8]; 077 NTLMUtilities.writeSecurityBuffer((short) 1234, (short) 1234, 4321, secBuf, 0); 078 assertEquals("d204d204e1100000", asHex(secBuf)); 079 } 080 081 /** 082 * Tests creating a type 1 message. 083 */ 084 @Test 085 public void testType1Message() { 086 int customFlags = NTLMUtilities.FLAG_NEGOTIATE_UNICODE | NTLMUtilities.FLAG_NEGOTIATE_OEM 087 | NTLMUtilities.FLAG_NEGOTIATE_NTLM | NTLMUtilities.FLAG_REQUEST_SERVER_AUTH_REALM 088 | NTLMUtilities.FLAG_NEGOTIATE_DOMAIN_SUPPLIED | NTLMUtilities.FLAG_NEGOTIATE_WORKSTATION_SUPPLIED; 089 090 byte[] osVer = new byte[8]; 091 NTLMUtilities.writeOSVersion((byte) 5, (byte) 0, (short) 2195, osVer, 0); 092 093 String msgType1 = asHex(NTLMUtilities.createType1Message("WORKSTATION", "DOMAIN", customFlags, osVer)); 094 assertEquals("4e544c4d53535000010000000732000006000600330000000b000b0028000000" 095 + "050093080000000f574f524b53544154494f4e444f4d41494e", msgType1); 096 097 assertEquals("050093080000000f", asHex(osVer)); 098 099 //Microsoft Windows XP [version 5.1.2600] 100 String os = System.getProperty("os.name"); 101 if (os != null && os.toUpperCase().contains("WINDOWS") && "5.1".equals(System.getProperty("os.version"))) { 102 String hex = asHex(NTLMUtilities.getOsVersion()); 103 assertEquals("0501", hex.substring(0, 4)); 104 assertEquals(16, hex.length()); 105 } 106 } 107 108 /** 109 * Tests creating a type 3 message. 110 * WARNING: Will silently fail if no MD4 digest provider is available. 111 */ 112 @Test 113 public void testType3Message() throws Exception { 114 try { 115 MessageDigest.getInstance("MD4"); 116 } catch (NoSuchAlgorithmException ex) { 117 logger.warn("No MD4 digest provider found !"); 118 return; 119 } 120 121 int flags = 0x00000001 | 0x00000200 | 0x00010000 | 0x00800000; 122 String msg = "4e544c4d53535000020000000c000c003000000001028100" 123 + "0123456789abcdef0000000000000000620062003c000000" 124 + "44004f004d00410049004e0002000c0044004f004d004100" 125 + "49004e0001000c0053004500520056004500520004001400" 126 + "64006f006d00610069006e002e0063006f006d0003002200" 127 + "7300650072007600650072002e0064006f006d0061006900" + "6e002e0063006f006d0000000000"; 128 129 byte[] challengePacket = ByteUtilities.asByteArray(msg); 130 int serverFlags = NTLMUtilities.extractFlagsFromType2Message(challengePacket); 131 assertEquals(flags, serverFlags); 132 133 NTLMUtilities.printTargetInformationBlockFromType2Message(challengePacket, serverFlags, new PrintWriter( 134 System.out, true)); 135 136 byte[] osVer = new byte[8]; 137 NTLMUtilities.writeOSVersion((byte) 5, (byte) 0, (short) 2195, osVer, 0); 138 139 byte[] challenge = NTLMUtilities.extractChallengeFromType2Message(challengePacket); 140 assertEquals("0123456789abcdef", asHex(challenge)); 141 142 String expectedTargetInfoBlock = "02000c0044004f004d00410049004e00" + "01000c00530045005200560045005200" 143 + "0400140064006f006d00610069006e00" + "2e0063006f006d000300220073006500" 144 + "72007600650072002e0064006f006d00" + "610069006e002e0063006f006d000000" + "0000"; 145 146 byte[] targetInfo = NTLMUtilities.extractTargetInfoFromType2Message(challengePacket, null); 147 assertEquals(expectedTargetInfoBlock, asHex(targetInfo)); 148 149 assertEquals("DOMAIN", 150 NTLMUtilities.extractTargetNameFromType2Message(challengePacket, new Integer(serverFlags))); 151 152 serverFlags = 0x00000001 | 0x00000200; 153 String msgType3 = asHex(NTLMUtilities.createType3Message("user", "SecREt01", challenge, "DOMAIN", 154 "WORKSTATION", serverFlags, null)); 155 156 String expected = "4e544c4d5353500003000000180018006a00000018001800" 157 + "820000000c000c0040000000080008004c00000016001600" 158 + "54000000000000009a0000000102000044004f004d004100" 159 + "49004e00750073006500720057004f0052004b0053005400" 160 + "4100540049004f004e00c337cd5cbd44fc9782a667af6d42" 161 + "7c6de67c20c2d3e77c5625a98c1c31e81847466b29b2df46" + "80f39958fb8c213a9cc6"; 162 assertEquals(expected, msgType3); 163 } 164 165 /** 166 * Tests flags manipulations. 167 */ 168 @Test 169 public void testFlags() { 170 int flags = NTLMUtilities.FLAG_NEGOTIATE_UNICODE | NTLMUtilities.FLAG_REQUEST_SERVER_AUTH_REALM 171 | NTLMUtilities.FLAG_NEGOTIATE_NTLM | NTLMUtilities.FLAG_NEGOTIATE_ALWAYS_SIGN; 172 173 int flags2 = NTLMUtilities.FLAG_NEGOTIATE_UNICODE | NTLMUtilities.FLAG_REQUEST_SERVER_AUTH_REALM 174 | NTLMUtilities.FLAG_NEGOTIATE_NTLM; 175 176 assertEquals(flags2, flags & (~NTLMUtilities.FLAG_NEGOTIATE_ALWAYS_SIGN)); 177 assertEquals(flags2, flags2 & (~NTLMUtilities.FLAG_NEGOTIATE_ALWAYS_SIGN)); 178 assertEquals("05820000", asHex(ByteUtilities.writeInt(flags))); 179 180 byte[] testFlags = ByteUtilities.asByteArray("7F808182"); 181 assertEquals("7f808182", asHex(testFlags)); 182 ByteUtilities.changeByteEndianess(testFlags, 0, 4); 183 assertEquals("807f8281", asHex(testFlags)); 184 ByteUtilities.changeByteEndianess(testFlags, 0, 4); 185 ByteUtilities.changeWordEndianess(testFlags, 0, 4); 186 assertEquals("8281807f", asHex(testFlags)); 187 } 188 189 /** 190 * Tests response computing. 191 * WARNING: Will silently fail if no MD4 digest provider is available. 192 */ 193 @Test 194 public void testResponses() throws Exception { 195 try { 196 MessageDigest.getInstance("MD4"); 197 } catch (NoSuchAlgorithmException ex) { 198 logger.warn("No MD4 digest provider found !"); 199 return; 200 } 201 202 String LMResponse = "c337cd5cbd44fc9782a667af6d427c6de67c20c2d3e77c56"; 203 204 assertEquals(LMResponse, 205 asHex(NTLMResponses.getLMResponse("SecREt01", ByteUtilities.asByteArray("0123456789abcdef")))); 206 207 String NTLMResponse = "25a98c1c31e81847466b29b2df4680f39958fb8c213a9cc6"; 208 209 assertEquals(NTLMResponse, 210 asHex(NTLMResponses.getNTLMResponse("SecREt01", ByteUtilities.asByteArray("0123456789abcdef")))); 211 212 String LMv2Response = "d6e6152ea25d03b7c6ba6629c2d6aaf0ffffff0011223344"; 213 214 assertEquals( 215 LMv2Response, 216 asHex(NTLMResponses.getLMv2Response("DOMAIN", "user", "SecREt01", 217 ByteUtilities.asByteArray("0123456789abcdef"), ByteUtilities.asByteArray("ffffff0011223344")))); 218 219 String NTLM2Response = "10d550832d12b2ccb79d5ad1f4eed3df82aca4c3681dd455"; 220 221 assertEquals(NTLM2Response, asHex(NTLMResponses.getNTLM2SessionResponse("SecREt01", 222 ByteUtilities.asByteArray("0123456789abcdef"), ByteUtilities.asByteArray("ffffff0011223344")))); 223 224 String NTLMv2Response = "cbabbca713eb795d04c97abc01ee4983" + "01010000000000000090d336b734c301" 225 + "ffffff00112233440000000002000c00" + "44004f004d00410049004e0001000c00" 226 + "53004500520056004500520004001400" + "64006f006d00610069006e002e006300" 227 + "6f006d00030022007300650072007600" + "650072002e0064006f006d0061006900" 228 + "6e002e0063006f006d00000000000000" + "0000"; 229 230 String targetInformation = "02000c0044004f004d00410049004e00" + "01000c00530045005200560045005200" 231 + "0400140064006f006d00610069006e00" + "2e0063006f006d000300220073006500" 232 + "72007600650072002e0064006f006d00" + "610069006e002e0063006f006d000000" + "0000"; 233 234 assertEquals(NTLMv2Response, asHex(NTLMResponses.getNTLMv2Response("DOMAIN", "user", "SecREt01", 235 ByteUtilities.asByteArray(targetInformation), ByteUtilities.asByteArray("0123456789abcdef"), 236 ByteUtilities.asByteArray("ffffff0011223344"), 1055844000000L))); 237 } 238}