001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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(
049                            byte[] material, byte[] serverChallenge)
050                    throws IOException, NoSuchAlgorithmException, NtlmLogonException {
051    
052                    Type3Message type3Message = new Type3Message(material);
053    
054                    if (type3Message.getFlag(
055                                    _NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY) &&
056                            (type3Message.getNTResponse().length == 24)) {
057    
058                            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
059    
060                            byte[] bytes = new byte[16];
061    
062                            System.arraycopy(serverChallenge, 0, bytes, 0, 8);
063                            System.arraycopy(type3Message.getLMResponse(), 0, bytes, 8, 8);
064    
065                            messageDigest.update(bytes);
066    
067                            serverChallenge = messageDigest.digest();
068                    }
069    
070                    return _netlogon.logon(
071                             type3Message.getDomain(), type3Message.getUser(),
072                             type3Message.getWorkstation(), serverChallenge,
073                             type3Message.getNTResponse(), type3Message.getLMResponse());
074            }
075    
076            public String getDomain() {
077                    return _domain;
078            }
079    
080            public String getDomainController() {
081                    return _domainController;
082            }
083    
084            public String getDomainControllerName() {
085                    return _domainControllerName;
086            }
087    
088            public String getServiceAccount() {
089                    return _ntlmServiceAccount.getAccount();
090            }
091    
092            public String getServicePassword() {
093                    return _ntlmServiceAccount.getPassword();
094            }
095    
096            public byte[] negotiate(byte[] material, byte[] serverChallenge)
097                    throws IOException {
098    
099                    Type1Message type1Message = new Type1Message(material);
100    
101                    Type2Message type2Message = new Type2Message(
102                            type1Message.getFlags(), serverChallenge, _domain);
103    
104                    if (type2Message.getFlag(
105                                    _NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY)) {
106    
107                            type2Message.setFlag(NtlmFlags.NTLMSSP_NEGOTIATE_LM_KEY, false);
108                            type2Message.setFlag(NtlmFlags.NTLMSSP_NEGOTIATE_TARGET_INFO, true);
109                            type2Message.setTargetInformation(getTargetInformation());
110                    }
111    
112                    return type2Message.toByteArray();
113            }
114    
115            public void setConfiguration(
116                    String domain, String domainController, String domainControllerName,
117                    String serviceAccount, String servicePassword) {
118    
119                    _domain = domain;
120                    _domainController = domainController;
121                    _domainControllerName = domainControllerName;
122                    _ntlmServiceAccount = new NtlmServiceAccount(
123                            serviceAccount, servicePassword);
124    
125                    _netlogon = new Netlogon();
126    
127                    _netlogon.setConfiguration(
128                            domainController, domainControllerName, _ntlmServiceAccount);
129            }
130    
131            protected byte[] getAVPairBytes(int avId, String value)
132                    throws UnsupportedEncodingException{
133    
134                    byte[] valueBytes = value.getBytes("UTF-16LE");
135                    byte[] avPairBytes = new byte[4 + valueBytes.length];
136    
137                    Encdec.enc_uint16le((short)avId, avPairBytes, 0);
138                    Encdec.enc_uint16le((short)valueBytes.length, avPairBytes, 2);
139    
140                    System.arraycopy(valueBytes, 0, avPairBytes, 4, valueBytes.length);
141    
142                    return avPairBytes;
143            }
144    
145            protected byte[] getTargetInformation() throws UnsupportedEncodingException{
146                    byte[] computerName = getAVPairBytes(
147                            1, _ntlmServiceAccount.getComputerName());
148                    byte[] domainName =  getAVPairBytes(2, _domain);
149    
150                    byte[] targetInformation = ArrayUtil.append(computerName, domainName);
151    
152                    byte[] eol = getAVPairBytes(0, StringPool.BLANK);
153    
154                    targetInformation = ArrayUtil.append(targetInformation, eol);
155    
156                    return targetInformation;
157            }
158    
159            private static final int _NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY =
160                    0x00080000;
161    
162            private String _domain;
163            private String _domainController;
164            private String _domainControllerName;
165            private Netlogon _netlogon;
166            private NtlmServiceAccount _ntlmServiceAccount;
167    
168    }