KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ofbiz > securityext > login > LoginServices


1 /*
2  * $Id: LoginServices.java 5462 2005-08-05 18:35:48Z jonesde $
3  *
4  * Copyright (c) 2001-2005 The Open For Business Project - www.ofbiz.org
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21  * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */

24 package org.ofbiz.securityext.login;
25
26 import java.sql.Timestamp JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.LinkedList JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Locale JavaDoc;
31 import java.util.Map JavaDoc;
32
33 import javax.transaction.Transaction JavaDoc;
34
35 import org.ofbiz.base.crypto.HashCrypt;
36 import org.ofbiz.base.util.Debug;
37 import org.ofbiz.base.util.UtilDateTime;
38 import org.ofbiz.base.util.UtilMisc;
39 import org.ofbiz.base.util.UtilProperties;
40 import org.ofbiz.base.util.UtilValidate;
41 import org.ofbiz.entity.GenericDelegator;
42 import org.ofbiz.entity.GenericEntityException;
43 import org.ofbiz.entity.GenericValue;
44 import org.ofbiz.entity.serialize.XmlSerializer;
45 import org.ofbiz.entity.transaction.GenericTransactionException;
46 import org.ofbiz.entity.transaction.TransactionUtil;
47 import org.ofbiz.security.Security;
48 import org.ofbiz.service.DispatchContext;
49 import org.ofbiz.service.ModelService;
50 import org.ofbiz.service.ServiceUtil;
51
52 /**
53  * <b>Title:</b> Login Services
54  *
55  * @author <a HREF="mailto:jaz@ofbiz.org">Andy Zeneski</a>
56  * @author <a HREF="mailto:jonesde@ofbiz.org">David E. Jones</a>
57  * @version $Rev: 5462 $
58  * @since 2.0
59  */

