KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > filesys > server > auth > SrvAuthenticator


1 /*
2  * Copyright (C) 2005 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;
18
19 import java.security.NoSuchAlgorithmException JavaDoc;
20 import java.util.Random JavaDoc;
21
22 import javax.transaction.UserTransaction JavaDoc;
23
24 import net.sf.acegisecurity.Authentication;
25
26 import org.alfresco.config.ConfigElement;
27 import org.alfresco.filesys.server.SrvSession;
28 import org.alfresco.filesys.server.config.InvalidConfigurationException;
29 import org.alfresco.filesys.server.config.ServerConfiguration;
30 import org.alfresco.filesys.server.core.SharedDevice;
31 import org.alfresco.filesys.server.filesys.DiskDeviceContext;
32 import org.alfresco.filesys.server.filesys.DiskInterface;
33 import org.alfresco.filesys.server.filesys.DiskSharedDevice;
34 import org.alfresco.filesys.server.filesys.SrvDiskInfo;
35 import org.alfresco.filesys.smb.server.repo.ContentContext;
36 import org.alfresco.model.ContentModel;
37 import org.alfresco.repo.security.authentication.AuthenticationComponent;
38 import org.alfresco.repo.security.authentication.MD4PasswordEncoder;
39 import org.alfresco.repo.security.authentication.MD4PasswordEncoderImpl;
40 import org.alfresco.repo.security.authentication.NTLMMode;
41 import org.alfresco.service.cmr.repository.NodeRef;
42 import org.alfresco.service.cmr.repository.NodeService;
43 import org.alfresco.service.cmr.security.AuthenticationService;
44 import org.alfresco.service.cmr.security.PersonService;
45 import org.alfresco.service.transaction.TransactionService;
46 import org.apache.commons.logging.Log;
47 import org.apache.commons.logging.LogFactory;
48
49 /**
50  * <p>
51  * An authenticator is used by the SMB server to authenticate users when in user level access mode
52  * and authenticate requests to connect to a share when in share level access.
53  */

