usergrid-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mdun...@apache.org
Subject [3/3] usergrid git commit: add password complexity check before submitting during reset password flow
Date Fri, 28 Jul 2017 22:11:44 GMT
add password complexity check before submitting during reset password flow


Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/ceba1fa4
Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/ceba1fa4
Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/ceba1fa4

Branch: refs/heads/hotfix-20170728
Commit: ceba1fa44455a6c8f962c5e7badd615a382dddae
Parents: c0c489e
Author: Mike Dunker <mdunker@google.com>
Authored: Fri Jul 28 15:09:09 2017 -0700
Committer: Mike Dunker <mdunker@google.com>
Committed: Fri Jul 28 15:09:09 2017 -0700

----------------------------------------------------------------------
 .../rest/applications/users/UserResource.java   |   8 +
 .../rest/management/users/UserResource.java     |   9 ++
 .../usergrid/management/ManagementService.java  |  10 +-
 .../cassandra/ManagementServiceImpl.java        |  14 ++
 .../usergrid/security/PasswordPolicy.java       |  53 +++++++
 .../usergrid/security/PasswordPolicyFig.java    |  79 ++++++++++
 .../usergrid/security/PasswordPolicyImpl.java   | 156 +++++++++++++++++++
 .../services/guice/ServiceModuleImpl.java       |   7 +
 8 files changed, 331 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/ceba1fa4/stack/rest/src/main/java/org/apache/usergrid/rest/applications/users/UserResource.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/applications/users/UserResource.java
b/stack/rest/src/main/java/org/apache/usergrid/rest/applications/users/UserResource.java
index 5435f7e..f0dbc14 100644
--- a/stack/rest/src/main/java/org/apache/usergrid/rest/applications/users/UserResource.java
+++ b/stack/rest/src/main/java/org/apache/usergrid/rest/applications/users/UserResource.java
@@ -17,6 +17,7 @@
 package org.apache.usergrid.rest.applications.users;
 
 
+import java.util.Collection;
 import java.util.Map;
 import java.util.UUID;
 
