You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by ja...@apache.org on 2007/09/07 06:58:36 UTC

svn commit: r573458 - in /ofbiz/trunk: applications/securityext/config/ framework/common/src/org/ofbiz/common/login/ framework/security/config/ framework/security/entitydef/

Author: jaz
Date: Thu Sep  6 21:58:35 2007
New Revision: 573458

URL: http://svn.apache.org/viewvc?rev=573458&view=rev
Log:
implementation (from Anil Patel) to support restricting changed passwords to not allow the use of a previous password (the length of tracking is configurable in security.properties)

Modified:
    ofbiz/trunk/applications/securityext/config/SecurityextUiLabels.properties
    ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LoginServices.java
    ofbiz/trunk/framework/security/config/security.properties
    ofbiz/trunk/framework/security/entitydef/entitygroup.xml
    ofbiz/trunk/framework/security/entitydef/entitymodel.xml

Modified: ofbiz/trunk/applications/securityext/config/SecurityextUiLabels.properties
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/securityext/config/SecurityextUiLabels.properties?rev=573458&r1=573457&r2=573458&view=diff
==============================================================================
--- ofbiz/trunk/applications/securityext/config/SecurityextUiLabels.properties (original)
+++ ofbiz/trunk/applications/securityext/config/SecurityextUiLabels.properties Thu Sep  6 21:58:35 2007
@@ -56,6 +56,7 @@
 loginevents.password_hint_is=The Password Hint is: ${passwordHint}.
 # ${errorMessage} = Error Description
 loginevents.error_accessing_password=Error accessing password: ${errorMessage}.
+loginevents.error_accessing_password_change_history=Error accessing password change history: ${errorMessage}.
 loginevents.user_with_the_username_not_found=A user with the username "${userLoginId}" was not found, please re-enter.
 loginevents.no_primary_email_address_set_contact_customer_service=No Primary Email Address has been set, please contact customer service.
 loginevents.problems_with_configuration_contact_customer_service=Problems with configuration; please contact customer service.
@@ -98,6 +99,7 @@
 loginservices.password_or_verify_missing=Password or verify password missing.
 loginservices.password_did_not_match_verify_password=Password did not match verify password.
 loginservices.password_must_be_least_characters_long=Password must be at least ${minPasswordLength} characters long.
+loginservices.password_must_be_different_from_last_passwords=Password cannot be one of your last ${passwordChangeHistoryLimit} passwords.
 loginservices.password_may_not_equal_username=Password may not equal the Username.
 loginservices.password_hint_may_not_contain_password=Password hint may not contain the password.
 

Modified: ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LoginServices.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LoginServices.java?rev=573458&r1=573457&r2=573458&view=diff
==============================================================================
--- ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LoginServices.java (original)
+++ ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LoginServices.java Thu Sep  6 21:58:35 2007
@@ -28,6 +28,8 @@
 
 import javax.transaction.Transaction;
 
+import javolution.util.FastList;
+
 import org.ofbiz.base.crypto.HashCrypt;
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.UtilDateTime;
@@ -37,10 +39,15 @@
 import org.ofbiz.entity.GenericDelegator;
 import org.ofbiz.entity.GenericEntityException;
 import org.ofbiz.entity.GenericValue;
+import org.ofbiz.entity.condition.EntityConditionList;
+import org.ofbiz.entity.condition.EntityExpr;
+import org.ofbiz.entity.condition.EntityOperator;
 import org.ofbiz.entity.model.ModelEntity;
 import org.ofbiz.entity.serialize.XmlSerializer;
 import org.ofbiz.entity.transaction.GenericTransactionException;
 import org.ofbiz.entity.transaction.TransactionUtil;
+import org.ofbiz.entity.util.EntityFindOptions;
+import org.ofbiz.entity.util.EntityListIterator;
 import org.ofbiz.security.Security;
 import org.ofbiz.service.DispatchContext;
 import org.ofbiz.service.ModelService;
@@ -340,7 +347,47 @@
         }
         return result;
     }