60 public class LoginServices {
61
62     public static final String JavaDoc module = LoginServices.class.getName();
63     public static final String JavaDoc resource = "SecurityextUiLabels";
64
65     /** Login service to authenticate username and password
66      * @return Map of results including (userLogin) GenericValue object
67      */

68     public static Map JavaDoc userLogin(DispatchContext ctx, Map JavaDoc context) {
69         Map JavaDoc result = new HashMap JavaDoc();
70         GenericDelegator delegator = ctx.getDelegator();
71         Locale JavaDoc locale = (Locale JavaDoc) context.get("locale");
72
73         boolean useEncryption = "true".equals(UtilProperties.getPropertyValue("security.properties", "password.encrypt"));
74
75         // if isServiceAuth is not specified, default to not a service auth
76
boolean isServiceAuth = context.get("isServiceAuth") != null && ((Boolean JavaDoc) context.get("isServiceAuth")).booleanValue();
77
78         String JavaDoc username = (String JavaDoc) context.get("login.username");
79         if (username == null) username = (String JavaDoc) context.get("username");
80         String JavaDoc password = (String JavaDoc) context.get("login.password");
81         if (password == null) password = (String JavaDoc) context.get("password");
82
83         // get the visitId for the history entity
84
String JavaDoc visitId = (String JavaDoc) context.get("visitId");
85
86         String JavaDoc errMsg = "";
87         if (username == null || username.length() <= 0) {
88             errMsg = UtilProperties.getMessage(resource,"loginservices.username_missing", locale);
89         } else if (password == null || password.length() <= 0) {
90             errMsg = UtilProperties.getMessage(resource,"loginservices.password_missing", locale);
91         } else {
92             String JavaDoc realPassword = useEncryption ? LoginServices.getPasswordHash(password) : password;
93
94             boolean repeat = true;
95             // starts at zero but it incremented at the beggining so in the first pass passNumber will be 1
96
int passNumber = 0;
97
98             while (repeat) {
99                 repeat = false;
100                 // pass number is incremented here because there are continues in this loop so it may never get to the end
101
passNumber++;
102
103                 GenericValue userLogin = null;
104
105                 try {
106                     // only get userLogin from cache for service calls; for web and other manual logins there is less time sensitivity
107
if (isServiceAuth) {
108                         userLogin = delegator.findByPrimaryKeyCache("UserLogin", UtilMisc.toMap("userLoginId", username));
109                     } else {
110                         userLogin = delegator.findByPrimaryKey("UserLogin", UtilMisc.toMap("userLoginId", username));
111                     }
112                 } catch (GenericEntityException e) {
113                     Debug.logWarning(e, "", module);
114                 }
115
116                 if (userLogin != null) {
117                     String JavaDoc ldmStr = UtilProperties.getPropertyValue("security.properties", "login.disable.minutes");
118                     long loginDisableMinutes = 30;
119
120                     try {
121                         loginDisableMinutes = Long.parseLong(ldmStr);
122                     } catch (Exception JavaDoc e) {
123                         loginDisableMinutes = 30;
124                         Debug.logWarning("Could not parse login.disable.minutes from security.properties, using default of 30", module);
125                     }
126
127                     Timestamp JavaDoc disabledDateTime = userLogin.getTimestamp("disabledDateTime");
128                     Timestamp JavaDoc reEnableTime = null;
129
130                     if (loginDisableMinutes > 0 && disabledDateTime != null) {
131                         reEnableTime = new Timestamp JavaDoc(disabledDateTime.getTime() + loginDisableMinutes * 60000);
132                     }
133
134                     boolean doStore = true;
135                     // we might change & store this userLogin, so we should clone it here to get a mutable copy
136
userLogin = GenericValue.create(userLogin);
137
138                     // get the is system flag -- system accounts can only be used for service authentication
139
boolean isSystem = (isServiceAuth && userLogin.get("isSystem") != null) ?
140                             "Y".equalsIgnoreCase(userLogin.getString("isSystem")) : false;
141
142                     // grab the hasLoggedOut flag
143
boolean hasLoggedOut = userLogin.get("hasLoggedOut") != null ?
144                             "Y".equalsIgnoreCase(userLogin.getString("hasLoggedOut")) : false;
145
146                     if (UtilValidate.isEmpty(userLogin.getString("enabled")) || "Y".equals(userLogin.getString("enabled")) ||
147                         (reEnableTime != null && reEnableTime.before(UtilDateTime.nowTimestamp())) || (isSystem)) {
148
149                         String JavaDoc successfulLogin;
150
151                         if (!isSystem) {
152                             userLogin.set("enabled", "Y");
153                         }
154
155                         // if the password.accept.encrypted.and.plain property in security is set to true allow plain or encrypted passwords
156
// if this is a system account don't bother checking the passwords
157
if ((userLogin.get("currentPassword") != null &&
158                             (realPassword.equals(userLogin.getString("currentPassword")) ||
159                                 ("true".equals(UtilProperties.getPropertyValue("security.properties", "password.accept.encrypted.and.plain")) && password.equals(userLogin.getString("currentPassword")))))) {
160                             Debug.logVerbose("[LoginServices.userLogin] : Password Matched", module);
161
162                             // update the hasLoggedOut flag
163
if (hasLoggedOut) {
164                                 userLogin.set("hasLoggedOut", "N");
165                             }
166
167                             // reset failed login count if necessry
168
Long JavaDoc currentFailedLogins = userLogin.getLong("successiveFailedLogins");
169                             if (currentFailedLogins != null && currentFailedLogins.longValue() > 0) {
170                                 userLogin.set("successiveFailedLogins", new Long JavaDoc(0));
171                             } else if (!hasLoggedOut) {
172                                 // successful login & no loggout flag, no need to change anything, so don't do the store
173
doStore = false;
174                             }
175
176                             successfulLogin = "Y";
177
178                             if (!isServiceAuth) {
179                                 // get the UserLoginSession if this is not a service auth
180
GenericValue userLoginSession = null;
181                                 Map JavaDoc userLoginSessionMap = null;
182                                 try {
183                                     userLoginSession = userLogin.getRelatedOne("UserLoginSession");
184                                     if (userLoginSession != null) {
185                                         Object JavaDoc deserObj = XmlSerializer.deserialize(userLoginSession.getString("sessionData"), delegator);
186                                         //don't check, just cast, if it fails it will get caught and reported below; if (deserObj instanceof Map)
187
userLoginSessionMap = (Map JavaDoc) deserObj;
188                                     }
189                                 } catch (GenericEntityException ge) {
190                                     Debug.logWarning(ge, "Cannot get UserLoginSession for UserLogin ID: " +
191                                             userLogin.getString("userLoginId"), module);
192                                 } catch (Exception JavaDoc e) {
193                                     Debug.logWarning(e, "Problems deserializing UserLoginSession", module);
194                                 }
195
196                                 // return the UserLoginSession Map
197
if (userLoginSessionMap != null) {
198                                     result.put("userLoginSession", userLoginSessionMap);
199                                 }
200                             }
201
202                             result.put("userLogin", userLogin);
203                             result.put(ModelService.RESPONSE_MESSAGE, ModelService.RESPOND_SUCCESS);
204                         } else {
205                             // password is incorrect, but this may be the result of a stale cache entry,
206
// so lets clear the cache and try again if this is the first pass
207
if (isServiceAuth && passNumber <= 1) {
208                                 delegator.clearCacheLine("UserLogin", UtilMisc.toMap("userLoginId", username));
209                                 repeat = true;
210                                 continue;
211                             }
212
213                             Debug.logInfo("[LoginServices.userLogin] : Password Incorrect", module);
214                             // password invalid...
215
errMsg = UtilProperties.getMessage(resource,"loginservices.password_incorrect", locale);
216
217                             // increment failed login count
218
Long JavaDoc currentFailedLogins = userLogin.getLong("successiveFailedLogins");
219
220                             if (currentFailedLogins == null) {
221                                 currentFailedLogins = new Long JavaDoc(1);
222                             } else {
223                                 currentFailedLogins = new Long JavaDoc(currentFailedLogins.longValue() + 1);
224                             }
225                             userLogin.set("successiveFailedLogins", currentFailedLogins);
226
227                             // if failed logins over amount in properties file, disable account
228
String JavaDoc mflStr = UtilProperties.getPropertyValue("security.properties", "max.failed.logins");
229                             long maxFailedLogins = 3;
230                             try {
231                                 maxFailedLogins = Long.parseLong(mflStr);
232                             } catch (Exception JavaDoc e) {
233                                 maxFailedLogins = 3;
234                                 Debug.logWarning("Could not parse max.failed.logins from security.properties, using default of 3", module);
235                             }
236
237                             if (maxFailedLogins > 0 && currentFailedLogins.longValue() >= maxFailedLogins) {
238                                 userLogin.set("enabled", "N");
239                                 userLogin.set("disabledDateTime", UtilDateTime.nowTimestamp());
240                             }
241
242                             successfulLogin = "N";
243                         }
244
245                         // this section is being done in its own transaction rather than in the
246
//current/existing transaction because we may return error and we don't
247
//want that to stop this from getting stored
248
Transaction JavaDoc parentTx = null;
249                         boolean beganTransaction = false;
250
251                         try {
252                             try {
253                                 parentTx = TransactionUtil.suspend();
254                             } catch (GenericTransactionException e) {
255                                 Debug.logError(e, "Could not suspend transaction: " + e.getMessage(), module);
256                             }
257
258                             try {
259                                 beganTransaction = TransactionUtil.begin();
260     
261                                 if (doStore) {
262                                     userLogin.store();
263                                 }
264     
265                                 if ("true".equals(UtilProperties.getPropertyValue("security.properties", "store.login.history"))) {
266                                     boolean createHistory = true;
267                                     
268                                     // only save info on service auth if option set to true to do so
269
if (isServiceAuth && !"true".equals(UtilProperties.getPropertyValue("security.properties", "store.login.history.on.service.auth"))) {
270                                         createHistory = false;
271                                     }
272     
273                                     if (createHistory) {
274                                         Map JavaDoc ulhCreateMap = UtilMisc.toMap("userLoginId", username, "visitId", visitId,
275                                                 "fromDate", UtilDateTime.nowTimestamp(),
276                                                 "partyId", userLogin.get("partyId"), "successfulLogin", successfulLogin);
277     
278                                         // ONLY save the password if it was incorrect
279
if ("N".equals(successfulLogin) && !"false".equals(UtilProperties.getPropertyValue("security.properties", "store.login.history.incorrect.password"))) {
280                                             ulhCreateMap.put("passwordUsed", password);
281                                         }
282                                         
283                                         delegator.create("UserLoginHistory", ulhCreateMap);
284                                     }
285                                 }
286                             } catch (GenericEntityException e) {
287                                 try {
288                                     TransactionUtil.rollback(beganTransaction, "Error saving UserLoginHistory", e);
289                                 } catch (GenericTransactionException e2) {
290                                     Debug.logError(e2, "Could not rollback nested transaction: " + e2.getMessage(), module);
291                                 }
292                                 
293                             } finally {
294                                 try {
295                                     TransactionUtil.commit(beganTransaction);
296                                 } catch (GenericTransactionException e) {
297                                     Debug.logError(e, "Could not commit nested transaction: " + e.getMessage(), module);
298                                 }
299                             }
300                         } finally {
301                             // resume/restore parent transaction
302
if (parentTx != null) {
303                                 try {
304                                     TransactionUtil.resume(parentTx);
305                                     Debug.logVerbose("Resumed the parent transaction.", module);
306                                 } catch (GenericTransactionException e) {
307                                     Debug.logError(e, "Could not resume parent nested transaction: " + e.getMessage(), module);
308                                 }
309                             }
310                         }
311                     } else {
312                         // account is disabled, but this may be the result of a stale cache entry,
313
// so lets clear the cache and try again if this is the first pass
314
if (isServiceAuth && passNumber <= 1) {
315                             delegator.clearCacheLine("UserLogin", UtilMisc.toMap("userLoginId", username));
316                             repeat = true;
317                             continue;
318                         }
319
320                         Map JavaDoc messageMap = UtilMisc.toMap("username", username);
321                         errMsg = UtilProperties.getMessage(resource,"loginservices.account_for_user_login_id_disabled",messageMap ,locale);
322                         if (disabledDateTime != null) {
323                             messageMap = UtilMisc.toMap("disabledDateTime", disabledDateTime);
324                             errMsg += UtilProperties.getMessage(resource,"loginservices.since_datetime",messageMap ,locale);
325                         } else {
326                             errMsg += ".";
327                         }
328
329                         if (loginDisableMinutes > 0 && reEnableTime != null) {
330                             messageMap = UtilMisc.toMap("reEnableTime", reEnableTime);
331                             errMsg += UtilProperties.getMessage(resource,"loginservices.will_be_reenabled",messageMap ,locale);
332                         } else {
333                             errMsg += UtilProperties.getMessage(resource,"loginservices.not_scheduled_to_be_reenabled",locale);
334                         }
335                     }
336                 } else {
337                     // userLogin record not found, user does not exist
338
errMsg = UtilProperties.getMessage(resource, "loginservices.user_not_found", locale);
339                     Debug.logInfo("[LoginServices.userLogin] : Invalid User : " + errMsg, module);
340                 }
341             }
342         }
343
344         if (errMsg.length() > 0) {
345             result.put(ModelService.RESPONSE_MESSAGE, ModelService.RESPOND_ERROR);
346             result.put(ModelService.ERROR_MESSAGE, errMsg);
347         }
348         return result;
349     }
350
351     /** Creates a UserLogin
352      *@param ctx The DispatchContext that this service is operating in
353      *@param context Map containing the input parameters
354      *@return Map with the result of the service, the output parameters
355      */

356     public static Map JavaDoc createUserLogin(DispatchContext ctx, Map JavaDoc context) {
357         Map JavaDoc result = new HashMap JavaDoc();
358         GenericDelegator delegator = ctx.getDelegator();
359         Security security = ctx.getSecurity();
360         GenericValue loggedInUserLogin = (GenericValue) context.get("userLogin");
361         List JavaDoc errorMessageList = new LinkedList JavaDoc();
362         Locale JavaDoc locale = (Locale JavaDoc) context.get("locale");
363
364         boolean useEncryption = "true".equals(UtilProperties.getPropertyValue("security.properties", "password.encrypt"));
365
366         String JavaDoc userLoginId = (String JavaDoc) context.get("userLoginId");
367         String JavaDoc partyId = (String JavaDoc) context.get("partyId");
368         String JavaDoc currentPassword = (String JavaDoc) context.get("currentPassword");
369         String JavaDoc currentPasswordVerify = (String JavaDoc) context.get("currentPasswordVerify");
370         String JavaDoc passwordHint = (String JavaDoc) context.get("passwordHint");
371         String JavaDoc errMsg = null;
372
373         // security: don't create a user login if the specified partyId (if not empty) already exists
374
// unless the logged in user has permission to do so (same partyId or PARTYMGR_CREATE)
375
if (partyId != null && partyId.length() > 0) {
376             GenericValue party = null;
377
378             try {
379                 party = delegator.findByPrimaryKey("Party", UtilMisc.toMap("partyId", partyId));
380             } catch (GenericEntityException e) {
381                 Debug.logWarning(e, "", module);
382             }
383
384             if (party != null) {
385                 if (loggedInUserLogin != null) {
386                     // <b>security check</b>: userLogin partyId must equal partyId, or must have PARTYMGR_CREATE permission
387
if (!partyId.equals(loggedInUserLogin.getString("partyId"))) {
388                         if (!security.hasEntityPermission("PARTYMGR", "_CREATE", loggedInUserLogin)) {
389
390                             errMsg = UtilProperties.getMessage(resource,"loginservices.party_with_specified_party_ID_exists_not_have_permission", locale);
391                             errorMessageList.add(errMsg);
392                         }
393                     }
394                 } else {
395                     errMsg = UtilProperties.getMessage(resource,"loginservices.must_be_logged_in_and_permission_create_login_party_ID_exists", locale);
396                     errorMessageList.add(errMsg);
397                 }
398             }
399         }
400
401         checkNewPassword(null, null, currentPassword, currentPasswordVerify, passwordHint, errorMessageList, true, locale);
402
403         GenericValue userLoginToCreate = delegator.makeValue("UserLogin", UtilMisc.toMap("userLoginId", userLoginId));
404         userLoginToCreate.set("passwordHint", passwordHint);
405         userLoginToCreate.set("partyId", partyId);
406         userLoginToCreate.set("currentPassword", useEncryption ? getPasswordHash(currentPassword) : currentPassword);
407
408         try {
409             if (delegator.findByPrimaryKey(userLoginToCreate.getPrimaryKey()) != null) {
410                 Map JavaDoc messageMap = UtilMisc.toMap("userLoginId", userLoginId);
411                 errMsg = UtilProperties.getMessage(resource,"loginservices.could_not_create_login_user_with_ID_exists", messageMap, locale);
412                 errorMessageList.add(errMsg);
413             }
414         } catch (GenericEntityException e) {
415             Debug.logWarning(e, "", module);
416             Map JavaDoc messageMap = UtilMisc.toMap("errorMessage", e.getMessage());
417             errMsg = UtilProperties.getMessage(resource,"loginservices.could_not_create_login_user_read_failure", messageMap, locale);
418             errorMessageList.add(errMsg);
419         }
420
421         if (errorMessageList.size() > 0) {
422             return ServiceUtil.returnError(errorMessageList);
423         }
424
425         try {
426             userLoginToCreate.create();
427         } catch (GenericEntityException e) {
428             Debug.logWarning(e, "", module);
429             Map JavaDoc messageMap = UtilMisc.toMap("errorMessage", e.getMessage());
430             errMsg = UtilProperties.getMessage(resource,"loginservices.could_not_create_login_user_write_failure", messageMap, locale);
431             return ServiceUtil.returnError(errMsg);
432         }
433
434         result.put(ModelService.RESPONSE_MESSAGE, ModelService.RESPOND_SUCCESS);
435         return result;
436     }
437
438     /** Updates UserLogin Password info
439      *@param ctx The DispatchContext that this service is operating in
440      *@param context Map containing the input parameters
441      *@return Map with the result of the service, the output parameters
442      */

443     public static Map JavaDoc updatePassword(DispatchContext ctx, Map JavaDoc context) {
444         Map JavaDoc result = new HashMap JavaDoc();
445         GenericDelegator delegator = ctx.getDelegator();
446         Security security = ctx.getSecurity();
447         GenericValue loggedInUserLogin = (GenericValue) context.get("userLogin");
448         Locale JavaDoc locale = (Locale JavaDoc) context.get("locale");
449
450         boolean useEncryption = "true".equals(UtilProperties.getPropertyValue("security.properties", "password.encrypt"));
451         boolean adminUser = false;
452
453         String JavaDoc userLoginId = (String JavaDoc) context.get("userLoginId");
454         String JavaDoc errMsg = null;
455
456         if (userLoginId == null || userLoginId.length() == 0) {
457             userLoginId = loggedInUserLogin.getString("userLoginId");
458         }
459
460         // <b>security check</b>: userLogin userLoginId must equal userLoginId, or must have PARTYMGR_UPDATE permission
461
// NOTE: must check permission first so that admin users can set own password without specifying old password
462
if (!security.hasEntityPermission("PARTYMGR", "_UPDATE", loggedInUserLogin)) {
463             if (!userLoginId.equals(loggedInUserLogin.getString("userLoginId"))) {
464                 errMsg = UtilProperties.getMessage(resource,"loginservices.not_have_permission_update_password_for_user_login", locale);
465                 return ServiceUtil.returnError(errMsg);
466             }
467         } else {
468             adminUser = true;
469         }
470
471         GenericValue userLoginToUpdate = null;
472
473         try {
474             userLoginToUpdate = delegator.findByPrimaryKey("UserLogin", UtilMisc.toMap("userLoginId", userLoginId));
475         } catch (GenericEntityException e) {
476             Map JavaDoc messageMap = UtilMisc.toMap("errorMessage", e.getMessage());
477             errMsg = UtilProperties.getMessage(resource,"loginservices.could_not_change_password_read_failure", messageMap, locale);
478             return ServiceUtil.returnError(errMsg);
479         }
480
481         if (userLoginToUpdate == null) {
482             Map JavaDoc messageMap = UtilMisc.toMap("userLoginId", userLoginId);
483             errMsg = UtilProperties.getMessage(resource,"loginservices.could_not_change_password_userlogin_with_id_not_exist", messageMap, locale);
484             return ServiceUtil.returnError(errMsg);
485         }
486
487         String JavaDoc currentPassword = (String JavaDoc) context.get("currentPassword");
488         String JavaDoc newPassword = (String JavaDoc) context.get("newPassword");
489         String JavaDoc newPasswordVerify = (String JavaDoc) context.get("newPasswordVerify");
490         String JavaDoc passwordHint = (String JavaDoc) context.get("passwordHint");
491
492         if ("true".equals(UtilProperties.getPropertyValue("security.properties", "password.lowercase"))) {
493             currentPassword = currentPassword.toLowerCase();
494             newPassword = newPassword.toLowerCase();
495             newPasswordVerify = newPasswordVerify.toLowerCase();
496         }
497
498         List JavaDoc errorMessageList = new LinkedList JavaDoc();
499
500         if (newPassword != null && newPassword.length() > 0) {
501             checkNewPassword(userLoginToUpdate, currentPassword, newPassword, newPasswordVerify,
502                 passwordHint, errorMessageList, adminUser, locale);
503         }
504
505         if (errorMessageList.size() > 0) {
506             return ServiceUtil.returnError(errorMessageList);
507         }
508
509         userLoginToUpdate.set("currentPassword", useEncryption ? getPasswordHash(newPassword) : newPassword, false);
510         userLoginToUpdate.set("passwordHint", passwordHint, false);
511
512         try {
513             userLoginToUpdate.store();
514         } catch (GenericEntityException e) {
515             Map JavaDoc messageMap = UtilMisc.toMap("errorMessage", e.getMessage());
516             errMsg = UtilProperties.getMessage(resource,"loginservices.could_not_change_password_write_failure", messageMap, locale);
517             return ServiceUtil.returnError(errMsg);
518         }
519
520         result.put(ModelService.RESPONSE_MESSAGE, ModelService.RESPOND_SUCCESS);
521         result.put("updatedUserLogin", userLoginToUpdate);
522         return result;
523     }
524
525     /** Updates the UserLoginId for a party, replicating password, etc from
526      * current login and expiring the old login.
527      *@param ctx The DispatchContext that this service is operating in
528      *@param context Map containing the input parameters
529      *@return Map with the result of the service, the output parameters
530      */

531     public static Map JavaDoc updateUserLoginId(DispatchContext ctx, Map JavaDoc context) {
532         Map JavaDoc result = new HashMap JavaDoc();
533         GenericDelegator delegator = ctx.getDelegator();
534         GenericValue loggedInUserLogin = (GenericValue) context.get("userLogin");
535         List JavaDoc errorMessageList = new LinkedList JavaDoc();
536         Locale JavaDoc locale = (Locale JavaDoc) context.get("locale");
537
538         //boolean useEncryption = "true".equals(UtilProperties.getPropertyValue("security.properties", "password.encrypt"));
539

540         String JavaDoc userLoginId = (String JavaDoc) context.get("userLoginId");
541         String JavaDoc errMsg = null;
542
543         if ((userLoginId != null) && ("true".equals(UtilProperties.getPropertyValue("security.properties", "username.lowercase")))) {
544             userLoginId = userLoginId.toLowerCase();
545         }
546
547         String JavaDoc partyId = loggedInUserLogin.getString("partyId");
548         String JavaDoc password = loggedInUserLogin.getString("currentPassword");
549         String JavaDoc passwordHint = loggedInUserLogin.getString("passwordHint");
550
551         // security: don't create a user login if the specified partyId (if not empty) already exists
552
// unless the logged in user has permission to do so (same partyId or PARTYMGR_CREATE)
553
if (partyId != null || partyId.length() > 0) {
554             //GenericValue party = null;
555
//try {
556
// party = delegator.findByPrimaryKey("Party", UtilMisc.toMap("partyId", partyId));
557
//} catch (GenericEntityException e) {
558
// Debug.logWarning(e, "", module);
559
//}
560

561             if (loggedInUserLogin != null) {
562                 // security check: userLogin partyId must equal partyId, or must have PARTYMGR_CREATE permission
563
if (!partyId.equals(loggedInUserLogin.getString("partyId"))) {
564                     errMsg = UtilProperties.getMessage(resource,"loginservices.party_with_party_id_exists_not_permission_create_user_login", locale);
565                     errorMessageList.add(errMsg);
566                 }
567             } else {
568                 errMsg = UtilProperties.getMessage(resource,"loginservices.must_logged_in_have_permission_create_user_login_exists", locale);
569                 errorMessageList.add(errMsg);
570             }
571         }
572
573         GenericValue newUserLogin = null;
574         boolean doCreate = true;
575
576         // check to see if there's a matching login and use it if it's for the same party
577
try {
578             newUserLogin = delegator.findByPrimaryKey("UserLogin", UtilMisc.toMap("userLoginId", userLoginId));
579         } catch (GenericEntityException e) {
580             Debug.logWarning(e, "", module);
581             Map JavaDoc messageMap = UtilMisc.toMap("errorMessage", e.getMessage());
582             errMsg = UtilProperties.getMessage(resource,"loginservices.could_not_create_login_user_read_failure", messageMap, locale);
583             errorMessageList.add(errMsg);
584         }
585
586         if (newUserLogin != null) {
587             if (!newUserLogin.get("partyId").equals(partyId)) {
588                 Map JavaDoc messageMap = UtilMisc.toMap("userLoginId", userLoginId);
589                 errMsg = UtilProperties.getMessage(resource,"loginservices.could_not_create_login_user_with_ID_exists", messageMap, locale);
590                 errorMessageList.add(errMsg);
591             } else {
592                 doCreate = false;
593             }
594         } else {
595             newUserLogin = delegator.makeValue("UserLogin", UtilMisc.toMap("userLoginId", userLoginId));
596         }
597
598         newUserLogin.set("passwordHint", passwordHint);
599         newUserLogin.set("partyId", partyId);
600         newUserLogin.set("currentPassword", password);
601         newUserLogin.set("enabled", "Y");
602         newUserLogin.set("disabledDateTime", null);
603
604         if (errorMessageList.size() > 0) {
605             return ServiceUtil.returnError(errorMessageList);
606         }
607
608         try {
609             if (doCreate) {
610                 newUserLogin.create();
611             } else {
612                 newUserLogin.store();
613             }
614         } catch (GenericEntityException e) {
615             Debug.logWarning(e, "", module);
616             Map JavaDoc messageMap = UtilMisc.toMap("errorMessage", e.getMessage());
617             errMsg = UtilProperties.getMessage(resource,"loginservices.could_not_create_login_user_write_failure", messageMap, locale);
618             return ServiceUtil.returnError(errMsg);
619         }
620
621         loggedInUserLogin.set("enabled", "N");
622         loggedInUserLogin.set("disabledDateTime", UtilDateTime.nowTimestamp());
623
624         try {
625             loggedInUserLogin.store();
626         } catch (GenericEntityException e) {
627             Debug.logWarning(e, "", module);
628             Map JavaDoc messageMap = UtilMisc.toMap("errorMessage", e.getMessage());
629             errMsg = UtilProperties.getMessage(resource,"loginservices.could_not_disable_old_login_user_write_failure", messageMap, locale);
630             return ServiceUtil.returnError(errMsg);
631         }
632
633         result.put(ModelService.RESPONSE_MESSAGE, ModelService.RESPOND_SUCCESS);
634         result.put("newUserLogin", newUserLogin);
635         return result;
636     }
637
638     /** Updates UserLogin Security info
639      *@param ctx The DispatchContext that this service is operating in
640      *@param context Map containing the input parameters
641      *@return Map with the result of the service, the output parameters
642      */

643     public static Map JavaDoc updateUserLoginSecurity(DispatchContext ctx, Map JavaDoc context) {
644         Map JavaDoc result = new HashMap JavaDoc();
645         GenericDelegator delegator = ctx.getDelegator();
646         Security security = ctx.getSecurity();
647         GenericValue loggedInUserLogin = (GenericValue) context.get("userLogin");
648         Locale JavaDoc locale = (Locale JavaDoc) context.get("locale");
649
650         String JavaDoc userLoginId = (String JavaDoc) context.get("userLoginId");
651         String JavaDoc errMsg = null;
652
653         if (userLoginId == null || userLoginId.length() == 0) {
654             userLoginId = loggedInUserLogin.getString("userLoginId");
655         }
656
657         // <b>security check</b>: must have PARTYMGR_UPDATE permission
658
if (!security.hasEntityPermission("PARTYMGR", "_UPDATE", loggedInUserLogin) && !security.hasEntityPermission("SECURITY", "_UPDATE", loggedInUserLogin)) {
659             errMsg = UtilProperties.getMessage(resource,"loginservices.not_permission_update_security_info_for_user_login", locale);
660             return ServiceUtil.returnError(errMsg);
661         }
662
663         GenericValue userLoginToUpdate = null;
664
665         try {
666             userLoginToUpdate = delegator.findByPrimaryKey("UserLogin", UtilMisc.toMap("userLoginId", userLoginId));
667         } catch (GenericEntityException e) {
668             Map JavaDoc messageMap = UtilMisc.toMap("errorMessage", e.getMessage());
669             errMsg = UtilProperties.getMessage(resource,"loginservices.could_not_change_password_read_failure", messageMap, locale);
670             return ServiceUtil.returnError(errMsg);
671         }
672
673         if (userLoginToUpdate == null) {
674             Map JavaDoc messageMap = UtilMisc.toMap("userLoginId", userLoginId);
675             errMsg = UtilProperties.getMessage(resource,"loginservices.could_not_change_password_userlogin_with_id_not_exist", messageMap, locale);
676             return ServiceUtil.returnError(errMsg);
677         }
678         
679         boolean wasEnabled = !"N".equals(userLoginToUpdate.get("enabled"));
680
681         if (context.containsKey("enabled")) {
682             userLoginToUpdate.set("enabled", context.get("enabled"), true);
683         }
684         if (context.containsKey("disabledDateTime")) {
685             userLoginToUpdate.set("disabledDateTime", context.get("disabledDateTime"), true);
686         }
687         if (context.containsKey("successiveFailedLogins")) {
688             userLoginToUpdate.set("successiveFailedLogins", context.get("successiveFailedLogins"), true);
689         }
690
691         // if was disabled and we are enabling it, clear disabledDateTime
692
if (!wasEnabled && "Y".equals(context.get("enabled"))) {
693             userLoginToUpdate.set("disabledDateTime", null);
694         }
695
696         // if was enabled and we are disabling it, and no disabledDateTime was passed, set it to now
697
if (wasEnabled && "N".equals(context.get("enabled")) && context.get("disabledDateTime") == null) {
698             userLoginToUpdate.set("disabledDateTime", UtilDateTime.nowTimestamp());
699         }
700
701         try {
702             userLoginToUpdate.store();
703         } catch (GenericEntityException e) {
704             Map JavaDoc messageMap = UtilMisc.toMap("errorMessage", e.getMessage());
705             errMsg = UtilProperties.getMessage(resource,"loginservices.could_not_change_password_write_failure", messageMap, locale);
706             return ServiceUtil.returnError(errMsg);
707         }
708
709         result.put(ModelService.RESPONSE_MESSAGE, ModelService.RESPOND_SUCCESS);
710         return result;
711     }
712
713     public static void checkNewPassword(GenericValue userLogin, String JavaDoc currentPassword, String JavaDoc newPassword, String JavaDoc newPasswordVerify, String JavaDoc passwordHint, List JavaDoc errorMessageList, boolean ignoreCurrentPassword, Locale JavaDoc locale) {
714         boolean useEncryption = "true".equals(UtilProperties.getPropertyValue("security.properties", "password.encrypt"));
715
716         String JavaDoc errMsg = null;
717
718         if (!ignoreCurrentPassword) {
719             String JavaDoc realPassword = currentPassword;
720
721             if (useEncryption && currentPassword != null) {
722                 realPassword = LoginServices.getPasswordHash(currentPassword);
723             }
724             // if the password.accept.encrypted.and.plain property in security is set to true allow plain or encrypted passwords
725
boolean passwordMatches = currentPassword != null && (realPassword.equals(userLogin.getString("currentPassword")) ||
726                     ("true".equals(UtilProperties.getPropertyValue("security.properties", "password.accept.encrypted.and.plain")) && currentPassword.equals(userLogin.getString("currentPassword"))));
727
728             if ((currentPassword == null) || (userLogin != null && currentPassword != null && !passwordMatches)) {
729                 errMsg = UtilProperties.getMessage(resource,"loginservices.old_password_not_correct_reenter", locale);
730                 errorMessageList.add(errMsg);
731             }
732         }
733
734         if (!UtilValidate.isNotEmpty(newPassword) || !UtilValidate.isNotEmpty(newPasswordVerify)) {
735             errMsg = UtilProperties.getMessage(resource,"loginservices.password_or_verify_missing", locale);
736             errorMessageList.add(errMsg);
737         } else if (!newPassword.equals(newPasswordVerify)) {
738             errMsg = UtilProperties.getMessage(resource,"loginservices.password_did_not_match_verify_password", locale);
739             errorMessageList.add(errMsg);
740         }
741
742         int minPasswordLength = 0;
743
744         try {
745             minPasswordLength = Integer.parseInt(UtilProperties.getPropertyValue("security.properties", "password.length.min", "0"));
746         } catch (NumberFormatException JavaDoc nfe) {
747             minPasswordLength = 0;
748         }
749
750         if (newPassword != null) {
751             if (!(newPassword.length() >= minPasswordLength)) {
752                 Map JavaDoc messageMap = UtilMisc.toMap("minPasswordLength", Integer.toString(minPasswordLength));
753                 errMsg = UtilProperties.getMessage(resource,"loginservices.password_must_be_least_characters_long", messageMap, locale);
754                 errorMessageList.add(errMsg);
755             }
756             if (userLogin != null && newPassword.equalsIgnoreCase(userLogin.getString("userLoginId"))) {
757                 errMsg = UtilProperties.getMessage(resource,"loginservices.password_may_not_equal_username", locale);
758                 errorMessageList.add(errMsg);
759             }
760             if (UtilValidate.isNotEmpty(passwordHint) && (passwordHint.toUpperCase().indexOf(newPassword.toUpperCase()) >= 0)) {
761                 errMsg = UtilProperties.getMessage(resource,"loginservices.password_hint_may_not_contain_password", locale);
762                 errorMessageList.add(errMsg);
763             }
764         }
765     }
766
767     public static String JavaDoc getPasswordHash(String JavaDoc str) {
768         String JavaDoc hashType = UtilProperties.getPropertyValue("security.properties", "password.encrypt.hash.type");
769
770         if (hashType == null || hashType.length() == 0) {
771             Debug.logWarning("Password encrypt hash type is not specified in security.properties, use SHA", module);
772             hashType = "SHA";
773         }
774
775         return HashCrypt.getDigestHash(str, hashType);
776     }
777 }
778
Popular Tags