@@ -465,6 +466,13 @@ public class UserResource extends ServiceResource {
             if ( ( password1 != null ) || ( password2 != null ) ) {
                 if ( management.checkPasswordResetTokenForAppUser( getApplicationId(), getUserUuid(),
token ) ) {
                     if ( ( password1 != null ) && password1.equals( password2 ) )
{
+                        // validate password
+                        Collection<String> violations = management.passwordPolicyCheck(password1,
false);
+                        if (violations.size() > 0) {
+                            // password not valid
+                            errorMsg = management.getPasswordDescription(false);
+                            return handleViewable( "resetpw_set_form", this, getOrganizationName()
);
+                        }
                         management.setAppUserPassword( getApplicationId(), getUser().getUuid(),
password1 );
                         management.revokeAccessTokenForAppUser( token );
                         return handleViewable( "resetpw_set_success", this, getOrganizationName()
);

http://git-wip-us.apache.org/repos/asf/usergrid/blob/ceba1fa4/stack/rest/src/main/java/org/apache/usergrid/rest/management/users/UserResource.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/management/users/UserResource.java
b/stack/rest/src/main/java/org/apache/usergrid/rest/management/users/UserResource.java
index 95f607b..cac5f2b 100644
--- a/stack/rest/src/main/java/org/apache/usergrid/rest/management/users/UserResource.java
+++ b/stack/rest/src/main/java/org/apache/usergrid/rest/management/users/UserResource.java
@@ -43,6 +43,7 @@ import javax.ws.rs.*;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.UriInfo;
+import java.util.Collection;
 import java.util.Map;
 import java.util.UUID;
 
@@ -297,6 +298,14 @@ public class UserResource extends AbstractContextResource {
             if ( ( password1 != null ) || ( password2 != null ) ) {
                 if ( management.checkPasswordResetTokenForAdminUser( user.getUuid(), tokenInfo
) ) {
                     if ( ( password1 != null ) && password1.equals( password2 ) )
{
+                        // validate password
+                        Collection<String> violations = management.passwordPolicyCheck(password1,
true);
+                        if (violations.size() > 0) {
+                            // password not valid
+                            errorMsg = management.getPasswordDescription(true);
+                            return handleViewable( "resetpw_set_form", this, organizationId
);
+                        }
+
                         management.setAdminUserPassword( user.getUuid(), password1 );
                         management.revokeAccessTokenForAdminUser( user.getUuid(), token );
                         loginEndpoint = properties.getProperty("usergrid.viewable.loginEndpoint");

http://git-wip-us.apache.org/repos/asf/usergrid/blob/ceba1fa4/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java
b/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java
index 2b88b07..df42d6a 100644
--- a/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java
+++ b/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java
@@ -17,11 +17,7 @@
 package org.apache.usergrid.management;
 
 
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.UUID;
+import java.util.*;
 
 import org.apache.usergrid.persistence.CredentialsInfo;
 import org.apache.usergrid.persistence.Entity;
@@ -372,6 +368,10 @@ public interface ManagementService {
 
 	Observable<Id> deleteAllEntities(final UUID applicationId,final int limit);
 
+	Collection<String> passwordPolicyCheck(String password, boolean isAdminUser);
+
+	String getPasswordDescription(boolean isAdminUser);
+
 
     // DO NOT REMOVE BELOW METHODS, THEY ARE HERE TO ALLOW EXTERNAL CLASSES TO OVERRIDE AND
HOOK INTO POST PROCESSING
     void createOrganizationPostProcessing( final OrganizationInfo orgInfo,

http://git-wip-us.apache.org/repos/asf/usergrid/blob/ceba1fa4/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
b/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
index 876cd5b..2d60441 100644
--- a/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
+++ b/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
@@ -54,6 +54,7 @@ import org.apache.usergrid.persistence.model.entity.Id;
 import org.apache.usergrid.persistence.model.entity.SimpleId;
 import org.apache.usergrid.security.AuthPrincipalInfo;
 import org.apache.usergrid.security.AuthPrincipalType;
+import org.apache.usergrid.security.PasswordPolicy;
 import org.apache.usergrid.security.crypto.EncryptionService;
 import org.apache.usergrid.security.oauth.AccessInfo;
 import org.apache.usergrid.security.oauth.ClientCredentialsInfo;
@@ -172,6 +173,8 @@ public class ManagementServiceImpl implements ManagementService {
 
     protected LocalShiroCache localShiroCache;
 
+    protected PasswordPolicy passwordPolicy;
+
 
     private LoadingCache<UUID, OrganizationConfig> orgConfigByAppCache = CacheBuilder.newBuilder().maximumSize(
1000 )
         .expireAfterWrite( Long.valueOf( System.getProperty(ORG_CONFIG_CACHE_PROP, "30000")
) , TimeUnit.MILLISECONDS)
@@ -215,6 +218,7 @@ public class ManagementServiceImpl implements ManagementService {
         this.service = injector.getInstance(ApplicationService.class);
         this.localShiroCache = injector.getInstance(LocalShiroCache.class);
 
+        this.passwordPolicy = injector.getInstance(PasswordPolicy.class);
     }
 
     @Autowired
@@ -3497,6 +3501,16 @@ public class ManagementServiceImpl implements ManagementService {
     }
 
     @Override
+    public Collection<String> passwordPolicyCheck(String password, boolean isAdminUser)
{
+        return passwordPolicy.policyCheck(password, isAdminUser);
+    }
+
+    @Override
+    public String getPasswordDescription(boolean isAdminUser) {
+        return passwordPolicy.getDescription(isAdminUser);
+    }
+
+    @Override
     public void createOrganizationPostProcessing( final OrganizationInfo orgInfo,
                                                   final Map<String,String> properties
){
         // do nothing, this is a hook for any classes extending the ManagementServiceInterface

http://git-wip-us.apache.org/repos/asf/usergrid/blob/ceba1fa4/stack/services/src/main/java/org/apache/usergrid/security/PasswordPolicy.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/security/PasswordPolicy.java
b/stack/services/src/main/java/org/apache/usergrid/security/PasswordPolicy.java
new file mode 100644
index 0000000..cc29b20
--- /dev/null
+++ b/stack/services/src/main/java/org/apache/usergrid/security/PasswordPolicy.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.usergrid.security;
+
+
+import java.util.Collection;
+
+
+/**
+ * Interface to password policy.
+ */
+public interface PasswordPolicy {
+
+    String ERROR_POLICY_VIOLIATION    = "error_password_policy_violation";
+
+    String ERROR_UPPERCASE_POLICY     = "error_uppercase_policy";
+
+    String ERROR_DIGITS_POLICY        = "error_digits_policy";
+
+    String ERROR_SPECIAL_CHARS_POLICY = "error_special_chars_policy";
+
+    String ERROR_LENGTH_POLICY        = "error_length_policy";
+
+
+    /**
+     * Check to see if password conforms to policy.
+     *
+     * @param password Password to check.
+     * @return Collection of error strings, one for each policy violated or empty if password
conforms.
+     */
+    Collection<String> policyCheck( String password, boolean isAdminUser );
+
+
+    /**
+     * Get description of password policy for error messages.
+     */
+    String getDescription( boolean isAdminUser );
+}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/ceba1fa4/stack/services/src/main/java/org/apache/usergrid/security/PasswordPolicyFig.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/security/PasswordPolicyFig.java
b/stack/services/src/main/java/org/apache/usergrid/security/PasswordPolicyFig.java
new file mode 100644
index 0000000..e93f8e4
--- /dev/null
+++ b/stack/services/src/main/java/org/apache/usergrid/security/PasswordPolicyFig.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.usergrid.security;
+
+import org.safehaus.guicyfig.Default;
+import org.safehaus.guicyfig.FigSingleton;
+import org.safehaus.guicyfig.GuicyFig;
+import org.safehaus.guicyfig.Key;
+
+
+@FigSingleton
+public interface PasswordPolicyFig extends GuicyFig {
+
+    String ALLOWED_SPECIAL_CHARS       = "usergrid.password-policy.allowed-special-chars";
+
+    String MIN_UPPERCASE_ADMIN         = "usergrid.password-policy.min-uppercase-admin";
+    String MIN_UPPERCASE               = "usergrid.password-policy.min-uppercase";
+
+    String MIN_DIGITS_ADMIN            = "usergrid.password-policy.min-digits-admin";
+    String MIN_DIGITS                  = "usergrid.password-policy.min-digits";
+
+    String MIN_SPECIAL_CHARS_ADMIN     = "usergrid.password-policy.min-special-chars-admin";
+    String MIN_SPECIAL_CHARS           = "usergrid.password-policy.min-special-chars";
+
+    String MIN_LENGTH_ADMIN            = "usergrid.password-policy.min-length-admin";
+    String MIN_LENGTH                  = "usergrid.password-policy.min-length";
+
+
+    @Key(MIN_UPPERCASE_ADMIN)
+    @Default("0")
+    int getMinUppercaseAdmin();
+
+    @Key(MIN_UPPERCASE)
+    @Default("0")
+    int getMinUppercase();
+
+    @Key(MIN_DIGITS_ADMIN)
+    @Default("0")
+    int getMinDigitsAdmin();
+
+    @Key(MIN_DIGITS)
+    @Default("0")
+    int getMinDigits();
+
+    @Key(MIN_SPECIAL_CHARS_ADMIN)
+    @Default("0")
+    int getMinSpecialCharsAdmin();
+
+    @Key(MIN_SPECIAL_CHARS)
+    @Default("0")
+    int getMinSpecialChars();
+
+    @Key(MIN_LENGTH_ADMIN)
+    @Default("4")
+    int getMinLengthAdmin();
+
+    @Key(MIN_LENGTH)
+    @Default("4")
+    int getMinLength();
+
+    @Key(ALLOWED_SPECIAL_CHARS)
+    @Default("`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?")
+    String getAllowedSpecialChars();
+}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/ceba1fa4/stack/services/src/main/java/org/apache/usergrid/security/PasswordPolicyImpl.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/security/PasswordPolicyImpl.java
b/stack/services/src/main/java/org/apache/usergrid/security/PasswordPolicyImpl.java
new file mode 100644
index 0000000..500592a
--- /dev/null
+++ b/stack/services/src/main/java/org/apache/usergrid/security/PasswordPolicyImpl.java
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.usergrid.security;
+
+import com.google.inject.Inject;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+
+public class PasswordPolicyImpl implements PasswordPolicy {
+
+    private final PasswordPolicyFig passwordPolicyFig;
+
+
+    @Inject
+    PasswordPolicyImpl( PasswordPolicyFig passwordPolicyFig ) {
+        this.passwordPolicyFig = passwordPolicyFig;
+    }
+
+
+    @Override
+    public String getDescription( boolean isAdminUser ) {
+
+        final int minLength;
+        final int minUppercase;
+        final int minDigits;
+        final int minSpecialChars;
+
+        if ( isAdminUser ) {
+            minLength       = passwordPolicyFig.getMinLengthAdmin();
+            minUppercase    = passwordPolicyFig.getMinUppercaseAdmin();
+            minDigits       = passwordPolicyFig.getMinDigitsAdmin();
+            minSpecialChars = passwordPolicyFig.getMinSpecialCharsAdmin();
+        } else {
+            minLength       = passwordPolicyFig.getMinLength();
+            minUppercase    = passwordPolicyFig.getMinUppercase();
+            minDigits       = passwordPolicyFig.getMinDigits();
+            minSpecialChars = passwordPolicyFig.getMinSpecialChars();
+        }
+
+        StringBuilder sb = new StringBuilder();
+        sb.append( "Password must be at least " ).append( minLength ).append(" characters.
");
+        if ( minUppercase > 0 ) {
+            sb.append( "Must include " ).append( minUppercase ).append(" uppercase characters.
");
+        }
+        if ( minDigits > 0 ) {
+            sb.append( "Must include " ).append( minDigits ).append(" numbers. ");
+        }
+        if ( minSpecialChars > 0 ) {
+            sb.append( "Must include " ).append( minUppercase ).append(" special characters.
");
+        }
+        return sb.toString();
+    }
+
+
+    @Override
+    public Collection<String> policyCheck( String password, boolean isAdminUser ) {
+
+        final int minLength;
+        final int minUppercase;
+        final int minDigits;
+        final int minSpecialChars;
+
+        if ( isAdminUser ) {
+            minLength       = passwordPolicyFig.getMinLengthAdmin();
+            minUppercase    = passwordPolicyFig.getMinUppercaseAdmin();
+            minDigits       = passwordPolicyFig.getMinDigitsAdmin();
+            minSpecialChars = passwordPolicyFig.getMinSpecialCharsAdmin();
+        } else {
+            minLength       = passwordPolicyFig.getMinLength();
+            minUppercase    = passwordPolicyFig.getMinUppercase();
+            minDigits       = passwordPolicyFig.getMinDigits();
+            minSpecialChars = passwordPolicyFig.getMinSpecialChars();
+        }
+
+        return policyCheck( password, minLength, minUppercase, minDigits, minSpecialChars
);
+    }
+
+
+    public Collection<String> policyCheck(
+        String password, int minLength, int minUppercase, int minDigits, int minSpecialChars
) {
+
+
+        List<String> violations = new ArrayList<>(3);
+
+        // check length
+        if ( password == null || password.length() < minLength ) {
+            violations.add( PasswordPolicy.ERROR_LENGTH_POLICY
+                + ": must be at least " + minLength + " characters" );
+        }
+
+        // count upper case
+        if ( minUppercase > 0 ) {
+            int upperCaseCount = 0;
+            for (char c : password.toCharArray()) {
+                if (StringUtils.isAllUpperCase( String.valueOf( c ) )) {
+                    upperCaseCount++;
+                }
+            }
+            if (upperCaseCount < minUppercase) {
+                violations.add( PasswordPolicy.ERROR_UPPERCASE_POLICY
+                    + ": requires " + minUppercase + " uppercase characters" );
+            }
+        }
+
+        // count digits case
+        if ( minDigits > 0 ) {
+            int digitCount = 0;
+            for (char c : password.toCharArray()) {
+                if (StringUtils.isNumeric( String.valueOf( c ) )) {
+                    digitCount++;
+                }
+            }
+            if (digitCount < minDigits) {
+                violations.add( PasswordPolicy.ERROR_DIGITS_POLICY
+                    + ": requires " + minDigits + " digits" );
+            }
+        }
+
+        // count special characters
+        if ( minSpecialChars > 0 ) {
+            int specialCharCount = 0;
+            for (char c : password.toCharArray()) {
+                if (passwordPolicyFig.getAllowedSpecialChars().contains( String.valueOf(
c ) )) {
+                    specialCharCount++;
+                }
+            }
+            if (specialCharCount < minSpecialChars) {
+                violations.add( PasswordPolicy.ERROR_SPECIAL_CHARS_POLICY
+                    + ": requires " + minSpecialChars + " special characters" );
+            }
+        }
+
+        return violations;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/ceba1fa4/stack/services/src/main/java/org/apache/usergrid/services/guice/ServiceModuleImpl.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/services/guice/ServiceModuleImpl.java
b/stack/services/src/main/java/org/apache/usergrid/services/guice/ServiceModuleImpl.java
index 58b301a..9e5485b 100644
--- a/stack/services/src/main/java/org/apache/usergrid/services/guice/ServiceModuleImpl.java
+++ b/stack/services/src/main/java/org/apache/usergrid/services/guice/ServiceModuleImpl.java
@@ -31,8 +31,12 @@ import org.apache.usergrid.persistence.cache.impl.CacheFactoryImpl;
 import org.apache.usergrid.persistence.cache.impl.ScopedCacheSerialization;
 import org.apache.usergrid.persistence.cache.impl.ScopedCacheSerializationImpl;
 import org.apache.usergrid.persistence.core.migration.data.MigrationPlugin;
+import org.apache.usergrid.security.PasswordPolicy;
+import org.apache.usergrid.security.PasswordPolicyFig;
+import org.apache.usergrid.security.PasswordPolicyImpl;
 import org.apache.usergrid.security.shiro.UsergridAuthenticationInfo;
 import org.apache.usergrid.security.shiro.UsergridAuthorizationInfo;
+import org.safehaus.guicyfig.GuicyFigModule;
 
 
 // <bean id="notificationsQueueListener" class="org.apache.usergrid.services.notifications.QueueListener"
@@ -70,5 +74,8 @@ public class ServiceModuleImpl extends AbstractModule implements ServiceModule
{
         bind(    new TypeLiteral<ScopedCacheSerialization<String, UsergridAuthenticationInfo>>()
{})
             .to( new TypeLiteral<ScopedCacheSerializationImpl<String, UsergridAuthenticationInfo>>()
{});
 
+        bind( PasswordPolicy.class ).to( PasswordPolicyImpl.class );
+
+        install( new GuicyFigModule( PasswordPolicyFig.class ) );
     }
 }


Mime
View raw message