-
+    
+    private static void createUserLoginPasswordHistory(GenericDelegator delegator,String userLoginId, String currentPassword) throws GenericEntityException{
+        int passwordChangeHistoryLimit = 0;
+        try {
+            passwordChangeHistoryLimit = Integer.parseInt(UtilProperties.getPropertyValue("security.properties", "password.change.history.limit", "0"));
+        } catch (NumberFormatException nfe) {
+            //No valid value is found so don't bother to save any password history
+            passwordChangeHistoryLimit = 0;
+        }
+        if(passwordChangeHistoryLimit == 0 || passwordChangeHistoryLimit < 0){
+            // Not saving password history, so return from here.
+            return;
+        }
+        List exprs = FastList.newInstance();
+        EntityFindOptions efo = new EntityFindOptions();
+        efo.setResultSetType(EntityFindOptions.TYPE_SCROLL_INSENSITIVE);
+        exprs.add(new EntityExpr("userLoginId", EntityOperator.EQUALS, userLoginId));
+        List orderBy = UtilMisc.toList("-fromDate");
+        EntityListIterator eli = delegator.findListIteratorByCondition("UserLoginPasswordHistory", new EntityConditionList(exprs, EntityOperator.AND),null, null,  orderBy,efo);
+        Timestamp nowTimestamp = UtilDateTime.nowTimestamp();
+        GenericValue pwdHist;
+        if((pwdHist = (GenericValue) eli.next()) !=null){
+            // updating password so set end date on previous password in history
+            pwdHist.set("thruDate", nowTimestamp);
+            pwdHist.store();
+            // check if we have hit the limit on number of password changes to be saved. If we did then delete the oldest password from history.
+            eli.last();
+            int rowIndex = eli.currentIndex();
+            if(rowIndex==passwordChangeHistoryLimit){
+                eli.afterLast();
+                pwdHist = (GenericValue) eli.previous();
+                pwdHist.remove();
+            }
+        }
+        // save this password in history         
+        GenericValue userLoginPwdHistToCreate = delegator.makeValue("UserLoginPasswordHistory", UtilMisc.toMap("userLoginId", userLoginId,"fromDate", nowTimestamp));
+        boolean useEncryption = "true".equals(UtilProperties.getPropertyValue("security.properties", "password.encrypt"));
+        userLoginPwdHistToCreate.set("currentPassword", useEncryption ? getPasswordHash(currentPassword) : currentPassword);
+        userLoginPwdHistToCreate.create();
+    }
+    
     /** Creates a UserLogin
      *@param ctx The DispatchContext that this service is operating in
      *@param context Map containing the input parameters
@@ -421,6 +468,7 @@
 
         try {
             userLoginToCreate.create();
+            createUserLoginPasswordHistory(delegator,userLoginId, currentPassword);
         } catch (GenericEntityException e) {
             Debug.logWarning(e, "", module);
             Map messageMap = UtilMisc.toMap("errorMessage", e.getMessage());
@@ -493,7 +541,6 @@
         }
 
         List errorMessageList = new LinkedList();
-
         if (newPassword != null && newPassword.length() > 0) {
             checkNewPassword(userLoginToUpdate, currentPassword, newPassword, newPasswordVerify,
                 passwordHint, errorMessageList, adminUser, locale);
@@ -509,6 +556,7 @@
 
         try {
             userLoginToUpdate.store();
+            createUserLoginPasswordHistory(delegator,userLoginId, newPassword);
         } catch (GenericEntityException e) {
             Map messageMap = UtilMisc.toMap("errorMessage", e.getMessage());
             errMsg = UtilProperties.getMessage(resource,"loginservices.could_not_change_password_write_failure", messageMap, locale);
@@ -732,6 +780,38 @@
                 errorMessageList.add(errMsg);
             }
 
+        }
+
+        int passwordChangeHistoryLimit = 0;
+        try {
+            passwordChangeHistoryLimit = Integer.parseInt(UtilProperties.getPropertyValue("security.properties", "password.change.history.limit", "0"));
+        } catch (NumberFormatException nfe) {
+            //No valid value is found so don't bother to save any password history
+            passwordChangeHistoryLimit = 0;
+        }
+        Debug.logInfo(" checkNewPassword passwordChangeHistoryLimitpasswordChangeHistoryLimitpasswordChangeHistoryLimit" + passwordChangeHistoryLimit, module);
+        if(passwordChangeHistoryLimit > 0 ){
+            Debug.logInfo(" checkNewPassword Checking of user is tyring to use old password " + passwordChangeHistoryLimit, module);
+            GenericDelegator delegator = userLogin.getDelegator();
+            String newPasswordHash = newPassword;
+            if (useEncryption) {
+                newPasswordHash = LoginServices.getPasswordHash(newPassword);
+            }                
+            try {
+                List pwdHistList = delegator.findByAnd("UserLoginPasswordHistory", UtilMisc.toMap("userLoginId",userLogin.getString("userLoginId"),"currentPassword",newPasswordHash));
+                Debug.logInfo(" checkNewPassword pwdHistListpwdHistList " + pwdHistList.size(), module);
+                if(pwdHistList.size() >0){
+                    Map messageMap = UtilMisc.toMap("passwordChangeHistoryLimit", passwordChangeHistoryLimit);
+                    errMsg = UtilProperties.getMessage(resource,"loginservices.password_must_be_different_from_last_passwords", messageMap, locale);
+                    errorMessageList.add(errMsg);
+                    Debug.logInfo(" checkNewPassword errorMessageListerrorMessageList " + pwdHistList.size(), module);
+                }
+            } catch (GenericEntityException e) {
+                Debug.logWarning(e, "", module);
+                Map messageMap = UtilMisc.toMap("errorMessage", e.getMessage());
+                errMsg = UtilProperties.getMessage(resource,"loginevents.error_accessing_password_change_history", messageMap, locale);
+            }
+           
         }
 
         if (!UtilValidate.isNotEmpty(newPassword) || !UtilValidate.isNotEmpty(newPasswordVerify)) {

Modified: ofbiz/trunk/framework/security/config/security.properties
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/security/config/security.properties?rev=573458&r1=573457&r2=573458&view=diff
==============================================================================
--- ofbiz/trunk/framework/security/config/security.properties (original)
+++ ofbiz/trunk/framework/security/config/security.properties Thu Sep  6 21:58:35 2007
@@ -29,6 +29,11 @@
 # -- disable the account after this many logins --
 max.failed.logins=3
 
+# -- number of password change to be saved in UserLoginPasswordHistory. 
+# -- passwords saved in history of userLoginId will not be allowed to be reused.
+# -- 0 to not save history at all
+password.change.history.limit=0
+
 # -- disable the account for this many minutes (if 0, then indefinate) --
 login.disable.minutes=5
 

Modified: ofbiz/trunk/framework/security/entitydef/entitygroup.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/security/entitydef/entitygroup.xml?rev=573458&r1=573457&r2=573458&view=diff
==============================================================================
--- ofbiz/trunk/framework/security/entitydef/entitygroup.xml (original)
+++ ofbiz/trunk/framework/security/entitydef/entitygroup.xml Thu Sep  6 21:58:35 2007
@@ -32,6 +32,7 @@
   <!-- ========================================================= -->
     
     <entity-group group="org.ofbiz" entity="UserLogin" />
+    <entity-group group="org.ofbiz" entity="UserLoginPasswordHistory" />
     <entity-group group="org.ofbiz" entity="UserLoginHistory" />
     <entity-group group="org.ofbiz" entity="UserLoginSession" />
 

Modified: ofbiz/trunk/framework/security/entitydef/entitymodel.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/security/entitydef/entitymodel.xml?rev=573458&r1=573457&r2=573458&view=diff
==============================================================================
--- ofbiz/trunk/framework/security/entitydef/entitymodel.xml (original)
+++ ofbiz/trunk/framework/security/entitydef/entitymodel.xml Thu Sep  6 21:58:35 2007
@@ -77,6 +77,20 @@
       <field name="successiveFailedLogins" type="numeric"></field>
       <prim-key field="userLoginId"/>
     </entity>
+    <entity entity-name="UserLoginPasswordHistory"
+            package-name="org.ofbiz.security.login"
+            never-cache="true"
+            title="User Login Password History Entity">
+      <field name="userLoginId" type="id-vlong-ne"></field>
+      <field name="fromDate" type="date-time"></field>
+      <field name="thruDate" type="date-time"></field>
+      <field name="currentPassword" type="short-varchar"></field>
+      <prim-key field="userLoginId"/>
+      <prim-key field="fromDate"/>
+      <relation type="one" fk-name="USER_LPH_USER" rel-entity-name="UserLogin">
+        <key-map field-name="userLoginId"/>
+      </relation>
+    </entity>
     <entity entity-name="UserLoginHistory"
             package-name="org.ofbiz.security.login"
             never-cache="true"