KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > sync4j > server > security > DBOfficer


1 /**
2  * Copyright (C) 2003-2005 Funambol
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */

18 package sync4j.server.security;
19
20 import java.util.HashMap JavaDoc;
21 import java.util.logging.Logger JavaDoc;
22 import java.util.logging.Level JavaDoc;
23
24 import java.security.Principal JavaDoc;
25 import javax.security.auth.*;
26 import javax.security.auth.login.*;
27 import javax.security.*;
28
29 import sync4j.framework.security.Officer;
30 import sync4j.framework.security.Sync4jPrincipal;
31 import sync4j.framework.logging.Sync4jLogger;
32 import sync4j.framework.core.Cred;
33 import sync4j.framework.core.Authentication;
34 import sync4j.framework.server.Sync4jDevice;
35 import sync4j.framework.config.ConfigurationConstants;
36 import sync4j.framework.tools.MD5;
37 import sync4j.framework.tools.Base64;
38 import sync4j.framework.server.Sync4jUser;
39 import sync4j.framework.server.store.PersistentStore;
40 import sync4j.framework.server.store.PersistentStoreException;
41 import sync4j.framework.server.store.WhereClause;
42 import sync4j.framework.server.store.LogicalClause;
43 import sync4j.framework.config.ConfigurationConstants;
44 import sync4j.server.config.Configuration;
45 import sync4j.server.admin.UserManager;
46
47 /**
48  * This is an implementation of the <i>Officier</i> interface. It always
49  * authenticates and authorizes users and resource accesses.
50  *
51  * @author Stefano Fornari @ Funambol.com
52  * @version $Id: DBOfficer.java,v 1.4 2005/03/02 20:57:39 harrie Exp $
53  */

