KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > sync4j > framework > 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
19
20 package sync4j.framework.security;
21
22 import java.util.HashMap JavaDoc;
23 import java.util.logging.Logger JavaDoc;
24 import java.util.logging.Level JavaDoc;
25
26 import java.security.Principal JavaDoc;
27 import javax.security.auth.*;
28 import javax.security.auth.login.*;
29 import javax.security.*;
30
31 import sync4j.framework.security.Officer;
32 import sync4j.framework.security.jaas.CredentialHandler;
33 import sync4j.framework.logging.Sync4jLogger;
34 import sync4j.framework.core.Cred;
35 import sync4j.framework.core.Authentication;
36 import sync4j.framework.config.Configuration;
37 import sync4j.framework.config.ConfigurationConstants;
38 import sync4j.framework.core.HMACAuthentication;
39 import sync4j.framework.core.Constants;
40 import sync4j.framework.tools.MD5;
41 import sync4j.framework.tools.Base64;
42 import sync4j.framework.server.store.*;
43 import sync4j.framework.server.Sync4jDevice;
44 import sync4j.framework.server.SyncUser;
45
46 import sync4j.server.admin.UserManager;
47
48
49 /**
50  * This implementation of <i>Officier</i>
51  *
52  * @author Stefano Nichele @ Funambol.com
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
61     // ------------------------------------------------------------- Public data
62
// -------------------------------------------------------------- Properties
63

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

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

76     private boolean loginExpired = false;
77
78     /**
79      * Can use a guest credential if there is not credential in the message?
80      */

81     private boolean guestEnabled = true;
82
83     public boolean isGuestEnabled() {
84         return this.guestEnabled;
85     }
86
87     public void setGuestEnabled(boolean guestEnabled) {
88         this.guestEnabled = guestEnabled;
89     }
90
91     /**
92      * Which type of authetication does impose the server?
93      */

94     private String JavaDoc authType = "syncml:auth-md5";
95
96     public String JavaDoc getAuthType() {
97         return this.authType;
98     }
99
100     public void setAuthType(String JavaDoc authType) {
101         this.authType = authType;
102
103         // the authType is supported!!!!
104
this.supportedAuthType = this.supportedAuthType + this.authType;
105     }
106
107
108     private String JavaDoc supportedAuthType = null;
109
110     public String JavaDoc getSupportedAuthType() {
111         return this.supportedAuthType;
112     }
113
114     public void setSupportedAuthType(String JavaDoc supportedAuthType) {
115
116         // the authType is supported!!!!
117
this.supportedAuthType = this.authType + supportedAuthType;
118     }
119
120
121     // ---------------------------------------------------------- Public methods
122

123     /**
124      * Authenticates a credential
125      *
126      * @param credential the credential to be authenticated
127      *
128      * @return true if the credential is autenticated, false otherwise
129      */

130     public boolean authenticate(Cred credential) {
131
132         String JavaDoc type = credential.getType();
133
134         if ( (Constants.AUTH_TYPE_BASIC).equals(type) ) {
135             return authenticateBasicCredential(credential);
136         } else if ( (Constants.AUTH_TYPE_MD5).equals(type) ) {
137             return authenticateMD5Credential(credential);
138         } else if ( (Constants.AUTH_TYPE_HMAC).equals(type) ) {
139             return authenticateHMACCredential(credential);
140         } else {
141             return false;
142         }
143     }
144
145     /**
146      * Authorizes a resource.
147      *
148      * @param principal the requesting entity
149      * @param resource the name (or the identifier) of the resource to be authorized
150      *
151      * @return true if the credential is authorized to access the resource, false
152      * otherwise
153      */

154     public boolean authorize(Principal JavaDoc principal, String JavaDoc resource) {
155         return true;
156     }
157
158     /** Un-authenticates a credential.
159      *
160      * @param credential the credential to be unauthenticated
161      */

162     public void unAuthenticate(Cred credential) {
163         //
164
// Do nothing. In the current implementation, the authentication is
165
// discarde as soon as the LoginContext is garbage collected.
166
//
167
}
168
169     /**
170      * @see sync4j.framework.security.Officer
171      */

