001: /*
002: * $Id: LoginServices.java,v 1.3 2003/12/09 20:47:32 jonesde Exp $
003: *
004: * Copyright (c) 2001, 2002 The Open For Business Project - www.ofbiz.org
005: *
006: * Permission is hereby granted, free of charge, to any person obtaining a
007: * copy of this software and associated documentation files (the "Software"),
008: * to deal in the Software without restriction, including without limitation
009: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
010: * and/or sell copies of the Software, and to permit persons to whom the
011: * Software is furnished to do so, subject to the following conditions:
012: *
013: * The above copyright notice and this permission notice shall be included
014: * in all copies or substantial portions of the Software.
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
017: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
018: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
019: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
020: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
021: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
022: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
023: */
024: package org.ofbiz.securityext.login;
025:
026: import java.sql.Timestamp;
027: import java.util.HashMap;
028: import java.util.LinkedList;
029: import java.util.List;
030: import java.util.Map;
031:
032: import javax.transaction.InvalidTransactionException;
033: import javax.transaction.SystemException;
034: import javax.transaction.Transaction;
035: import javax.transaction.TransactionManager;
036:
037: import org.ofbiz.base.util.Debug;
038: import org.ofbiz.base.util.UtilDateTime;
039: import org.ofbiz.base.util.UtilMisc;
040: import org.ofbiz.base.util.UtilProperties;
041: import org.ofbiz.base.util.UtilValidate;
042: import org.ofbiz.entity.GenericDelegator;
043: import org.ofbiz.entity.GenericEntityException;
044: import org.ofbiz.entity.GenericValue;
045: import org.ofbiz.entity.serialize.XmlSerializer;
046: import org.ofbiz.entity.transaction.GenericTransactionException;
047: import org.ofbiz.entity.transaction.TransactionFactory;
048: import org.ofbiz.entity.transaction.TransactionUtil;
049: import org.ofbiz.security.Security;
050: import org.ofbiz.service.DispatchContext;
051: import org.ofbiz.service.ModelService;
052: import org.ofbiz.service.ServiceUtil;
053:
054: /**
055: * <b>Title:</b> Login Services
056: *
057: * @author <a href="mailto:jaz@ofbiz.org">Andy Zeneski</a>
058: * @author <a href="mailto:jonesde@ofbiz.org">David E. Jones</a>
059: * @version $Revision: 1.3 $
060: * @since 2.0
061: */
062: public class LoginServices {
063:
064: public static final String module = LoginServices.class.getName();
065:
066: /** Login service to authenticate username and password
067: * @return Map of results including (userLogin) GenericValue object
068: */
069: public static Map userLogin(DispatchContext ctx, Map context) {
070: Map result = new HashMap();
071: GenericDelegator delegator = ctx.getDelegator();
072:
073: boolean useEncryption = "true".equals(UtilProperties
074: .getPropertyValue("security.properties",
075: "password.encrypt"));
076:
077: // if isServiceAuth is not specified, default to not a service auth
078: boolean isServiceAuth = context.get("isServiceAuth") != null
079: && ((Boolean) context.get("isServiceAuth"))
080: .booleanValue();
081:
082: String username = (String) context.get("login.username");
083: if (username == null)
084: username = (String) context.get("username");
085: String password = (String) context.get("login.password");
086: if (password == null)
087: password = (String) context.get("password");
088:
089: // get the visitId for the history entity
090: String visitId = (String) context.get("visitId");
091:
092: String errMsg = "";
093: if (username == null || username.length() <= 0) {
094: errMsg = "Username missing.";
095: } else if (password == null || password.length() <= 0) {
096: errMsg = "Password missing";
097: } else {
098: String realPassword = useEncryption ? HashEncrypt
099: .getHash(password) : password;
100:
101: boolean repeat = true;
102: // starts at zero but it incremented at the beggining so in the first pass passNumber will be 1
103: int passNumber = 0;
104:
105: while (repeat) {
106: repeat = false;
107: // pass number is incremented here because there are continues in this loop so it may never get to the end
108: passNumber++;
109:
110: GenericValue userLogin = null;
111:
112: try {
113: // only get userLogin from cache for service calls; for web and other manual logins there is less time sensitivity
114: if (isServiceAuth) {
115: userLogin = delegator.findByPrimaryKeyCache(
116: "UserLogin", UtilMisc.toMap(
117: "userLoginId", username));
118: } else {
119: userLogin = delegator.findByPrimaryKey(
120: "UserLogin", UtilMisc.toMap(
121: "userLoginId", username));
122: }
123: } catch (GenericEntityException e) {
124: Debug.logWarning(e, "", module);
125: }
126:
127: if (userLogin != null) {
128: String ldmStr = UtilProperties.getPropertyValue(
129: "security.properties",
130: "login.disable.minutes");
131: long loginDisableMinutes = 30;
132:
133: try {
134: loginDisableMinutes = Long.parseLong(ldmStr);
135: } catch (Exception e) {
136: loginDisableMinutes = 30;
137: Debug
138: .logWarning(
139: "Could not parse login.disable.minutes from security.properties, using default of 30",
140: module);
141: }
142:
143: Timestamp disabledDateTime = userLogin
144: .getTimestamp("disabledDateTime");
145: Timestamp reEnableTime = null;
146:
147: if (loginDisableMinutes > 0
148: && disabledDateTime != null) {
149: reEnableTime = new Timestamp(disabledDateTime
150: .getTime()
151: + loginDisableMinutes * 60000);
152: }
153:
154: boolean doStore = true;
155: // we might change & store this userLogin, so we should clone it here to get a mutable copy
156: userLogin = new GenericValue(userLogin);
157:
158: if (UtilValidate.isEmpty(userLogin
159: .getString("enabled"))
160: || "Y".equals(userLogin
161: .getString("enabled"))
162: || (reEnableTime != null && reEnableTime
163: .before(UtilDateTime.nowTimestamp()))) {
164:
165: String successfulLogin;
166:
167: userLogin.set("enabled", "Y");
168: // if the password.accept.encrypted.and.plain property in security is set to true allow plain or encrypted passwords
169: if (userLogin.get("currentPassword") != null
170: && (realPassword.equals(userLogin
171: .getString("currentPassword")) || ("true"
172: .equals(UtilProperties
173: .getPropertyValue(
174: "security.properties",
175: "password.accept.encrypted.and.plain")) && password
176: .equals(userLogin
177: .getString("currentPassword"))))) {
178: Debug
179: .logVerbose(
180: "[LoginServices.userLogin] : Password Matched",
181: module);
182:
183: // reset failed login count if necessry
184: Long currentFailedLogins = userLogin
185: .getLong("successiveFailedLogins");
186: if (currentFailedLogins != null
187: && currentFailedLogins.longValue() > 0) {
188: userLogin.set("successiveFailedLogins",
189: new Long(0));
190: } else {
191: // successful login, no need to change anything, so don't do the store
192: doStore = false;
193: }
194:
195: successfulLogin = "Y";
196:
197: if (!isServiceAuth) {
198: // get the UserLoginSession if this is not a service auth
199: GenericValue userLoginSession = null;
200: Map userLoginSessionMap = null;
201: try {
202: userLoginSession = userLogin
203: .getRelatedOne("UserLoginSession");
204: if (userLoginSession != null) {
205: Object deserObj = XmlSerializer
206: .deserialize(
207: userLoginSession
208: .getString("sessionData"),
209: delegator);
210: //don't check, just cast, if it fails it will get caught and reported below; if (deserObj instanceof Map)
211: userLoginSessionMap = (Map) deserObj;
212: }
213: } catch (GenericEntityException ge) {
214: Debug
215: .logWarning(
216: ge,
217: "Cannot get UserLoginSession for UserLogin ID: "
218: + userLogin
219: .getString("userLoginId"),
220: module);
221: } catch (Exception e) {
222: Debug
223: .logWarning(
224: e,
225: "Problems deserializing UserLoginSession",
226: module);
227: }
228:
229: // return the UserLoginSession Map
230: if (userLoginSessionMap != null) {
231: result.put("userLoginSession",
232: userLoginSessionMap);
233: }
234: }
235:
236: result.put("userLogin", userLogin);
237: result.put(ModelService.RESPONSE_MESSAGE,
238: ModelService.RESPOND_SUCCESS);
239: } else {
240: // password is incorrect, but this may be the result of a stale cache entry,
241: // so lets clear the cache and try again if this is the first pass
242: if (isServiceAuth && passNumber <= 1) {
243: delegator.clearCacheLine("UserLogin",
244: UtilMisc.toMap("userLoginId",
245: username));
246: repeat = true;
247: continue;
248: }
249:
250: Debug
251: .logInfo(
252: "[LoginServices.userLogin] : Password Incorrect",
253: module);
254: // password invalid...
255: errMsg = "Password incorrect.";
256:
257: // increment failed login count
258: Long currentFailedLogins = userLogin
259: .getLong("successiveFailedLogins");
260:
261: if (currentFailedLogins == null) {
262: currentFailedLogins = new Long(1);
263: } else {
264: currentFailedLogins = new Long(
265: currentFailedLogins.longValue() + 1);
266: }
267: userLogin.set("successiveFailedLogins",
268: currentFailedLogins);
269:
270: // if failed logins over amount in properties file, disable account
271: String mflStr = UtilProperties
272: .getPropertyValue(
273: "security.properties",
274: "max.failed.logins");
275: long maxFailedLogins = 3;
276:
277: try {
278: maxFailedLogins = Long
279: .parseLong(mflStr);
280: } catch (Exception e) {
281: maxFailedLogins = 3;
282: Debug
283: .logWarning(
284: "Could not parse max.failed.logins from security.properties, using default of 3",
285: module);
286: }
287:
288: if (maxFailedLogins > 0
289: && currentFailedLogins.longValue() >= maxFailedLogins) {
290: userLogin.set("enabled", "N");
291: userLogin.set("disabledDateTime",
292: UtilDateTime.nowTimestamp());
293: }
294:
295: successfulLogin = "N";
296: }
297:
298: // this section is being done in its own transaction rather than in the
299: //current/existing transaction because we may return error and we don't
300: //want that to stop this from getting stored
301: TransactionManager txMgr = TransactionFactory
302: .getTransactionManager();
303: Transaction parentTx = null;
304: boolean beganTransaction = false;
305:
306: try {
307: if (txMgr != null) {
308: try {
309: parentTx = txMgr.suspend();
310: beganTransaction = TransactionUtil
311: .begin();
312: } catch (SystemException se) {
313: Debug.logError(se,
314: "Cannot suspend transaction: "
315: + se.getMessage(),
316: module);
317: } catch (GenericTransactionException e) {
318: Debug.logError(e,
319: "Cannot begin nested transaction: "
320: + e.getMessage(),
321: module);
322: }
323: }
324:
325: if (doStore) {
326: try {
327: userLogin.store();
328: } catch (GenericEntityException e) {
329: Debug.logWarning(e, "", module);
330: }
331: }
332:
333: if ("true".equals(UtilProperties
334: .getPropertyValue(
335: "security.properties",
336: "store.login.history"))) {
337: boolean createHistory = true;
338:
339: if (isServiceAuth
340: && !"true"
341: .equals(UtilProperties
342: .getPropertyValue(
343: "security.properties",
344: "store.login.history.on.service.auth"))) {
345: createHistory = false;
346: }
347:
348: if (createHistory) {
349: try {
350: delegator
351: .create(
352: "UserLoginHistory",
353: UtilMisc
354: .toMap(
355: "userLoginId",
356: username,
357: "visitId",
358: visitId,
359: "fromDate",
360: UtilDateTime
361: .nowTimestamp(),
362: "passwordUsed",
363: password,
364: "partyId",
365: userLogin
366: .get("partyId"),
367: "successfulLogin",
368: successfulLogin));
369: } catch (GenericEntityException e) {
370: Debug.logWarning(e, "", module);
371: }
372: }
373: }
374:
375: try {
376: TransactionUtil
377: .commit(beganTransaction);
378: } catch (GenericTransactionException e) {
379: Debug.logError(e,
380: "Could not commit nested transaction: "
381: + e.getMessage(),
382: module);
383: }
384: } finally {
385: // resume/restore parent transaction
386: if (parentTx != null) {
387: try {
388: txMgr.resume(parentTx);
389: Debug
390: .logVerbose(
391: "Resumed the parent transaction.",
392: module);
393: } catch (InvalidTransactionException ite) {
394: Debug.logError(ite,
395: "Cannot resume transaction: "
396: + ite.getMessage(),
397: module);
398: } catch (SystemException se) {
399: Debug.logError(se,
400: "Unexpected transaction error: "
401: + se.getMessage(),
402: module);
403: }
404: }
405: }
406: } else {
407: // account is disabled, but this may be the result of a stale cache entry,
408: // so lets clear the cache and try again if this is the first pass
409: if (isServiceAuth && passNumber <= 1) {
410: delegator.clearCacheLine("UserLogin",
411: UtilMisc.toMap("userLoginId",
412: username));
413: repeat = true;
414: continue;
415: }
416:
417: errMsg = "The account for user login id \""
418: + username + "\" has been disabled";
419: if (disabledDateTime != null) {
420: errMsg += " since " + disabledDateTime
421: + ".";
422: } else {
423: errMsg += ".";
424: }
425:
426: if (loginDisableMinutes > 0
427: && reEnableTime != null) {
428: errMsg += " It will be re-enabled "
429: + reEnableTime + ".";
430: } else {
431: errMsg += " It is not scheduled to be re-enabled.";
432: }
433: }
434: } else {
435: // userLogin record not found, user does not exist
436: errMsg = "User not found.";
437: Debug.logInfo(
438: "[LoginServices.userLogin] : Invalid User : "
439: + errMsg, module);
440: }
441: }
442: }
443:
444: if (errMsg.length() > 0) {
445: result.put(ModelService.RESPONSE_MESSAGE,
446: ModelService.RESPOND_ERROR);
447: result.put(ModelService.ERROR_MESSAGE, errMsg);
448: }
449: return result;
450: }
451:
452: /** Creates a UserLogin
453: *@param ctx The DispatchContext that this service is operating in
454: *@param context Map containing the input parameters
455: *@return Map with the result of the service, the output parameters
456: */
457: public static Map createUserLogin(DispatchContext ctx, Map context) {
458: Map result = new HashMap();
459: GenericDelegator delegator = ctx.getDelegator();
460: Security security = ctx.getSecurity();
461: GenericValue loggedInUserLogin = (GenericValue) context
462: .get("userLogin");
463: List errorMessageList = new LinkedList();
464:
465: boolean useEncryption = "true".equals(UtilProperties
466: .getPropertyValue("security.properties",
467: "password.encrypt"));
468:
469: String userLoginId = (String) context.get("userLoginId");
470: String partyId = (String) context.get("partyId");
471: String currentPassword = (String) context
472: .get("currentPassword");
473: String currentPasswordVerify = (String) context
474: .get("currentPasswordVerify");
475: String passwordHint = (String) context.get("passwordHint");
476:
477: // security: don't create a user login if the specified partyId (if not empty) already exists
478: // unless the logged in user has permission to do so (same partyId or PARTYMGR_CREATE)
479: if (partyId != null && partyId.length() > 0) {
480: GenericValue party = null;
481:
482: try {
483: party = delegator.findByPrimaryKey("Party", UtilMisc
484: .toMap("partyId", partyId));
485: } catch (GenericEntityException e) {
486: Debug.logWarning(e, "", module);
487: }
488:
489: if (party != null) {
490: if (loggedInUserLogin != null) {
491: // <b>security check</b>: userLogin partyId must equal partyId, or must have PARTYMGR_CREATE permission
492: if (!partyId.equals(loggedInUserLogin
493: .getString("partyId"))) {
494: if (!security.hasEntityPermission("PARTYMGR",
495: "_CREATE", loggedInUserLogin)) {
496: errorMessageList
497: .add("Party with specified party ID exists and you do not have permission to create a user login with this party ID");
498: }
499: }
500: } else {
501: errorMessageList
502: .add("You must be logged in and have permission to create a user login with a party ID for a party that already exists");
503: }
504: }
505: }
506:
507: checkNewPassword(null, null, currentPassword,
508: currentPasswordVerify, passwordHint, errorMessageList,
509: true);
510:
511: GenericValue userLoginToCreate = delegator
512: .makeValue("UserLogin", UtilMisc.toMap("userLoginId",
513: userLoginId));
514: userLoginToCreate.set("passwordHint", passwordHint);
515: userLoginToCreate.set("partyId", partyId);
516: userLoginToCreate.set("currentPassword",
517: useEncryption ? HashEncrypt.getHash(currentPassword)
518: : currentPassword);
519:
520: try {
521: if (delegator.findByPrimaryKey(userLoginToCreate
522: .getPrimaryKey()) != null) {
523: errorMessageList
524: .add("Could not create login user: user with ID \""
525: + userLoginId + "\" already exists");
526: }
527: } catch (GenericEntityException e) {
528: Debug.logWarning(e, "", module);
529: errorMessageList
530: .add("Could not create login user (read failure): "
531: + e.getMessage());
532: }
533:
534: if (errorMessageList.size() > 0) {
535: return ServiceUtil.returnError(errorMessageList);
536: }
537:
538: try {
539: userLoginToCreate.create();
540: } catch (GenericEntityException e) {
541: Debug.logWarning(e, "", module);
542: return ServiceUtil
543: .returnError("Could create login user (write failure): "
544: + e.getMessage());
545: }
546:
547: result.put(ModelService.RESPONSE_MESSAGE,
548: ModelService.RESPOND_SUCCESS);
549: return result;
550: }
551:
552: /** Updates UserLogin Password info
553: *@param ctx The DispatchContext that this service is operating in
554: *@param context Map containing the input parameters
555: *@return Map with the result of the service, the output parameters
556: */
557: public static Map updatePassword(DispatchContext ctx, Map context) {
558: Map result = new HashMap();
559: GenericDelegator delegator = ctx.getDelegator();
560: Security security = ctx.getSecurity();
561: GenericValue loggedInUserLogin = (GenericValue) context
562: .get("userLogin");
563:
564: boolean useEncryption = "true".equals(UtilProperties
565: .getPropertyValue("security.properties",
566: "password.encrypt"));
567: boolean adminUser = false;
568:
569: String userLoginId = (String) context.get("userLoginId");
570:
571: if (userLoginId == null || userLoginId.length() == 0) {
572: userLoginId = loggedInUserLogin.getString("userLoginId");
573: }
574:
575: // <b>security check</b>: userLogin userLoginId must equal userLoginId, or must have PARTYMGR_UPDATE permission
576: // NOTE: must check permission first so that admin users can set own password without specifying old password
577: if (!security.hasEntityPermission("PARTYMGR", "_UPDATE",
578: loggedInUserLogin)) {
579: if (!userLoginId.equals(loggedInUserLogin
580: .getString("userLoginId"))) {
581: return ServiceUtil
582: .returnError("You do not have permission to update the password for this user login");
583: }
584: } else {
585: adminUser = true;
586: }
587:
588: GenericValue userLoginToUpdate = null;
589:
590: try {
591: userLoginToUpdate = delegator.findByPrimaryKey("UserLogin",
592: UtilMisc.toMap("userLoginId", userLoginId));
593: } catch (GenericEntityException e) {
594: return ServiceUtil
595: .returnError("Could not change password (read failure): "
596: + e.getMessage());
597: }
598:
599: if (userLoginToUpdate == null) {
600: return ServiceUtil
601: .returnError("Could not change password, UserLogin with ID \""
602: + userLoginId + "\" does not exist");
603: }
604:
605: String currentPassword = (String) context
606: .get("currentPassword");
607: String newPassword = (String) context.get("newPassword");
608: String newPasswordVerify = (String) context
609: .get("newPasswordVerify");
610: String passwordHint = (String) context.get("passwordHint");
611:
612: if ("true".equals(UtilProperties.getPropertyValue(
613: "security.properties", "password.lowercase"))) {
614: currentPassword = currentPassword.toLowerCase();
615: newPassword = newPassword.toLowerCase();
616: newPasswordVerify = newPasswordVerify.toLowerCase();
617: }
618:
619: List errorMessageList = new LinkedList();
620:
621: if (newPassword != null && newPassword.length() > 0) {
622: checkNewPassword(userLoginToUpdate, currentPassword,
623: newPassword, newPasswordVerify, passwordHint,
624: errorMessageList, adminUser);
625: }
626:
627: if (errorMessageList.size() > 0) {
628: return ServiceUtil.returnError(errorMessageList);
629: }
630:
631: userLoginToUpdate.set("currentPassword",
632: useEncryption ? HashEncrypt.getHash(newPassword)
633: : newPassword, false);
634: userLoginToUpdate.set("passwordHint", passwordHint, false);
635:
636: try {
637: userLoginToUpdate.store();
638: } catch (GenericEntityException e) {
639: return ServiceUtil
640: .returnError("Could not change password (write failure): "
641: + e.getMessage());
642: }
643:
644: result.put(ModelService.RESPONSE_MESSAGE,
645: ModelService.RESPOND_SUCCESS);
646: result.put("updatedUserLogin", userLoginToUpdate);
647: return result;
648: }
649:
650: /** Updates the UserLoginId for a party, replicating password, etc from
651: * current login and expiring the old login.
652: *@param ctx The DispatchContext that this service is operating in
653: *@param context Map containing the input parameters
654: *@return Map with the result of the service, the output parameters
655: */
656: public static Map updateUserLoginId(DispatchContext ctx, Map context) {
657: Map result = new HashMap();
658: GenericDelegator delegator = ctx.getDelegator();
659: GenericValue loggedInUserLogin = (GenericValue) context
660: .get("userLogin");
661: List errorMessageList = new LinkedList();
662:
663: //boolean useEncryption = "true".equals(UtilProperties.getPropertyValue("security.properties", "password.encrypt"));
664:
665: String userLoginId = (String) context.get("userLoginId");
666:
667: if ((userLoginId != null)
668: && ("true".equals(UtilProperties.getPropertyValue(
669: "security.properties", "username.lowercase")))) {
670: userLoginId = userLoginId.toLowerCase();
671: }
672:
673: String partyId = loggedInUserLogin.getString("partyId");
674: String password = loggedInUserLogin
675: .getString("currentPassword");
676: String passwordHint = loggedInUserLogin
677: .getString("passwordHint");
678:
679: // security: don't create a user login if the specified partyId (if not empty) already exists
680: // unless the logged in user has permission to do so (same partyId or PARTYMGR_CREATE)
681: if (partyId != null || partyId.length() > 0) {
682: //GenericValue party = null;
683: //try {
684: // party = delegator.findByPrimaryKey("Party", UtilMisc.toMap("partyId", partyId));
685: //} catch (GenericEntityException e) {
686: // Debug.logWarning(e, "", module);
687: //}
688:
689: if (loggedInUserLogin != null) {
690: // security check: userLogin partyId must equal partyId, or must have PARTYMGR_CREATE permission
691: if (!partyId.equals(loggedInUserLogin
692: .getString("partyId"))) {
693: errorMessageList
694: .add("Party with specified party ID exists and you do not have permission to create a user login with this party ID");
695: }
696: } else {
697: errorMessageList
698: .add("You must be logged in and have permission to create a user login with a party ID for a party that already exists");
699: }
700: }
701:
702: GenericValue newUserLogin = null;
703: boolean doCreate = true;
704:
705: // check to see if there's a matching login and use it if it's for the same party
706: try {
707: newUserLogin = delegator.findByPrimaryKey("UserLogin",
708: UtilMisc.toMap("userLoginId", userLoginId));
709: } catch (GenericEntityException e) {
710: Debug.logWarning(e, "", module);
711: errorMessageList
712: .add("Could not create login user (read failure): "
713: + e.getMessage());
714: }
715:
716: if (newUserLogin != null) {
717: if (!newUserLogin.get("partyId").equals(partyId)) {
718: errorMessageList
719: .add("Could not create login user: user with ID \""
720: + userLoginId + "\" already exists");
721: } else {
722: doCreate = false;
723: }
724: } else {
725: newUserLogin = delegator.makeValue("UserLogin", UtilMisc
726: .toMap("userLoginId", userLoginId));
727: }
728:
729: newUserLogin.set("passwordHint", passwordHint);
730: newUserLogin.set("partyId", partyId);
731: newUserLogin.set("currentPassword", password);
732: newUserLogin.set("enabled", "Y");
733: newUserLogin.set("disabledDateTime", null);
734:
735: if (errorMessageList.size() > 0) {
736: return ServiceUtil.returnError(errorMessageList);
737: }
738:
739: try {
740: if (doCreate) {
741: newUserLogin.create();
742: } else {
743: newUserLogin.store();
744: }
745: } catch (GenericEntityException e) {
746: Debug.logWarning(e, "", module);
747: return ServiceUtil
748: .returnError("Couldn't create login user (write failure): "
749: + e.getMessage());
750: }
751:
752: loggedInUserLogin.set("enabled", "N");
753: loggedInUserLogin.set("disabledDateTime", UtilDateTime
754: .nowTimestamp());
755:
756: try {
757: loggedInUserLogin.store();
758: } catch (GenericEntityException e) {
759: Debug.logWarning(e, "", module);
760: return ServiceUtil
761: .returnError("Couldn't disable old login user (write failure): "
762: + e.getMessage());
763: }
764:
765: result.put(ModelService.RESPONSE_MESSAGE,
766: ModelService.RESPOND_SUCCESS);
767: result.put("newUserLogin", newUserLogin);
768: return result;
769: }
770:
771: /** Updates UserLogin Security info
772: *@param ctx The DispatchContext that this service is operating in
773: *@param context Map containing the input parameters
774: *@return Map with the result of the service, the output parameters
775: */
776: public static Map updateUserLoginSecurity(DispatchContext ctx,
777: Map context) {
778: Map result = new HashMap();
779: GenericDelegator delegator = ctx.getDelegator();
780: Security security = ctx.getSecurity();
781: GenericValue loggedInUserLogin = (GenericValue) context
782: .get("userLogin");
783:
784: String userLoginId = (String) context.get("userLoginId");
785:
786: if (userLoginId == null || userLoginId.length() == 0) {
787: userLoginId = loggedInUserLogin.getString("userLoginId");
788: }
789:
790: // <b>security check</b>: must have PARTYMGR_UPDATE permission
791: if (!security.hasEntityPermission("PARTYMGR", "_UPDATE",
792: loggedInUserLogin)
793: && !security.hasEntityPermission("SECURITY", "_UPDATE",
794: loggedInUserLogin)) {
795: return ServiceUtil
796: .returnError("You do not have permission to update the security info for this user login");
797: }
798:
799: GenericValue userLoginToUpdate = null;
800:
801: try {
802: userLoginToUpdate = delegator.findByPrimaryKey("UserLogin",
803: UtilMisc.toMap("userLoginId", userLoginId));
804: } catch (GenericEntityException e) {
805: return ServiceUtil
806: .returnError("Could not change password (read failure): "
807: + e.getMessage());
808: }
809:
810: if (userLoginToUpdate == null) {
811: return ServiceUtil
812: .returnError("Could not change password, UserLogin with ID \""
813: + userLoginId + "\" does not exist");
814: }
815:
816: boolean wasEnabled = !"N".equals(userLoginToUpdate
817: .get("enabled"));
818:
819: if (context.containsKey("enabled")) {
820: userLoginToUpdate.set("enabled", context.get("enabled"),
821: true);
822: }
823: if (context.containsKey("disabledDateTime")) {
824: userLoginToUpdate.set("disabledDateTime", context
825: .get("disabledDateTime"), true);
826: }
827: if (context.containsKey("successiveFailedLogins")) {
828: userLoginToUpdate.set("successiveFailedLogins", context
829: .get("successiveFailedLogins"), true);
830: }
831:
832: // if was disabled and we are enabling it, clear disabledDateTime
833: if (!wasEnabled && "Y".equals(context.get("enabled"))) {
834: userLoginToUpdate.set("disabledDateTime", null);
835: }
836:
837: // if was enabled and we are disabling it, and no disabledDateTime was passed, set it to now
838: if (wasEnabled && "N".equals(context.get("enabled"))
839: && context.get("disabledDateTime") == null) {
840: userLoginToUpdate.set("disabledDateTime", UtilDateTime
841: .nowTimestamp());
842: }
843:
844: try {
845: userLoginToUpdate.store();
846: } catch (GenericEntityException e) {
847: return ServiceUtil
848: .returnError("Could not change password (write failure): "
849: + e.getMessage());
850: }
851:
852: result.put(ModelService.RESPONSE_MESSAGE,
853: ModelService.RESPOND_SUCCESS);
854: return result;
855: }
856:
857: public static void checkNewPassword(GenericValue userLogin,
858: String currentPassword, String newPassword,
859: String newPasswordVerify, String passwordHint,
860: List errorMessageList, boolean ignoreCurrentPassword) {
861: boolean useEncryption = "true".equals(UtilProperties
862: .getPropertyValue("security.properties",
863: "password.encrypt"));
864:
865: if (!ignoreCurrentPassword) {
866: String realPassword = currentPassword;
867:
868: if (useEncryption && currentPassword != null) {
869: realPassword = HashEncrypt.getHash(currentPassword);
870: }
871: // if the password.accept.encrypted.and.plain property in security is set to true allow plain or encrypted passwords
872: boolean passwordMatches = currentPassword != null
873: && (realPassword.equals(userLogin
874: .getString("currentPassword")) || ("true"
875: .equals(UtilProperties
876: .getPropertyValue(
877: "security.properties",
878: "password.accept.encrypted.and.plain")) && currentPassword
879: .equals(userLogin
880: .getString("currentPassword"))));
881:
882: if ((currentPassword == null)
883: || (userLogin != null && currentPassword != null && !passwordMatches)) {
884: errorMessageList
885: .add("Old Password was not correct, please re-enter.");
886: }
887: }
888:
889: if (!UtilValidate.isNotEmpty(newPassword)
890: || !UtilValidate.isNotEmpty(newPasswordVerify)) {
891: errorMessageList
892: .add("Password or verify password missing.");
893: } else if (!newPassword.equals(newPasswordVerify)) {
894: errorMessageList
895: .add("Password did not match verify password");
896: }
897:
898: int minPasswordLength = 0;
899:
900: try {
901: minPasswordLength = Integer.parseInt(UtilProperties
902: .getPropertyValue("security.properties",
903: "password.length.min", "0"));
904: } catch (NumberFormatException nfe) {
905: minPasswordLength = 0;
906: }
907:
908: if (newPassword != null) {
909: if (!(newPassword.length() >= minPasswordLength)) {
910: errorMessageList.add("Password must be at least "
911: + minPasswordLength + " characters long");
912: }
913: if (userLogin != null
914: && newPassword.equalsIgnoreCase(userLogin
915: .getString("userLoginId"))) {
916: errorMessageList
917: .add("Password may not equal the Username");
918: }
919: if (UtilValidate.isNotEmpty(passwordHint)
920: && (passwordHint.toUpperCase().indexOf(
921: newPassword.toUpperCase()) >= 0)) {
922: errorMessageList
923: .add("Password hint may not contain the password");
924: }
925: }
926: }
927: }
|