View Javadoc

    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one
    3    *  or more contributor license agreements.  See the NOTICE file
    4    *  distributed with this work for additional information
    5    *  regarding copyright ownership.  The ASF licenses this file
    6    *  to you under the Apache License, Version 2.0 (the
    7    *  "License"); you may not use this file except in compliance
    8    *  with the License.  You may obtain a copy of the License at
    9    *
    10   *    http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   *  Unless required by applicable law or agreed to in writing,
    13   *  software distributed under the License is distributed on an
    14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    15   *  KIND, either express or implied.  See the License for the
    16   *  specific language governing permissions and limitations
    17   *  under the License.
    18   *
    19   */
    20  package org.apache.mina.proxy;
    21
    22  import static org.apache.mina.proxy.utils.ByteUtilities.asHex;
    23  import static org.junit.Assert.assertEquals;
    24
    25  import java.io.PrintWriter;
    26  import java.io.UnsupportedEncodingException;
    27  import java.security.MessageDigest;
    28  import java.security.NoSuchAlgorithmException;
    29  import java.security.Security;
    30
    31  import org.apache.mina.proxy.handlers.http.ntlm.NTLMResponses;
    32  import org.apache.mina.proxy.handlers.http.ntlm.NTLMUtilities;
    33  import org.apache.mina.proxy.utils.ByteUtilities;
    34  import org.apache.mina.proxy.utils.MD4Provider;
    35  import org.junit.Test;
    36  import org.slf4j.Logger;
    37  import org.slf4j.LoggerFactory;
    38
    39  /**
    40   * NTLMTest.java - JUNIT tests of the NTLM authentication mechanism.
    41   *
    42   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
    43   * @since MINA 2.0.0-M3
    44   */
    45  public class NTLMTest {
    46      private final static Logger logger = LoggerFactory.getLogger(NTLMTest.class);
    47
    48      static {
    49          if (Security.getProvider("MINA") == null) {
    50              Security.addProvider(new MD4Provider());
    51          }
    52      }
    53
    54      /**
    55       * Tests bytes manipulations.
    56       */
    57      @Test
    58      public void testEncoding() throws UnsupportedEncodingException {
    59          assertEquals("d204", asHex(ByteUtilities.writeShort((short) 1234)));
    60          assertEquals("d2040000", asHex(ByteUtilities.writeInt(1234)));
    61          assertEquals("01000000", asHex(ByteUtilities.writeInt((short) 1)));
    62          assertEquals("4e544c4d53535000", asHex(NTLMUtilities.NTLM_SIGNATURE));
    63
    64          assertEquals("680065006c006c006f00", asHex(ByteUtilities.getUTFStringAsByteArray("hello")));
    65          assertEquals("48454c4c4f", asHex(ByteUtilities.getOEMStringAsByteArray("HELLO")));
    66      }
    67
    68      /**
    69       * Tests conversions to and from network byte order.
    70       */
    71      @Test
    72      public void testMethods() {
    73          byte[] buf = new byte[4];
    74          ByteUtilities.intToNetworkByteOrder(1234, buf, 0, 4);
    75          assertEquals("000004d2", asHex(buf));
    76          assertEquals(1234, ByteUtilities.networkByteOrderToInt(buf, 0, 4));
    77      }
    78
    79      /**
    80       * Tests security buffers.
    81       */
    82      @Test
    83      public void testSecurityBuffer() {
    84          byte[] secBuf = new byte[8];
    85          NTLMUtilities.writeSecurityBuffer((short) 1234, (short) 1234, 4321, secBuf, 0);
    86          assertEquals("d204d204e1100000", asHex(secBuf));
    87      }
    88
    89      /**
    90       * Tests creating a type 1 message.
    91       */
    92      @Test
    93      public void testType1Message() {
    94          int customFlags = NTLMUtilities.FLAG_NEGOTIATE_UNICODE | NTLMUtilities.FLAG_NEGOTIATE_OEM
    95                  | NTLMUtilities.FLAG_NEGOTIATE_NTLM | NTLMUtilities.FLAG_REQUEST_SERVER_AUTH_REALM
    96                  | NTLMUtilities.FLAG_NEGOTIATE_DOMAIN_SUPPLIED | NTLMUtilities.FLAG_NEGOTIATE_WORKSTATION_SUPPLIED;
    97
    98          byte[] osVer = new byte[8];
    99          NTLMUtilities.writeOSVersion((byte) 5, (byte) 0, (short) 2195, osVer, 0);
    100
    101         String msgType1 = asHex(NTLMUtilities.createType1Message("WORKSTATION", "DOMAIN", customFlags, osVer));
    102         assertEquals("4e544c4d53535000010000000732000006000600330000000b000b0028000000"
    103                 + "050093080000000f574f524b53544154494f4e444f4d41494e", msgType1);
    104
    105         assertEquals("050093080000000f", asHex(osVer));
    106
    107         //Microsoft Windows XP [version 5.1.2600]
    108         String os = System.getProperty("os.name");
    109         if (os != null && os.toUpperCase().contains("WINDOWS") && "5.1".equals(System.getProperty("os.version"))) {
    110             String hex = asHex(NTLMUtilities.getOsVersion());
    111             assertEquals("0501", hex.substring(0, 4));
    112             assertEquals(16, hex.length());
    113         }
    114     }
    115
    116     /**
    117      * Tests creating a type 3 message.
    118      * WARNING: Will silently fail if no MD4 digest provider is available.
    119      */
    120     @Test
    121     public void testType3Message() throws Exception {
    122         try {
    123             MessageDigest.getInstance("MD4");
    124         } catch (NoSuchAlgorithmException ex) {
    125             logger.warn("No MD4 digest provider found !");
    126             return;
    127         }
    128
    129         int flags = 0x00000001 | 0x00000200 | 0x00010000 | 0x00800000;
    130         String msg = "4e544c4d53535000020000000c000c003000000001028100"
    131                 + "0123456789abcdef0000000000000000620062003c000000"
    132                 + "44004f004d00410049004e0002000c0044004f004d004100"
    133                 + "49004e0001000c0053004500520056004500520004001400"
    134                 + "64006f006d00610069006e002e0063006f006d0003002200"
    135                 + "7300650072007600650072002e0064006f006d0061006900" + "6e002e0063006f006d0000000000";
    136
    137         byte[] challengePacket = ByteUtilities.asByteArray(msg);
    138         int serverFlags = NTLMUtilities.extractFlagsFromType2Message(challengePacket);
    139         assertEquals(flags, serverFlags);
    140
    141         NTLMUtilities.printTargetInformationBlockFromType2Message(challengePacket, serverFlags, new PrintWriter(
    142                 System.out, true));
    143
    144         byte[] osVer = new byte[8];
    145         NTLMUtilities.writeOSVersion((byte) 5, (byte) 0, (short) 2195, osVer, 0);
    146
    147         byte[] challenge = NTLMUtilities.extractChallengeFromType2Message(challengePacket);
    148         assertEquals("0123456789abcdef", asHex(challenge));
    149
    150         String expectedTargetInfoBlock = "02000c0044004f004d00410049004e00" + "01000c00530045005200560045005200"
    151                 + "0400140064006f006d00610069006e00" + "2e0063006f006d000300220073006500"
    152                 + "72007600650072002e0064006f006d00" + "610069006e002e0063006f006d000000" + "0000";
    153
    154         byte[] targetInfo = NTLMUtilities.extractTargetInfoFromType2Message(challengePacket, null);
    155         assertEquals(expectedTargetInfoBlock, asHex(targetInfo));
    156
    157         assertEquals("DOMAIN",
    158                 NTLMUtilities.extractTargetNameFromType2Message(challengePacket, new Integer(serverFlags)));
    159
    160         serverFlags = 0x00000001 | 0x00000200;
    161         String msgType3 = asHex(NTLMUtilities.createType3Message("user", "SecREt01", challenge, "DOMAIN",
    162                 "WORKSTATION", serverFlags, null));
    163
    164         String expected = "4e544c4d5353500003000000180018006a00000018001800"
    165                 + "820000000c000c0040000000080008004c00000016001600"
    166                 + "54000000000000009a0000000102000044004f004d004100"
    167                 + "49004e00750073006500720057004f0052004b0053005400"
    168                 + "4100540049004f004e00c337cd5cbd44fc9782a667af6d42"
    169                 + "7c6de67c20c2d3e77c5625a98c1c31e81847466b29b2df46" + "80f39958fb8c213a9cc6";
    170         assertEquals(expected, msgType3);
    171     }
    172
    173     /**
    174      * Tests flags manipulations.
    175      */
    176     @Test
    177     public void testFlags() {
    178         int flags = NTLMUtilities.FLAG_NEGOTIATE_UNICODE | NTLMUtilities.FLAG_REQUEST_SERVER_AUTH_REALM
    179                 | NTLMUtilities.FLAG_NEGOTIATE_NTLM | NTLMUtilities.FLAG_NEGOTIATE_ALWAYS_SIGN;
    180
    181         int flags2 = NTLMUtilities.FLAG_NEGOTIATE_UNICODE | NTLMUtilities.FLAG_REQUEST_SERVER_AUTH_REALM
    182                 | NTLMUtilities.FLAG_NEGOTIATE_NTLM;
    183
    184         assertEquals(flags2, flags & (~NTLMUtilities.FLAG_NEGOTIATE_ALWAYS_SIGN));
    185         assertEquals(flags2, flags2 & (~NTLMUtilities.FLAG_NEGOTIATE_ALWAYS_SIGN));
    186         assertEquals("05820000", asHex(ByteUtilities.writeInt(flags)));
    187
    188         byte[] testFlags = ByteUtilities.asByteArray("7F808182");
    189         assertEquals("7f808182", asHex(testFlags));
    190         ByteUtilities.changeByteEndianess(testFlags, 0, 4);
    191         assertEquals("807f8281", asHex(testFlags));
    192         ByteUtilities.changeByteEndianess(testFlags, 0, 4);
    193         ByteUtilities.changeWordEndianess(testFlags, 0, 4);
    194         assertEquals("8281807f", asHex(testFlags));
    195     }
    196
    197     /**
    198      * Tests response computing.
    199      * WARNING: Will silently fail if no MD4 digest provider is available.
    200      */
    201     @Test
    202     public void testResponses() throws Exception {
    203         try {
    204             MessageDigest.getInstance("MD4");
    205         } catch (NoSuchAlgorithmException ex) {
    206             logger.warn("No MD4 digest provider found !");
    207             return;
    208         }
    209
    210         String LMResponse = "c337cd5cbd44fc9782a667af6d427c6de67c20c2d3e77c56";
    211
    212         assertEquals(LMResponse,
    213                 asHex(NTLMResponses.getLMResponse("SecREt01", ByteUtilities.asByteArray("0123456789abcdef"))));
    214
    215         String NTLMResponse = "25a98c1c31e81847466b29b2df4680f39958fb8c213a9cc6";
    216
    217         assertEquals(NTLMResponse,
    218                 asHex(NTLMResponses.getNTLMResponse("SecREt01", ByteUtilities.asByteArray("0123456789abcdef"))));
    219
    220         String LMv2Response = "d6e6152ea25d03b7c6ba6629c2d6aaf0ffffff0011223344";
    221
    222         assertEquals(
    223                 LMv2Response,
    224                 asHex(NTLMResponses.getLMv2Response("DOMAIN", "user", "SecREt01",
    225                         ByteUtilities.asByteArray("0123456789abcdef"), ByteUtilities.asByteArray("ffffff0011223344"))));
    226
    227         String NTLM2Response = "10d550832d12b2ccb79d5ad1f4eed3df82aca4c3681dd455";
    228
    229         assertEquals(NTLM2Response, asHex(NTLMResponses.getNTLM2SessionResponse("SecREt01",
    230                 ByteUtilities.asByteArray("0123456789abcdef"), ByteUtilities.asByteArray("ffffff0011223344"))));
    231
    232         String NTLMv2Response = "cbabbca713eb795d04c97abc01ee4983" + "01010000000000000090d336b734c301"
    233                 + "ffffff00112233440000000002000c00" + "44004f004d00410049004e0001000c00"
    234                 + "53004500520056004500520004001400" + "64006f006d00610069006e002e006300"
    235                 + "6f006d00030022007300650072007600" + "650072002e0064006f006d0061006900"
    236                 + "6e002e0063006f006d00000000000000" + "0000";
    237
    238         String targetInformation = "02000c0044004f004d00410049004e00" + "01000c00530045005200560045005200"
    239                 + "0400140064006f006d00610069006e00" + "2e0063006f006d000300220073006500"
    240                 + "72007600650072002e0064006f006d00" + "610069006e002e0063006f006d000000" + "0000";
    241
    242         assertEquals(NTLMv2Response, asHex(NTLMResponses.getNTLMv2Response("DOMAIN", "user", "SecREt01",
    243                 ByteUtilities.asByteArray(targetInformation), ByteUtilities.asByteArray("0123456789abcdef"),
    244                 ByteUtilities.asByteArray("ffffff0011223344"), 1055844000000L)));
    245     }
    246 }