172     public boolean isAccountExpired() {
173         return loginExpired;
174     }
175
176
177     // --------------------------------------------------------- Private Methods
178
private void readObject(java.io.ObjectInputStream JavaDoc in)
179     throws java.io.IOException JavaDoc, ClassNotFoundException JavaDoc {
180         in.defaultReadObject();
181         log = Sync4jLogger.getLogger();
182     }
183
184
185     private boolean authenticateBasicCredential(Cred credential) {
186         SyncUser user = null ;
187         Authentication auth = credential.getAuthentication();
188
189         String JavaDoc username = null;
190         String JavaDoc password = null;
191
192         String JavaDoc s = new String JavaDoc(Base64.decode(credential.getData()));
193
194         int p = s.indexOf(':');
195
196         if (p == -1) {
197             username = s;
198             password = "";
199         } else {
200             username = (p>0) ? s.substring(0, p) : "";
201             password = (p == (s.length()-1)) ? "" : s.substring(p+1);
202         }
203
204         if (log.isLoggable(Level.FINE)) {
205             log.fine("Username: " + username + "; password: " + password);
206         }
207
208         try {
209             user = readUser(username);
210         } catch (NotFoundException e) {
211             if (log.isLoggable(Level.FINE)) {
212                 log.fine("User " + username + " not found!");
213             }
214         } catch (PersistentStoreException e) {
215             log.severe( "Error reading the user "
216                       + username
217                       + ": "
218                       + e.getMessage()
219                       );
220             log.throwing(getClass().getName(), "authenticateBasicCredential", e);
221
222             return false;
223         }
224
225         return password.equals(user.getPassword());
226     }
227
228     private boolean authenticateMD5Credential(Cred credential) {
229
230         Sync4jDevice device = null ;
231         Authentication auth = credential.getAuthentication();
232
233         try {
234             device = readDevice(auth.getDeviceId());
235         } catch (PersistentStoreException e) {
236             log.severe("Error configuring the persistent store: " + e);
237             log.throwing(getClass().getName(), "authenticateMD5Credential", e);
238
239             return false;
240         }
241
242         //
243
// NOTE: the digest read from the store is formatted as
244
// b64(H(username:password))
245
//
246
String JavaDoc userDigest = device.getDigest();
247         byte[] clientNonce = auth.getNextNonce().getValue();
248
249         if (log.isLoggable(Level.FINE)) {
250             log.fine("userDigest: " + userDigest);
251         }
252
253         byte[] userDigestBytes = userDigest.getBytes();
254
255         //
256
// computation of the MD5 digest
257
//
258
// Creates a unique buffer containing the bytes to digest
259
//
260
byte[] buf = new byte[userDigestBytes.length + 1 + clientNonce.length];
261
262         System.arraycopy(userDigestBytes, 0, buf, 0, userDigestBytes.length);
263         buf[userDigestBytes.length] = (byte)':';
264         System.arraycopy(clientNonce, 0, buf, userDigestBytes.length+1, clientNonce.length);
265
266         byte[] digest = MD5.digest(buf);
267
268         //
269
// encoding digest in Base64 for comparation with digest sent by client
270
//
271
String JavaDoc serverDigestNonceB64 = new String JavaDoc(Base64.encode(digest));
272
273         //
274
// digest sent by client in format b64
275
//
276
String JavaDoc msgDigestNonceB64 = auth.getData();
277
278         if (log.isLoggable(Level.FINE)) {
279             log.fine("serverDigestNonceB64: " + serverDigestNonceB64);
280             log.fine("msgDigestNonceB64: " + msgDigestNonceB64 );
281         }
282
283         if (!msgDigestNonceB64.equals(serverDigestNonceB64)) {
284             return false;
285         }
286
287         auth.setUsername(userDigest);
288
289         return true;
290
291     }
292
293     private boolean authenticateHMACCredential(Cred credential) {
294         Sync4jDevice device = null ;
295         Authentication auth = credential.getAuthentication();
296
297         if ( !(auth instanceof HMACAuthentication) ) {
298             throw new IllegalStateException JavaDoc("Authentication not valid!");
299         }
300
301         try {
302             device = readDevice(auth.getDeviceId());
303         } catch (PersistentStoreException e) {
304             log.severe("Error configuring the persistent store: " + e);
305             log.throwing(getClass().getName(), "authenticateMD5Credential", e);
306
307             return false;
308         }
309
310         String JavaDoc userMac = ((HMACAuthentication)auth).getUserMac() ;
311         String JavaDoc calculatedMac = ((HMACAuthentication)auth).getCalculatedMac();
312
313         if ((userMac != null) && (userMac.equals(calculatedMac))) {
314             auth.setUsername(device.getDigest());
315             return true;
316         }
317
318         return false;
319     }
320
321     /**
322      * Reads a device from the persistent store from the device id.
323      *
324      * @param deviceId the device id
325      *
326      * @return a Sync4jDevice representing the device
327      *
328      * @throws PersistentStoreException in case of errors reading from the db
329      */

330     private Sync4jDevice readDevice(String JavaDoc deviceId)
331     throws PersistentStoreException {
332         Configuration config = Configuration.getConfiguration();
333
334         PersistentStore ps =
335             (PersistentStore)config.getBeanInstance(ConfigurationConstants.CFG_PERSISTENT_STORE);
336
337         Sync4jDevice device = new Sync4jDevice(deviceId, null, null);
338         ps.read(device);
339
340         return device;
341     }
342
343     /**
344      * Reads a user from the database store given his/her usernameù.
345      *
346      * @param username the user name
347      *
348      * @throws NotFoundException if no users are found
349      * PersistentStoreException in case of persistent store errors
350      */

351     private SyncUser readUser(String JavaDoc username)
352     throws NotFoundException, PersistentStoreException {
353         Configuration config = Configuration.getConfiguration();
354
355         UserManager um =
356             (UserManager)config.getBeanInstance(ConfigurationConstants.CFG_USER_MANAGER);
357
358         SyncUser[] results = um.getUsers(
359             new WhereClause("username", new String JavaDoc[] { username }, WhereClause.OPT_EQ, false)
360         );
361
362         if ((results == null) || (results.length == 0)) {
363             throw new NotFoundException(username);
364         }
365
366         return results[0];
367     }
368
369
370 }
Popular Tags