54 public abstract class SrvAuthenticator
55 {
56     // Logging
57

58     protected static final Log logger = LogFactory.getLog("org.alfresco.smb.protocol.auth");
59
60     // Encryption algorithm types
61

62     public static final int LANMAN = PasswordEncryptor.LANMAN;
63     public static final int NTLM1 = PasswordEncryptor.NTLM1;
64     public static final int NTLM2 = PasswordEncryptor.NTLM2;
65
66     // Authentication status values
67

68     public static final int AUTH_ALLOW = 0;
69     public static final int AUTH_GUEST = 0x10000000;
70     public static final int AUTH_DISALLOW = -1;
71     public static final int AUTH_BADPASSWORD = -2;
72     public static final int AUTH_BADUSER = -3;
73
74     // Share access permissions, returned by authenticateShareConnect()
75

76     public static final int NoAccess = 0;
77     public static final int ReadOnly = 1;
78     public static final int Writeable = 2;
79
80     // Server access mode
81

82     public static final int SHARE_MODE = 0;
83     public static final int USER_MODE = 1;
84
85     // Standard encrypted password length
86

87     public static final int STANDARD_PASSWORD_LEN = 24;
88
89     // Default guest user name
90

91     protected static final String JavaDoc GUEST_USERNAME = "guest";
92
93     // Server access mode
94

95     private int m_accessMode = SHARE_MODE;
96
97     // Use encrypted password
98

99     private boolean m_encryptPwd = false;
100
101     // Password encryption algorithms
102

103     private PasswordEncryptor m_encryptor = new PasswordEncryptor();
104
105     // Flag to enable/disable the guest account, and control mapping of unknown users to the guest account
106

107     private boolean m_allowGuest;
108     private boolean m_mapToGuest;
109
110     // Default guest user name
111

112     private String JavaDoc m_guestUserName = GUEST_USERNAME;
113     
114     // Random number generator used to generate challenge keys
115

116     protected Random JavaDoc m_random = new Random JavaDoc(System.currentTimeMillis());
117
118     // Server configuration
119

120     protected ServerConfiguration m_config;
121     
122     // Authentication component, used to access internal authentication functions
123

124     protected AuthenticationComponent m_authComponent;
125
126     // MD4 hash decoder
127

128     protected MD4PasswordEncoder m_md4Encoder = new MD4PasswordEncoderImpl();
129     
130     // Various services required to get user information
131

132     protected NodeService m_nodeService;
133     protected PersonService m_personService;
134     protected TransactionService m_transactionService;
135     protected AuthenticationService m_authenticationService;
136     
137     /**
138      * Authenticate a connection to a share.
139      *
140      * @param client User/client details from the tree connect request.
141      * @param share Shared device the client wants to connect to.
142      * @param pwd Share password.
143      * @param sess Server session.
144      * @return int Granted file permission level or disallow status if negative. See the
145      * FilePermission class.
146      */

147     public int authenticateShareConnect(ClientInfo client, SharedDevice share, String JavaDoc sharePwd, SrvSession sess)
148     {
149         // Allow write access
150
//
151
// Main authentication is handled by authenticateUser()
152

153         return SrvAuthenticator.Writeable;
154     }
155
156     /**
157      * Authenticate a user. A user may be granted full access, guest access or no access.
158      *
159      * @param client User/client details from the session setup request.
160      * @param sess Server session
161      * @param alg Encryption algorithm
162      * @return int Access level or disallow status.
163      */

164     public abstract int authenticateUser(ClientInfo client, SrvSession sess, int alg);
165
166     /**
167      * Return the user account details for the specified user
168      *
169      * @param user String
170      * @return UserAccount
171      */

172     public UserAccount getUserDetails(String JavaDoc user)
173     {
174         return null;
175     }
176
177     /**
178      * Authenticate a user using a plain text password.
179      *
180      * @param client User/client details from the session setup request.
181      * @param sess Server session
182      * @return int Access level or disallow status.
183      * @throws InvalidConfigurationException
184      */

185     public final int authenticateUserPlainText(ClientInfo client, SrvSession sess)
186     {
187
188         // Get a challenge key
189

190         sess.setChallengeKey(getChallengeKey(sess));
191
192         if (sess.hasChallengeKey() == false)
193             return SrvAuthenticator.AUTH_DISALLOW;
194
195         // Get the plain text password
196

197         String JavaDoc textPwd = client.getPasswordAsString();
198         if (textPwd == null)
199             textPwd = client.getANSIPasswordAsString();
200
201         // Encrypt the password
202

203         byte[] encPwd = generateEncryptedPassword(textPwd, sess.getChallengeKey(), SrvAuthenticator.NTLM1);
204         client.setPassword(encPwd);
205
206         // Authenticate the user
207

208         return authenticateUser(client, sess, SrvAuthenticator.NTLM1);
209     }
210
211     /**
212      * Initialize the authenticator
213      *
214      * @param config ServerConfiguration
215      * @param params ConfigElement
216      * @exception InvalidConfigurationException
217      */

218     public void initialize(ServerConfiguration config, ConfigElement params) throws InvalidConfigurationException
219     {
220         // Save the server configuration so we can access the authentication component
221

222         m_config = config;
223         
224         // Check that the required authentication classes are available
225

226         m_authComponent = m_config.getAuthenticationComponent();
227         
228         if ( m_authComponent == null)
229             throw new InvalidConfigurationException("Authentication component not available");
230         
231         // Get hold of various services
232

233         m_nodeService = config.getNodeService();
234         m_personService = config.getPersonService();
235         m_transactionService = config.getTransactionService();
236         m_authenticationService = config.getAuthenticationService();
237         
238         // Set the guest user name
239

240         setGuestUserName( m_authComponent.getGuestUserName());
241         
242         // Check that the authentication component is the required type for this authenticator
243

244         if ( validateAuthenticationMode() == false)
245             throw new InvalidConfigurationException("Required authentication mode not available");
246     }
247
248     /**
249      * Validate that the authentication component supports the required mode
250      *
251      * @return boolean
252      */

253     protected boolean validateAuthenticationMode()
254     {
255         return true;
256     }
257     
258     /**
259      * Encrypt the plain text password with the specified encryption key using the specified
260      * encryption algorithm.
261      *
262      * @return byte[]
263      * @param plainPwd java.lang.String
264      * @param encryptKey byte[]
265      * @param alg int
266      */

267     protected final byte[] generateEncryptedPassword(String JavaDoc plainPwd, byte[] encryptKey, int alg)
268     {
269
270         // Use the password encryptor
271

272         byte[] encPwd = null;
273
274         try
275         {
276
277             // Encrypt the password
278

279             encPwd = m_encryptor.generateEncryptedPassword(plainPwd, encryptKey, alg);
280         }
281         catch (NoSuchAlgorithmException JavaDoc ex)
282         {
283         }
284
285         // Return the encrypted password
286

287         return encPwd;
288     }
289
290     /**
291      * Return the access mode of the server, either SHARE_MODE or USER_MODE.
292      *
293      * @return int
294      */

295     public final int getAccessMode()
296     {
297         return m_accessMode;
298     }
299
300     /**
301      * Get a challenge encryption key, when encrypted passwords are enabled.
302      *
303      * @param sess SrvSession
304      * @return byte[]
305      */

306     public abstract byte[] getChallengeKey(SrvSession sess);
307
308     /**
309      * Determine if encrypted passwords should be used.
310      *
311      * @return boolean
312      */

313     public final boolean hasEncryptPasswords()
314     {
315         return m_encryptPwd;
316     }
317
318     /**
319      * Determine if guest access is allowed
320      *
321      * @return boolean
322      */

323     public final boolean allowGuest()
324     {
325         return m_allowGuest;
326     }
327
328     /**
329      * Return the guest user name
330      *
331      * @return String
332      */

333     public final String JavaDoc getGuestUserName()
334     {
335         return m_guestUserName;
336     }
337     
338     /**
339      * Determine if unknown users should be mapped to the guest account
340      *
341      * @return boolean
342      */

343     public final boolean mapUnknownUserToGuest()
344     {
345         return m_mapToGuest;
346     }
347     
348     /**
349      * Set the access mode of the server.
350      *
351      * @param mode Either SHARE_MODE or USER_MODE.
352      */

353     public final void setAccessMode(int mode)
354     {
355         m_accessMode = mode;
356     }
357
358     /**
359      * Set/clear the encrypted passwords flag.
360      *
361      * @param encFlag Encrypt passwords if true, use plain text passwords if false.
362      */

363     public final void setEncryptedPasswords(boolean encFlag)
364     {
365         m_encryptPwd = encFlag;
366     }
367
368     /**
369      * Enable/disable the guest account
370      *
371      * @param ena Enable the guest account if true, only allow defined user accounts access if false
372      */

373     public final void setAllowGuest(boolean ena)
374     {
375         m_allowGuest = ena;
376     }
377
378     /**
379      * Set the guest user name
380      *
381      * @param guest String
382      */

383     public final void setGuestUserName( String JavaDoc guest)
384     {
385         m_guestUserName = guest;
386     }
387     
388     /**
389      * Enable/disable mapping of unknown users to the guest account
390      *
391      * @param ena Enable mapping of unknown users to the guest if true
392      */

393     public final void setMapToGuest( boolean ena)
394     {
395         m_mapToGuest = ena;
396     }
397     
398     /**
399      * Close the authenticator, perform any cleanup
400      */

401     public void closeAuthenticator()
402     {
403         // Override if cleanup required
404
}
405     
406     /**
407      * Validate a password by encrypting the plain text password using the specified encryption key
408      * and encryption algorithm.
409      *
410      * @return boolean
411      * @param plainPwd java.lang.String
412      * @param encryptedPwd java.lang.String
413      * @param encryptKey byte[]
414      * @param alg int
415      */

416     protected final boolean validatePassword(String JavaDoc plainPwd, byte[] encryptedPwd, byte[] encryptKey, int alg)
417     {
418
419         // Generate an encrypted version of the plain text password
420

421         byte[] encPwd = generateEncryptedPassword(plainPwd != null ? plainPwd : "", encryptKey, alg);
422
423         // Compare the generated password with the received password
424

425         if (encPwd != null && encryptedPwd != null && encPwd.length == STANDARD_PASSWORD_LEN
426                 && encryptedPwd.length == STANDARD_PASSWORD_LEN)
427         {
428
429             // Compare the password arrays
430

431             for (int i = 0; i < STANDARD_PASSWORD_LEN; i++)
432                 if (encPwd[i] != encryptedPwd[i])
433                     return false;
434
435             // Password is valid
436

437             return true;
438         }
439
440         // User or password is invalid
441

442         return false;
443     }
444
445     /**
446      * Convert the password string to a byte array
447      *
448      * @param pwd String
449      * @return byte[]
450      */

451
452     protected final byte[] convertPassword(String JavaDoc pwd)
453     {
454
455         // Create a padded/truncated 14 character string
456

457         StringBuffer JavaDoc p14str = new StringBuffer JavaDoc();
458         p14str.append(pwd);
459         if (p14str.length() > 14)
460             p14str.setLength(14);
461         else
462         {
463             while (p14str.length() < 14)
464                 p14str.append((char) 0x00);
465         }
466
467         // Convert the P14 string to an array of bytes. Allocate the return 16 byte array.
468

469         return p14str.toString().getBytes();
470     }
471     
472     /**
473      * Return the password encryptor
474      *
475      * @return PasswordEncryptor
476      */

477     protected final PasswordEncryptor getEncryptor()
478     {
479         return m_encryptor;
480     }
481     
482     /**
483      * Return the authentication status as a string
484      *
485      * @param sts int
486      * @return String
487      */

488     protected final String JavaDoc getStatusAsString(int sts)
489     {
490         String JavaDoc str = null;
491         
492         switch ( sts)
493         {
494         case AUTH_ALLOW:
495             str = "Allow";
496             break;
497         case AUTH_DISALLOW:
498             str = "Disallow";
499             break;
500         case AUTH_GUEST:
501             str = "Guest";
502             break;
503         case AUTH_BADPASSWORD:
504             str = "BadPassword";
505             break;
506         case AUTH_BADUSER:
507             str = "BadUser";
508             break;
509         }
510         
511         return str;
512     }
513     
514     /**
515      * Logon using the guest user account
516      *
517      * @param client ClientInfo
518      * @param sess SrvSession
519      */

520     protected final void doGuestLogon( ClientInfo client, SrvSession sess)
521     {
522         // Get a guest authentication token
523

524         m_authenticationService.authenticateAsGuest();
525         Authentication authToken = m_authComponent.getCurrentAuthentication();
526         
527         client.setAuthenticationToken( authToken);
528         
529         // Set the home folder for the guest user
530

531         client.setUserName( getGuestUserName());
532         getHomeFolderForUser( client);
533         
534         // Mark the client as being a guest logon
535

536         client.setGuest( true);
537
538         // Create a dynamic share for the guest user
539
// Create the disk driver and context
540

541         DiskInterface diskDrv = m_config.getDiskInterface();
542         DiskDeviceContext diskCtx = new ContentContext("", "", client.getHomeFolder());
543
544         // Default the filesystem to look like an 80Gb sized disk with 90% free space
545

546         diskCtx.setDiskInformation(new SrvDiskInfo(2560, 64, 512, 2304));
547         
548         // Create a temporary shared device for the users home directory
549

550         sess.addDynamicShare( new DiskSharedDevice( client.getUserName(), diskDrv, diskCtx, SharedDevice.Temporary));
551     }
552     
553     /**
554      * Get the home folder for the user
555      *
556      * @param client ClientInfo
557      */

558     protected final void getHomeFolderForUser(ClientInfo client)
559     {
560         // Get the home folder for the user
561

562         UserTransaction JavaDoc tx = m_transactionService.getUserTransaction();
563         NodeRef homeSpaceRef = null;
564         
565         try
566         {
567             tx.begin();
568             homeSpaceRef = (NodeRef) m_nodeService.getProperty(m_personService.getPerson(client.getUserName()),
569                     ContentModel.PROP_HOMEFOLDER);
570             client.setHomeFolder( homeSpaceRef);
571             tx.commit();
572         }
573         catch (Throwable JavaDoc ex)
574         {
575             try
576             {
577                 tx.rollback();
578             }
579             catch (Throwable JavaDoc ex2)
580             {
581                 logger.error("Failed to rollback transaction", ex2);
582             }
583             
584              // Re-throw the exception
585
if (ex instanceof RuntimeException JavaDoc)
586             {
587                 throw (RuntimeException JavaDoc) ex;
588             }
589             else
590             {
591                 throw new RuntimeException JavaDoc("Error during execution of transaction.", ex);
592             }
593         }
594     }
595     
596 }
Popular Tags