54 public class DBOfficer implements Officer, java.io.Serializable JavaDoc {
55
56     // ---------------------------------------------------------- Protected data
57

58     protected transient Logger JavaDoc log = Sync4jLogger.getLogger();
59     protected PersistentStore ps = null;
60     protected UserManager userManager = null;
61
62     // ------------------------------------------------------------- Public data
63
// -------------------------------------------------------------- Properties
64

65     /**
66      * Has the last login failed for incorrect login/password?
67      */

68     private boolean loginFailed = false;
69
70     public boolean isLoginFailed() {
71         return loginFailed;
72     }
73
74     /**
75      * Has the last login failed for expired temporary login?
76      */

77     private boolean loginExpired = false;
78
79     /**
80      * Which type of authetication does impose the server?
81      */

82     private String JavaDoc clientAuth = Cred.AUTH_TYPE_BASIC;
83
84     public String JavaDoc getClientAuth() {
85         return this.clientAuth;
86     }
87     public void setClientAuth(String JavaDoc clientAuth) {
88         this.clientAuth = clientAuth;
89     }
90     
91     /**
92      * Which type of authetication use the server to send his credential?
93      */

94     private String JavaDoc serverAuth = Cred.AUTH_NONE;
95     public String JavaDoc getServerAuth() {
96         return this.serverAuth;
97     }
98     
99     public void setServerAuth(String JavaDoc serverAuth) {
100         this.serverAuth = serverAuth;
101     }
102
103     // ---------------------------------------------------------- Public methods
104

105     /**
106      * Authenticates a credential.
107      *
108      * @param credential the credential to be authenticated
109      *
110      * @return true if the credential is autenticated, false otherwise
111      */

112     public boolean authenticate(Cred credential) {
113         Configuration config = Configuration.getConfiguration();
114         ps = config.getStore();
115
116         userManager = (UserManager)config.getUserManager();
117
118         String JavaDoc type = credential.getType();
119
120         if ((Cred.AUTH_TYPE_BASIC).equals(type)) {
121             return authenticateBasicCredential(credential);
122         } else if ( (Cred.AUTH_TYPE_MD5).equals(type) ) {
123             String JavaDoc syncMLVerProto =
124                              credential.getAuthentication().getSyncMLVerProto();
125             //
126
// The modality in order to calculate the digest is different to second
127
// of the used version of SyncML
128
//
129
if (syncMLVerProto.indexOf("1.0") != -1) {
130                 return authenticateMD5Credential10(credential);
131             } else if (syncMLVerProto.indexOf("1.1") != -1) {
132                 return authenticateMD5Credential11(credential);
133             }
134         } else if ( (Cred.AUTH_TYPE_HMAC).equals(type) ) {
135             return false;
136         }
137         return false;
138     }
139
140     private boolean authenticateBasicCredential(Cred credential) {
141         Sync4jUser[] users = null;
142         String JavaDoc username = null, password = null;
143         Sync4jPrincipal principal = null;
144
145         Authentication auth = credential.getAuthentication();
146         String JavaDoc deviceId = auth.getDeviceId();
147         String JavaDoc userpwd = new String JavaDoc(Base64.decode(auth.getData()));
148
149         int p = userpwd.indexOf(':');
150
151         if (p == -1) {
152             username = userpwd;
153             password = "";
154         } else {
155             username = (p>0) ? userpwd.substring(0, p) : "";
156             password = (p == (userpwd.length()-1)) ? "" : userpwd.substring(p+1);
157         }
158
159         if (log.isLoggable(Level.FINEST)) {
160             log.finest("Username: " + username);
161         }
162
163         //
164
// Verify that exist the principal for the specify deviceId and username
165
//
166
try {
167             principal = new Sync4jPrincipal(username, deviceId);
168             ps.read(principal);
169             credential.getAuthentication().setPrincipalId(principal.getId());
170         } catch(PersistentStoreException e) {
171             log.severe("Error reading principal: " + e);
172             log.throwing(getClass().getName(), "authenticateBasicCredential", e);
173             return false;
174         }
175
176         try {
177             WhereClause[] wc = new WhereClause[2];
178             String JavaDoc value[] = new String JavaDoc[1];
179             value[0] = username;
180             wc[0] = new WhereClause("username",value, WhereClause.OPT_EQ, true);
181
182             value = new String JavaDoc[1];
183             value[0] = password;
184             wc[1] = new WhereClause("password",value, WhereClause.OPT_EQ, true);
185             LogicalClause lc = new LogicalClause(LogicalClause.OPT_AND, wc);
186
187             users = userManager.getUsers(lc);
188             if (users.length == 1) {
189                 return true;
190         }
191         
192         } catch(PersistentStoreException e) {
193             log.severe("Error reading user: " + e);
194             log.throwing(getClass().getName(), "authenticateBasicCredential", e);
195             return false;
196         }
197         
198
199         return false;
200     }
201     private boolean authenticateMD5Credential10(Cred credential) {
202         Sync4jPrincipal principals[] = null ;
203         boolean isFindDigest = false;
204         String JavaDoc password = null ;
205         String JavaDoc username = null ;
206         String JavaDoc usernamepwd = null ;
207
208         Authentication auth = credential.getAuthentication();
209         String JavaDoc deviceId = auth.getDeviceId();
210
211         //
212
// Gets all principal for the specify deviceId
213
//
214
WhereClause whereClause = new WhereClause("device",
215                                                   new String JavaDoc[] {deviceId},
216                                                   WhereClause.OPT_EQ,
217                                                   true);
218         try {
219             principals = (Sync4jPrincipal[])ps.read(
220                 new Sync4jPrincipal(null, deviceId),
221                 whereClause
222             );
223         } catch(PersistentStoreException e) {
224             log.severe("Error reading principals: " + e);
225             log.throwing(getClass().getName(), "authenticateMD5Credential11", e);
226             return false;
227         }
228         //
229
// Search the username
230
//
231
int size = principals.length;
232         for (int i=0; i<size; i++) {
233             Sync4jUser user = new Sync4jUser(principals[i].getUsername(), null, null, null, null, null);
234
235             try {
236                 userManager.getUser(user);
237             } catch(PersistentStoreException e) {
238                 log.severe("Error reading user: " + e);
239                 log.throwing(getClass().getName(), "authenticateMD5Credential11", e);
240             }
241         
242             //
243
// Calculate digest
244
//
245
username = user.getUsername();
246             password = user.getPassword();
247             usernamepwd = username + ':' + password;
248             byte[] usernamepwdBytes = usernamepwd.getBytes();
249
250             byte[] clientNonce = auth.getNextNonce().getValue();
251         
252             if (log.isLoggable(Level.FINEST)) {
253                 log.finest("username: " + username);
254                 log.finest("password: " + password);
255                 log.finest("clientNonce : " + new String JavaDoc(Base64.encode(clientNonce)));
256             }
257         
258             //
259
// computation of the MD5 digest
260
//
261
// Creates a unique buffer containing the bytes to digest
262
//
263
byte[] buf = new byte[usernamepwdBytes.length + 1 + clientNonce.length];
264
265             System.arraycopy(usernamepwdBytes, 0, buf, 0, usernamepwdBytes.length);
266             buf[usernamepwdBytes.length] = (byte)':';
267             System.arraycopy(clientNonce, 0, buf, usernamepwdBytes.length+1, clientNonce.length);
268
269             byte[] digest = MD5.digest(buf);
270
271             //
272
// encoding digest in Base64 for comparation with digest sent by client
273
//
274
String JavaDoc serverDigestNonceB64 = new String JavaDoc(Base64.encode(digest));
275
276             //
277
// digest sent by client in format b64
278
//
279
String JavaDoc msgDigestNonceB64 = auth.getData();
280         
281             if (log.isLoggable(Level.FINEST)) {
282                 log.finest("serverDigestNonceB64: " + serverDigestNonceB64);
283                 log.finest("msgDigestNonceB64: " + msgDigestNonceB64 );
284             }
285
286             if (msgDigestNonceB64.equals(serverDigestNonceB64)) {
287                 credential.getAuthentication().setPrincipalId(principals[i].getId());
288                 isFindDigest = true;
289                 break;
290             }
291         }
292
293         if (!isFindDigest) {
294             return false;
295         }
296
297         auth.setUsername(usernamepwd);
298         credential.setAuthentication(auth);
299         return true;
300     }
301
302     private boolean authenticateMD5Credential11(Cred credential) {
303         Sync4jPrincipal principals[] = null ;
304         boolean isFindDigest = false;
305         String JavaDoc password = null ;
306         String JavaDoc username = null ;
307         byte[] userDigestB64 = null ;
308         
309         Authentication auth = credential.getAuthentication();
310         String JavaDoc deviceId = auth.getDeviceId();
311
312         //
313
// Gets all principal for the specify deviceId
314
//
315
WhereClause whereClause = new WhereClause("device",
316                                                   new String JavaDoc[] {deviceId},
317                                                   WhereClause.OPT_EQ,
318                                                   true);
319         try {
320             principals = (Sync4jPrincipal[])ps.read(
321                 new Sync4jPrincipal(null, deviceId),
322                 whereClause
323             );
324         } catch(PersistentStoreException e) {
325             log.severe("Error reading principals: " + e);
326             log.throwing(getClass().getName(), "authenticateMD5Credential11", e);
327             return false;
328         }
329         //
330
// Search the username
331
//
332
int size = principals.length;
333         for (int i=0; i<size; i++) {
334             Sync4jUser user = new Sync4jUser(principals[i].getUsername(), null, null, null, null, null);
335
336             try {
337                 userManager.getUser(user);
338             } catch(PersistentStoreException e) {
339                 log.severe("Error reading user: " + e);
340                 log.throwing(getClass().getName(), "authenticateMD5Credential11", e);
341             }
342         
343             //
344
// Calculate digest
345
//
346
username = user.getUsername();
347             password = user.getPassword();
348
349             byte[] userDigest = MD5.digest((new String JavaDoc(username + ':' + password)).getBytes());
350             userDigestB64 = Base64.encode(userDigest);
351         
352             byte[] clientNonce = auth.getNextNonce().getValue();
353         
354             if (log.isLoggable(Level.FINEST)) {
355                 log.finest("userDigestB64: " + new String JavaDoc(userDigestB64));
356                 log.finest("clientNonce : " + new String JavaDoc(Base64.encode(clientNonce)));
357             }
358         
359             //
360
// computation of the MD5 digest
361
//
362
// Creates a unique buffer containing the bytes to digest
363
//
364
byte[] buf = new byte[userDigestB64.length + 1 + clientNonce.length];
365
366             System.arraycopy(userDigestB64, 0, buf, 0, userDigestB64.length);
367             buf[userDigestB64.length] = (byte)':';
368             System.arraycopy(clientNonce, 0, buf, userDigestB64.length+1, clientNonce.length);
369
370             byte[] digest = MD5.digest(buf);
371
372             //
373
// encoding digest in Base64 for comparation with digest sent by client
374
//
375
String JavaDoc serverDigestNonceB64 = new String JavaDoc(Base64.encode(digest));
376         
377             //
378
// digest sent by client in format b64
379
//
380
String JavaDoc msgDigestNonceB64 = auth.getData();
381         
382             if (log.isLoggable(Level.FINEST)) {
383                 log.finest("serverDigestNonceB64: " + serverDigestNonceB64);
384                 log.finest("msgDigestNonceB64: " + msgDigestNonceB64 );
385             }
386
387             if (msgDigestNonceB64.equals(serverDigestNonceB64)) {
388                 credential.getAuthentication().setPrincipalId(principals[i].getId());
389                 isFindDigest = true;
390                 break;
391             }
392         }
393
394         if (!isFindDigest) {
395             return false;
396         }
397         auth.setUsername(new String JavaDoc(userDigestB64));
398         credential.setAuthentication(auth);
399         return true;
400     }
401
402     /**
403      * Authorizes a resource.
404      *
405      * @param principal the requesting entity
406      * @param resource the name (or the identifier) of the resource to be authorized
407      *
408      * @return true if the credential is authorized to access the resource, false
409      * otherwise
410      */

411     public boolean authorize(Principal JavaDoc principal, String JavaDoc resource) {
412         return true;
413     }
414
415     /** Un-authenticates a credential.
416      *
417      * @param credential the credential to be unauthenticated
418      */

419     public void unAuthenticate(Cred credential) {
420         //
421
// Do nothing. In the current implementation, the authentication is
422
// discarde as soon as the LoginContext is garbage collected.
423
//
424
}
425
426     /**
427      * @see sync4j.framework.security.Officer
428      */

429     public boolean isAccountExpired() {
430         return loginExpired;
431     }
432
433
434     private void readObject(java.io.ObjectInputStream JavaDoc in)
435     throws java.io.IOException JavaDoc, ClassNotFoundException JavaDoc {
436         in.defaultReadObject();
437         log = Sync4jLogger.getLogger();
438     }
439 }
Popular Tags