KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > filesys > server > auth > ntlm > AlfrescoAuthenticator


1 /*
2  * Copyright (C) 2006 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.filesys.server.auth.ntlm;
18
19 import java.security.NoSuchAlgorithmException JavaDoc;
20 import net.sf.acegisecurity.Authentication;
21
22 import org.alfresco.filesys.server.SrvSession;
23 import org.alfresco.filesys.server.auth.ClientInfo;
24 import org.alfresco.filesys.server.auth.SrvAuthenticator;
25 import org.alfresco.filesys.smb.server.SMBSrvSession;
26 import org.alfresco.filesys.util.DataPacker;
27 import org.alfresco.repo.security.authentication.NTLMMode;
28 import org.alfresco.repo.security.authentication.ntlm.NTLMPassthruToken;
29
30 /**
31  * Alfresco Authenticator Class
32  *
33  * <p>The Alfresco authenticator implementation enables user level security mode using the Alfresco authentication
34  * component.
35  *
36  * <p>Note: Switching off encrypted password support will cause later NT4 service pack releases and
37  * Win2000 to refuse to connect to the server without a registry update on the client.
38  *
39  * @author GKSpencer
40  */

41 public class AlfrescoAuthenticator extends SrvAuthenticator
42 {
43     /**
44      * Default Constructor
45      *
46      * <p>Default to user mode security with encrypted password support.
47      */

48     public AlfrescoAuthenticator()
49     {
50         setAccessMode(SrvAuthenticator.USER_MODE);
51         setEncryptedPasswords(true);
52     }
53
54     /**
55      * Validate that the authentication component supports the required mode
56      *
57      * @return boolean
58      */

59     protected boolean validateAuthenticationMode()
60     {
61         // Make sure the authentication component supports MD4 hashed passwords or passthru mode
62

63         if ( m_authComponent.getNTLMMode() != NTLMMode.MD4_PROVIDER &&
64                 m_authComponent.getNTLMMode() != NTLMMode.PASS_THROUGH)
65             return false;
66         return true;
67     }
68     
69     /**
70      * Authenticate a user
71      *
72      * @param client Client information
73      * @param sess Server session
74      * @param alg Encryption algorithm
75      */

76     public int authenticateUser(ClientInfo client, SrvSession sess, int alg)
77     {
78         // Check if this is an SMB/CIFS null session logon.
79
//
80
// The null session will only be allowed to connect to the IPC$ named pipe share.
81

82         if (client.isNullSession() && sess instanceof SMBSrvSession)
83         {
84             // Debug
85

86             if ( logger.isDebugEnabled())
87                 logger.debug("Null CIFS logon allowed");
88
89             return SrvAuthenticator.AUTH_ALLOW;
90         }
91
92         // Check if the client is already authenticated, and it is not a null logon
93

94         if ( client.getAuthenticationToken() != null && client.getLogonType() != ClientInfo.LogonNull)
95         {
96             // Use the existing authentication token
97

98             m_authComponent.setCurrentUser(client.getUserName());
99
100             // Debug
101

102             if ( logger.isDebugEnabled())
103                 logger.debug("Re-using existing authentication token");
104             
105             // Return the authentication status
106

107             return client.getLogonType() != ClientInfo.LogonGuest ? AUTH_ALLOW : AUTH_GUEST;
108         }
109         
110         // Check if this is a guest logon
111

112         int authSts = AUTH_DISALLOW;
113         
114         if ( client.isGuest() || client.getUserName().equalsIgnoreCase(getGuestUserName()))
115         {
116             // Check if guest logons are allowed
117

118             if ( allowGuest() == false)
119                 return AUTH_DISALLOW;
120             
121             // Get a guest authentication token
122

123             doGuestLogon( client, sess);
124             
125             // Indicate logged on as guest
126

127             authSts = AUTH_GUEST;
128             
129             // DEBUG
130

131             if ( logger.isDebugEnabled())
132                 logger.debug("Authenticated user " + client.getUserName() + " sts=" + getStatusAsString(authSts));
133             
134             // Return the guest status
135

136             return authSts;
137         }
138         
139         // Check if MD4 or passthru mode is configured
140

141         else if ( m_authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER)
142         {
143             // Perform local MD4 password check
144

145             authSts = doMD4UserAuthentication(client, sess, alg);
146         }
147         else
148         {
149             // Perform passthru authentication password check
150

151             authSts = doPassthruUserAuthentication(client, sess, alg);
152         }
153         
154         // Check if the logon status indicates a guest logon
155

156         if ( authSts == AUTH_GUEST)
157         {
158             // Only allow the guest logon if user mapping is enabled
159

160             if ( mapUnknownUserToGuest())
161             {
162                 // Logon as guest, setup the security context
163

164                 doGuestLogon( client, sess);
165             }
166             else
167             {
168                 // Do not allow the guest logon
169

170                 authSts = AUTH_DISALLOW;
171             }
172         }
173         
174         // DEBUG
175

176         if ( logger.isDebugEnabled())
177             logger.debug("Authenticated user " + client.getUserName() + " sts=" + getStatusAsString(authSts) +
178                     " via " + (m_authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER ? "MD4" : "Passthru"));
179                     
180         // Return the authentication status
181

182         return authSts;
183     }
184
185     /**
186      * Generate a challenge key
187      *
188      * @param sess SrvSession
189      * @return byte[]
190      */

191     public byte[] getChallengeKey(SrvSession sess)
192     {
193         // In MD4 mode we generate the challenge locally
194

195         byte[] key = null;
196         
197         // Check if the client is already authenticated, and it is not a null logon
198

199         if ( sess.hasClientInformation() && sess.getClientInformation().getAuthenticationToken() != null &&
200                 sess.getClientInformation().getLogonType() != ClientInfo.LogonNull)
201         {
202             // Return the previous challenge, user is already authenticated
203

204             key = sess.getChallengeKey();
205             
206             // DEBUG
207

208             if ( logger.isDebugEnabled())
209                 logger.debug("Re-using existing challenge, already authenticated");
210         }
211         else if ( m_authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER)
212         {
213             // Generate a new challenge key, pack the key and return
214

215             key = new byte[8];
216     
217             DataPacker.putIntelLong(m_random.nextLong(), key, 0);
218         }
219         else
220         {
221             // Create an authentication token for the session
222

223             NTLMPassthruToken authToken = new NTLMPassthruToken();
224             
225             // Run the first stage of the passthru authentication to get the challenge
226

227             m_authComponent.authenticate( authToken);
228             
229             // Save the authentication token for the second stage of the authentication
230

231             sess.setAuthenticationToken(authToken);
232             
233             // Get the challenge from the token
234

235             if ( authToken.getChallenge() != null)
236                 key = authToken.getChallenge().getBytes();
237         }
238
239         // Return the challenge
240

241         return key;
242     }
243
244     /**
245      * Perform MD4 user authentication
246      *
247      * @param client Client information
248      * @param sess Server session
249      * @param alg Encryption algorithm
250      * @return int
251      */

252     private final int doMD4UserAuthentication(ClientInfo client, SrvSession sess, int alg)
253     {
254         // Get the stored MD4 hashed password for the user, or null if the user does not exist
255

256         String JavaDoc md4hash = m_authComponent.getMD4HashedPassword(client.getUserName());
257         
258         if ( md4hash != null)
259         {
260             // Check if the client has supplied an NTLM hashed password, if not then do not allow access
261

262             if ( client.getPassword() == null)
263                 return SrvAuthenticator.AUTH_BADPASSWORD;
264             
265             try
266             {
267                 // Generate the local encrypted password using the challenge that was sent to the client
268

269                 byte[] p21 = new byte[21];
270                 byte[] md4byts = m_md4Encoder.decodeHash(md4hash);
271                 System.arraycopy(md4byts, 0, p21, 0, 16);
272                 
273                 // Generate the local hash of the password using the same challenge
274

275                 byte[] localHash = getEncryptor().doNTLM1Encryption(p21, sess.getChallengeKey());
276                 
277                 // Validate the password
278

279                 byte[] clientHash = client.getPassword();
280
281                 if ( clientHash == null || clientHash.length != localHash.length)
282                     return SrvAuthenticator.AUTH_BADPASSWORD;
283                 
284                 for ( int i = 0; i < clientHash.length; i++)
285                 {
286                     if ( clientHash[i] != localHash[i])
287                         return SrvAuthenticator.AUTH_BADPASSWORD;
288                 }
289                 
290                 // Set the current user to be authenticated, save the authentication token
291

292                 client.setAuthenticationToken( m_authComponent.setCurrentUser(client.getUserName()));
293                 
294                 // Get the users home folder node, if available
295

296                 getHomeFolderForUser( client);
297                 
298                 // Passwords match, grant access
299

300                 return SrvAuthenticator.AUTH_ALLOW;
301             }
302             catch (NoSuchAlgorithmException JavaDoc ex)
303             {
304             }
305             
306             // Error during password check, do not allow access
307

308             return SrvAuthenticator.AUTH_DISALLOW;
309         }
310
311         // Check if this is an SMB/CIFS null session logon.
312
//
313
// The null session will only be allowed to connect to the IPC$ named pipe share.
314

315         if (client.isNullSession() && sess instanceof SMBSrvSession)
316             return SrvAuthenticator.AUTH_ALLOW;
317         
318         // User does not exist, check if guest access is allowed
319

320         return allowGuest() ? SrvAuthenticator.AUTH_GUEST : SrvAuthenticator.AUTH_DISALLOW;
321     }
322     
323     /**
324      * Perform passthru user authentication
325      *
326      * @param client Client information
327      * @param sess Server session
328      * @param alg Encryption algorithm
329      * @return int
330      */

331     private final int doPassthruUserAuthentication(ClientInfo client, SrvSession sess, int alg)
332     {
333         // Get the authentication token for the session
334

335         NTLMPassthruToken authToken = (NTLMPassthruToken) sess.getAuthenticationToken();
336         
337         if ( authToken == null)
338             return SrvAuthenticator.AUTH_DISALLOW;
339
340         // Get the appropriate hashed password for the algorithm
341

342         int authSts = SrvAuthenticator.AUTH_DISALLOW;
343         byte[] hashedPassword = null;
344         
345         if ( alg == NTLM1)
346             hashedPassword = client.getPassword();
347         else if ( alg == LANMAN)
348             hashedPassword = client.getANSIPassword();
349         else
350         {
351             // Invalid/unsupported algorithm specified
352

353             return SrvAuthenticator.AUTH_DISALLOW;
354         }
355         
356         // Set the username and hashed password in the authentication token
357

358         authToken.setUserAndPassword( client.getUserName(), hashedPassword, alg);
359         
360         // Authenticate the user
361

362         Authentication genAuthToken = null;
363         
364         try
365         {
366             // Run the second stage of the passthru authentication
367

368             genAuthToken = m_authComponent.authenticate( authToken);
369             
370             // Check if the user has been logged on as a guest
371

372             if (authToken.isGuestLogon())
373             {
374
375                 // Check if the local server allows guest access
376

377                 if (allowGuest() == true)
378                 {
379
380                     // Allow the user access as a guest
381

382                     authSts = SrvAuthenticator.AUTH_GUEST;
383                 }
384             }
385             else
386             {
387
388                 // Allow the user full access to the server
389

390                 authSts = SrvAuthenticator.AUTH_ALLOW;
391             }
392
393             // Set the current user to be authenticated, save the authentication token
394

395             client.setAuthenticationToken( genAuthToken);
396             
397             // Get the users home folder node, if available
398

399             getHomeFolderForUser( client);
400             
401             // DEBUG
402

403             if ( logger.isDebugEnabled())
404                 logger.debug("Auth token " + genAuthToken);
405         }
406         catch ( Exception JavaDoc ex)
407         {
408             logger.error("Error during passthru authentication", ex);
409         }
410         
411         // Clear the authentication token
412

413         sess.setAuthenticationToken(null);
414         
415         // Return the authentication status
416

417         return authSts;
418     }
419 }
Popular Tags