001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.security.ntlm;
016    
017    import com.liferay.portal.kernel.util.ArrayUtil;
018    import com.liferay.portal.kernel.util.StringPool;
019    
020    import java.io.IOException;
021    import java.io.UnsupportedEncodingException;
022    
023    import java.security.MessageDigest;
024    import java.security.NoSuchAlgorithmException;
025    
026    import jcifs.ntlmssp.NtlmFlags;
027    import jcifs.ntlmssp.Type1Message;
028    import jcifs.ntlmssp.Type2Message;
029    import jcifs.ntlmssp.Type3Message;
030    
031    import jcifs.util.Encdec;
032    
033    /**
034     * @author Marcellus Tavares
035     * @author Michael C. Han
036     */
037    public class NtlmManager {
038    
039            public NtlmManager(
040                    String domain, String domainController, String domainControllerName,
041                    String serviceAccount, String servicePassword) {
042    
043                    setConfiguration(
044                            domain, domainController, domainControllerName, serviceAccount,
045                            servicePassword);
046            }
047    
048            public NtlmUserAccount authenticate(byte[] material, byte[] serverChallenge)
049                    throws IOException, NoSuchAlgorithmException, NtlmLogonException {
050    
051                    Type3Message type3Message = new Type3Message(material);
052    
053                    if (type3Message.getFlag(
054                                    _NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY) &&
055                            (type3Message.getNTResponse().length == 24)) {
056    
057                            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
058    
059                            byte[] bytes = new byte[16];
060    
061                            System.arraycopy(serverChallenge, 0, bytes, 0, 8);
062                            System.arraycopy(type3Message.getLMResponse(), 0, bytes, 8, 8);
063    
064                            messageDigest.update(bytes);
065    
066                            serverChallenge = messageDigest.digest();
067                    }
068    
069                    return _netlogon.logon(
070                            type3Message.getDomain(), type3Message.getUser(),
071                            type3Message.getWorkstation(), serverChallenge,
072                            type3Message.getNTResponse(), type3Message.getLMResponse());
073            }
074    
075            public String getDomain() {
076                    return _domain;
077            }
078    
079            public String getDomainController() {
080                    return _domainController;
081            }
082    
083            public String getDomainControllerName() {
084                    return _domainControllerName;
085            }
086    
087            public String getServiceAccount() {
088                    return _ntlmServiceAccount.getAccount();
089            }
090    
091            public String getServicePassword() {
092                    return _ntlmServiceAccount.getPassword();
093            }
094    
095            public byte[] negotiate(byte[] material, byte[] serverChallenge)
096                    throws IOException {
097    
098                    Type1Message type1Message = new Type1Message(material);
099    
100                    Type2Message type2Message = new Type2Message(
101                            type1Message.getFlags(), serverChallenge, _domain);
102    
103                    if (type2Message.getFlag(
104                                    _NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY)) {
105    
106                            type2Message.setFlag(NtlmFlags.NTLMSSP_NEGOTIATE_LM_KEY, false);
107                            type2Message.setFlag(NtlmFlags.NTLMSSP_NEGOTIATE_TARGET_INFO, true);
108                            type2Message.setTargetInformation(getTargetInformation());
109                    }
110    
111                    return type2Message.toByteArray();
112            }
113    
114            public void setConfiguration(
115                    String domain, String domainController, String domainControllerName,
116                    String serviceAccount, String servicePassword) {
117    
118                    _domain = domain;
119                    _domainController = domainController;
120                    _domainControllerName = domainControllerName;
121                    _ntlmServiceAccount = new NtlmServiceAccount(
122                            serviceAccount, servicePassword);
123    
124                    _netlogon = new Netlogon();
125    
126                    _netlogon.setConfiguration(
127                            domainController, domainControllerName, _ntlmServiceAccount);
128            }
129    
130            protected byte[] getAVPairBytes(int avId, String value)
131                    throws UnsupportedEncodingException {
132    
133                    byte[] valueBytes = value.getBytes("UTF-16LE");
134                    byte[] avPairBytes = new byte[4 + valueBytes.length];
135    
136                    Encdec.enc_uint16le((short)avId, avPairBytes, 0);
137                    Encdec.enc_uint16le((short)valueBytes.length, avPairBytes, 2);
138    
139                    System.arraycopy(valueBytes, 0, avPairBytes, 4, valueBytes.length);
140    
141                    return avPairBytes;
142            }
143    
144            protected byte[] getTargetInformation()
145                    throws UnsupportedEncodingException {
146    
147                    byte[] computerName = getAVPairBytes(
148                            1, _ntlmServiceAccount.getComputerName());
149                    byte[] domainName = getAVPairBytes(2, _domain);
150    
151                    byte[] targetInformation = ArrayUtil.append(computerName, domainName);
152    
153                    byte[] eol = getAVPairBytes(0, StringPool.BLANK);
154    
155                    targetInformation = ArrayUtil.append(targetInformation, eol);
156    
157                    return targetInformation;
158            }
159    
160            private static final int _NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY =
161                    0x00080000;
162    
163            private String _domain;
164            private String _domainController;
165            private String _domainControllerName;
166            private Netlogon _netlogon;
167            private NtlmServiceAccount _ntlmServiceAccount;
168    
169    }