You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by sn...@apache.org on 2016/10/24 13:06:59 UTC
[74/83] [abbrv] usergrid git commit: Configurable Password Policy and
5 supporting JUnit tests.
Configurable Password Policy and 5 supporting JUnit tests.
Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/a30e1a56
Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/a30e1a56
Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/a30e1a56
Branch: refs/heads/asf-site
Commit: a30e1a564e74b033601db60d37960fca46b34fe7
Parents: c65f903
Author: Dave Johnson <sn...@apache.org>
Authored: Wed Oct 19 13:42:34 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Wed Oct 19 14:05:17 2016 -0400
----------------------------------------------------------------------
.../exceptions/AbstractExceptionMapper.java | 2 +-
.../PasswordPolicyViolationExceptionMapper.java | 48 ++++++
.../collection/users/PermissionsResourceIT.java | 4 +-
.../collection/users/UserResourceIT.java | 38 ++++-
.../usergrid/rest/management/AdminUsersIT.java | 51 ++++++
.../rest/management/ManagementResourceIT.java | 4 +-
.../rest/management/RegistrationIT.java | 6 +-
.../cassandra/ManagementServiceImpl.java | 73 +++++++--
.../usergrid/security/PasswordPolicy.java | 53 ++++++
.../usergrid/security/PasswordPolicyFig.java | 79 +++++++++
.../usergrid/security/PasswordPolicyImpl.java | 156 ++++++++++++++++++
.../PasswordPolicyViolationException.java | 46 ++++++
.../services/guice/ServiceModuleImpl.java | 8 +
.../usergrid/security/PasswordPolicyTest.java | 47 ++++++
.../security/PasswordPolicyTestFig.java | 161 +++++++++++++++++++
15 files changed, 750 insertions(+), 26 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/usergrid/blob/a30e1a56/stack/rest/src/main/java/org/apache/usergrid/rest/exceptions/AbstractExceptionMapper.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/exceptions/AbstractExceptionMapper.java b/stack/rest/src/main/java/org/apache/usergrid/rest/exceptions/AbstractExceptionMapper.java
index 19d35fd..4a4b8b0 100644
--- a/stack/rest/src/main/java/org/apache/usergrid/rest/exceptions/AbstractExceptionMapper.java
+++ b/stack/rest/src/main/java/org/apache/usergrid/rest/exceptions/AbstractExceptionMapper.java
@@ -102,7 +102,7 @@ public abstract class AbstractExceptionMapper<E extends java.lang.Throwable> imp
}
- private Response toResponse( int status, String jsonResponse ) {
+ protected Response toResponse( int status, String jsonResponse ) {
if ( status >= 500 ) {
// only log real errors as errors
logger.error( "Server Error ({}):\n{}", status, jsonResponse );
http://git-wip-us.apache.org/repos/asf/usergrid/blob/a30e1a56/stack/rest/src/main/java/org/apache/usergrid/rest/exceptions/PasswordPolicyViolationExceptionMapper.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/exceptions/PasswordPolicyViolationExceptionMapper.java b/stack/rest/src/main/java/org/apache/usergrid/rest/exceptions/PasswordPolicyViolationExceptionMapper.java
new file mode 100644
index 0000000..fcd09e3
--- /dev/null
+++ b/stack/rest/src/main/java/org/apache/usergrid/rest/exceptions/PasswordPolicyViolationExceptionMapper.java
@@ -0,0 +1,48 @@
+/*
+ * 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.rest.exceptions;
+
+
+import org.apache.usergrid.rest.ApiResponse;
+import org.apache.usergrid.services.exceptions.PasswordPolicyViolationException;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.Provider;
+
+import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
+import static org.apache.usergrid.utils.JsonUtils.mapToJsonString;
+
+
+/** <p> Mapper for OAuthProblemException. </p> */
+@Provider
+public class PasswordPolicyViolationExceptionMapper extends AbstractExceptionMapper<PasswordPolicyViolationException> {
+
+ @Override
+ public Response toResponse( PasswordPolicyViolationException e ) {
+
+ ApiResponse apiResponse = new ApiResponse();
+ apiResponse.setError( e.getMessage() );
+
+ StringBuilder sb = new StringBuilder();
+ for ( String violation : e.getViolations() ) {
+ sb.append( violation ).append(" ");
+ }
+ apiResponse.setErrorDescription( sb.toString() );
+
+ return toResponse( SC_BAD_REQUEST, mapToJsonString(apiResponse) );
+ }
+}
http://git-wip-us.apache.org/repos/asf/usergrid/blob/a30e1a56/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/PermissionsResourceIT.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/PermissionsResourceIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/PermissionsResourceIT.java
index 5380e00..aff952b 100644
--- a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/PermissionsResourceIT.java
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/PermissionsResourceIT.java
@@ -638,12 +638,12 @@ public class PermissionsResourceIT extends AbstractRestIT {
// cannot create app user named me
try {
- app().collection( "users" ).post( new User( "me", "it's me", "me@example.com", "me!" ) );
+ app().collection( "users" ).post( new User( "me", "it's me", "me@example.com", "me!me!" ) );
fail("Must not be able to create app user named me");
} catch ( BadRequestException expected ) {}
// cannot use update to rename app user to me
- Entity user = app().collection( "users" ).post( new User( "dave", "Sneaky Me", "me@example.com", "me!" ) );
+ Entity user = app().collection( "users" ).post( new User( "dave", "Sneaky Me", "me@example.com", "me!me!" ) );
try {
app().collection( "users" ).entity( user ).put( new Entity().chainPut( "username", "me" ));
fail("Must not be able to update app user to name me");
http://git-wip-us.apache.org/repos/asf/usergrid/blob/a30e1a56/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/UserResourceIT.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/UserResourceIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/UserResourceIT.java
index d36d0a1..c9dc0d8 100644
--- a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/UserResourceIT.java
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/collection/users/UserResourceIT.java
@@ -47,6 +47,7 @@ import java.io.IOException;
import javax.ws.rs.core.MediaType;
+import static org.apache.usergrid.security.PasswordPolicy.ERROR_POLICY_VIOLIATION;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -776,6 +777,7 @@ public class UserResourceIT extends AbstractRestIT {
}
+
@Test
public void test_PUT_password_ok() {
Entity entity = usersResource.post(new User("edanuff", "edanuff", "edanuff@email.com", "sesame"));
@@ -798,7 +800,7 @@ public class UserResourceIT extends AbstractRestIT {
@Test
public void setUserPasswordAsAdmin() throws IOException {
usersResource.post(new User("edanuff", "edanuff", "edanuff@email.com", "sesame"));
- String newPassword = "foo";
+ String newPassword = "foofoo";
refreshIndex();
// change the password as admin. The old password isn't required
@@ -816,8 +818,8 @@ public class UserResourceIT extends AbstractRestIT {
public void passwordMismatchErrorUser() {
usersResource.post(new User("edanuff", "edanuff", "edanuff@email.com", "sesame"));
- String origPassword = "foo";
- String newPassword = "bar";
+ String origPassword = "foofoo";
+ String newPassword = "barbar";
ChangePasswordEntity data = new ChangePasswordEntity(origPassword, newPassword);
@@ -833,6 +835,36 @@ public class UserResourceIT extends AbstractRestIT {
@Test
+ public void createAppUserWithInvalidPassword() {
+
+ try {
+ Entity entity = usersResource.post(new User("edanuff", "edanuff", "edanuff@email.com", "foo"));
+ fail("Invalid password should have caused error");
+
+ } catch( ClientErrorException uie ) {
+ errorParse( 400, ERROR_POLICY_VIOLIATION, uie );
+ }
+ }
+
+
+ @Test
+ public void testChangePassordToInvalidValue() {
+
+ Entity entity = usersResource.post(new User("edanuff", "edanuff", "edanuff@email.com", "sesame"));
+ refreshIndex();
+
+ try {
+ usersResource.entity(entity).collection("password").post(new ChangePasswordEntity("sesame", "abc"));
+ fail("Invalid password should have caused error");
+
+ } catch( ClientErrorException uie ) {
+ errorParse( 400, ERROR_POLICY_VIOLIATION, uie );
+ }
+
+ }
+
+
+ @Test
public void addRemoveRole() throws IOException {
String roleName = "rolename";
http://git-wip-us.apache.org/repos/asf/usergrid/blob/a30e1a56/stack/rest/src/test/java/org/apache/usergrid/rest/management/AdminUsersIT.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/management/AdminUsersIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/management/AdminUsersIT.java
index a8bd834..f80f131 100644
--- a/stack/rest/src/test/java/org/apache/usergrid/rest/management/AdminUsersIT.java
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/management/AdminUsersIT.java
@@ -19,6 +19,7 @@ package org.apache.usergrid.rest.management;
import com.sun.jersey.api.client.UniformInterfaceException;
import net.jcip.annotations.NotThreadSafe;
+import org.apache.commons.lang.RandomStringUtils;
import org.apache.usergrid.management.MockImapClient;
import org.apache.usergrid.persistence.core.util.StringUtils;
import org.apache.usergrid.persistence.index.utils.UUIDUtils;
@@ -42,6 +43,7 @@ import java.io.IOException;
import java.util.*;
import static org.apache.usergrid.management.AccountCreationProps.*;
+import static org.apache.usergrid.security.PasswordPolicy.ERROR_POLICY_VIOLIATION;
import static org.junit.Assert.*;
@@ -92,6 +94,55 @@ public class AdminUsersIT extends AbstractRestIT {
/**
+ * Test that creating user with password that violates policy results in informative error message.
+ */
+ @Test
+ public void createUserWithInvalidPassword() throws IOException {
+
+ String rando = RandomStringUtils.randomAlphanumeric(10);
+ Form userForm = new Form();
+ userForm.param( "username", "user_" + rando );
+ userForm.param( "name", rando);
+ userForm.param( "email", "user_" + rando + "@example.com" );
+ userForm.param( "password", "abc" );
+
+ try {
+ management().users().post( User.class, userForm );
+ fail("Invalid password should have caused error");
+
+ } catch( ClientErrorException uie ) {
+ errorParse( 400, ERROR_POLICY_VIOLIATION, uie );
+ }
+
+ }
+
+
+ /**
+ * Test that setting a password that violates policy results in informative error message.
+ */
+ @Test
+ public void resetPasswordWithInvalidNewPassword() throws IOException {
+
+ String username = clientSetup.getUsername();
+ String password = clientSetup.getPassword();
+
+ Map<String, Object> passwordPayload = new HashMap<String, Object>();
+
+ // Default password policy is lenient, only requires length of 4
+ passwordPayload.put( "newpassword", "abc" );
+ passwordPayload.put( "oldpassword", password );
+
+ try {
+ management.users().user( username ).password().post( Entity.class, passwordPayload );
+ fail("Invalid password should have caused error");
+
+ } catch( ClientErrorException uie ) {
+ errorParse( 400, ERROR_POLICY_VIOLIATION, uie );
+ }
+ }
+
+
+ /**
* Check that we cannot change the password by using an older password
*/
@Test
http://git-wip-us.apache.org/repos/asf/usergrid/blob/a30e1a56/stack/rest/src/test/java/org/apache/usergrid/rest/management/ManagementResourceIT.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/management/ManagementResourceIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/management/ManagementResourceIT.java
index 1a3eb1d..635368e 100644
--- a/stack/rest/src/test/java/org/apache/usergrid/rest/management/ManagementResourceIT.java
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/management/ManagementResourceIT.java
@@ -81,7 +81,7 @@ public class ManagementResourceIT extends AbstractRestIT {
.users()
.post( ApiResponse.class, new User( "test" + uuid, "test" + uuid, "test" + uuid + "@email.com", "test" ) );
Map<String, Object> data = new HashMap<>();
- data.put( "newpassword", "foo" );
+ data.put( "newpassword", "foofoo" );
data.put( "oldpassword", "test" );
management.users()
.user( "test" + uuid )
@@ -90,7 +90,7 @@ public class ManagementResourceIT extends AbstractRestIT {
Token token = management.token().post(Token.class, new Token( "test"+uuid, "foo" ) );
management.token().setToken( token );
data.clear();
- data.put( "oldpassword", "foo" );
+ data.put( "oldpassword", "foofoo" );
data.put( "newpassword", "test" );
management.users().user("test"+uuid).password().post(Entity.class, data);
}
http://git-wip-us.apache.org/repos/asf/usergrid/blob/a30e1a56/stack/rest/src/test/java/org/apache/usergrid/rest/management/RegistrationIT.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/management/RegistrationIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/management/RegistrationIT.java
index 885710d..8404632 100644
--- a/stack/rest/src/test/java/org/apache/usergrid/rest/management/RegistrationIT.java
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/management/RegistrationIT.java
@@ -145,6 +145,7 @@ public class RegistrationIT extends AbstractRestIT {
/**
* Test checking that we should be able to add a admin with no password attached to them.
+ *
* @throws Exception
*/
@@ -163,7 +164,10 @@ public class RegistrationIT extends AbstractRestIT {
// this should send resetpwd link in email to newly added org admin user(that did not exist
///in usergrid) and "User Invited To Organization" email
String adminToken = getAdminToken().getAccessToken();
- Entity node = postAddAdminToOrg(this.clientSetup.getOrganizationName(), this.clientSetup.getUsername()+"@servertest.com", "");
+ Entity node = postAddAdminToOrg(
+ this.clientSetup.getOrganizationName(),
+ this.clientSetup.getUsername()+"@servertest.com",
+ "changeme");
UUID userId = node.getUuid();
refreshIndex();
http://git-wip-us.apache.org/repos/asf/usergrid/blob/a30e1a56/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 03377a3..35fdd30 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;
@@ -70,6 +71,7 @@ import org.apache.usergrid.security.tokens.TokenInfo;
import org.apache.usergrid.security.tokens.TokenService;
import org.apache.usergrid.security.tokens.exceptions.TokenException;
import org.apache.usergrid.services.*;
+import org.apache.usergrid.services.exceptions.PasswordPolicyViolationException;
import org.apache.usergrid.utils.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -172,6 +174,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 +219,8 @@ public class ManagementServiceImpl implements ManagementService {
this.service = injector.getInstance(ApplicationService.class);
this.localShiroCache = injector.getInstance(LocalShiroCache.class);
+ this.passwordPolicy = injector.getInstance( PasswordPolicy.class );
+
}
@Autowired
@@ -929,7 +935,8 @@ public class ManagementServiceImpl implements ManagementService {
@Override
- public UserInfo createAdminFromPrexistingPassword( UUID organizationId, User user, CredentialsInfo ci ) throws Exception {
+ public UserInfo createAdminFromPrexistingPassword( UUID organizationId, User user, CredentialsInfo ci )
+ throws Exception {
return doCreateAdmin( organizationId, user, ci,
// we can't actually set the mongo password. We never have the plain text in
@@ -941,6 +948,12 @@ public class ManagementServiceImpl implements ManagementService {
@Override
public UserInfo createAdminFrom( UUID organizationId, User user, String password ) throws Exception {
+
+ Collection<String> policyVioliations = passwordPolicy.policyCheck( password, false );
+ if ( !policyVioliations.isEmpty() ) {
+ throw new PasswordPolicyViolationException( passwordPolicy.getDescription( true ), policyVioliations );
+ }
+
return doCreateAdmin(organizationId, user,
encryptionService.defaultEncryptedCredentials(password, user.getUuid(), smf.getManagementAppId()),
encryptionService.plainTextCredentials(mongoPassword(user.getUsername(), password), user.getUuid(),
@@ -949,20 +962,23 @@ public class ManagementServiceImpl implements ManagementService {
@Override
- public UserInfo createAdminUser( UUID organizationId, String username, String name, String email, String password, boolean activated,
+ public UserInfo createAdminUser( UUID organizationId, String username, String name, String email,
+ String password, boolean activated,
boolean disabled ) throws Exception {
return createAdminUser(organizationId, username, name, email, password, activated, disabled, null);
}
@Override
- public UserInfo createAdminUser( UUID organizationId, String username, String name, String email, String password, boolean activated,
- boolean disabled, Map<String, Object> userProperties ) throws Exception {
+ public UserInfo createAdminUser( UUID organizationId, String username, String name, String email, String password,
+ boolean activated, boolean disabled, Map<String, Object> userProperties )
+ throws Exception {
if ( !validateAdminInfo(username, name, email, password) ) {
return null;
}
- return createAdminUserInternal( organizationId, username, name, email, password, activated, disabled, userProperties );
+ return createAdminUserInternal(
+ organizationId, username, name, email, password, activated, disabled, userProperties );
}
@@ -976,25 +992,32 @@ public class ManagementServiceImpl implements ManagementService {
EntityManager em = emf.getEntityManager( smf.getManagementAppId() );
- if ( !( tokens.isExternalSSOProviderEnabled() && SubjectUtils.isServiceAdmin()) && !em.isPropertyValueUniqueForEntity( "user", "username", username ) ) {
+ if ( !( tokens.isExternalSSOProviderEnabled() && SubjectUtils.isServiceAdmin())
+ && !em.isPropertyValueUniqueForEntity( "user", "username", username ) ) {
throw new DuplicateUniquePropertyExistsException( "user", "username", username );
}
- if ( !(tokens.isExternalSSOProviderEnabled()&& SubjectUtils.isServiceAdmin()) && !em.isPropertyValueUniqueForEntity( "user", "email", email ) ) {
+ if ( !(tokens.isExternalSSOProviderEnabled()&& SubjectUtils.isServiceAdmin())
+ && !em.isPropertyValueUniqueForEntity( "user", "email", email ) ) {
throw new DuplicateUniquePropertyExistsException( "user", "email", email );
}
return true;
}
- protected UserInfo createAdminUserInternal( UUID organizationId, String username, String name, String email, String password,
- boolean activated, boolean disabled, Map<String, Object> userProperties )
+ protected UserInfo createAdminUserInternal( UUID organizationId, String username, String name, String email,
+ String password, boolean activated, boolean disabled,
+ Map<String, Object> userProperties )
throws Exception {
+
+
logger.info( "createAdminUserInternal: {}", username );
- if ( isBlank( password ) ) {
- password = encodeBase64URLSafeString( bytes( UUID.randomUUID() ) );
+ Collection<String> policyVioliations = passwordPolicy.policyCheck( password, true );
+ if ( !policyVioliations.isEmpty() ) {
+ throw new PasswordPolicyViolationException( passwordPolicy.getDescription( true ), policyVioliations );
}
+
if ( username == null ) {
username = email;
}
@@ -1265,6 +1288,11 @@ public class ManagementServiceImpl implements ManagementService {
return;
}
+ Collection<String> policyVioliations = passwordPolicy.policyCheck( newPassword, true );
+ if ( !policyVioliations.isEmpty() ) {
+ throw new PasswordPolicyViolationException( passwordPolicy.getDescription( true ), policyVioliations );
+ }
+
EntityManager em = emf.getEntityManager( smf.getManagementAppId() );
User user = em.get( userId, User.class );
@@ -1646,7 +1674,8 @@ public class ManagementServiceImpl implements ManagementService {
@Override
- public Map<String, Object> getAdminUserOrganizationData(UserInfo user, boolean includeApps, boolean includeOrgUsers) throws Exception {
+ public Map<String, Object> getAdminUserOrganizationData(UserInfo user, boolean includeApps, boolean includeOrgUsers)
+ throws Exception {
Map<String, Object> json = new HashMap<>();
@@ -2654,8 +2683,8 @@ public class ManagementServiceImpl implements ManagementService {
String token = getConfirmationTokenForAdminUser(user.getUuid(), 0, organizationId);
OrganizationConfig orgConfig = organizationId != null ?
getOrganizationConfigByUuid(organizationId) : getOrganizationConfigForUserInfo(user);
- String confirmation_url = orgConfig.getFullUrl(WorkflowUrl.ADMIN_CONFIRMATION_URL, user.getUuid().toString()) +
- "?token=" + token;
+ String confirmation_url = orgConfig.getFullUrl(WorkflowUrl.ADMIN_CONFIRMATION_URL,
+ user.getUuid().toString()) + "?token=" + token;
sendAdminUserEmail(user, "User Account Confirmation: " + user.getEmail(),
emailMsg(hashMap("confirm_email", user.getEmail()).map("confirmation_url", confirmation_url),
PROPERTIES_EMAIL_ADMIN_CONFIRMATION));
@@ -2779,7 +2808,8 @@ public class ManagementServiceImpl implements ManagementService {
@Override
- public boolean checkPasswordResetTokenForAppUser( UUID applicationId, UUID userId, String token ) throws Exception {
+ public boolean checkPasswordResetTokenForAppUser( UUID applicationId, UUID userId, String token )
+ throws Exception {
AuthPrincipalInfo principal = null;
try {
principal = getPrincipalFromAccessToken( token, TOKEN_TYPE_PASSWORD_RESET, APPLICATION_USER );
@@ -3036,10 +3066,16 @@ public class ManagementServiceImpl implements ManagementService {
@Override
public void setAppUserPassword( UUID applicationId, UUID userId, String newPassword ) throws Exception {
+
if ( ( userId == null ) || ( newPassword == null ) ) {
return;
}
+ Collection<String> policyVioliations = passwordPolicy.policyCheck( newPassword, false );
+ if ( !policyVioliations.isEmpty() ) {
+ throw new PasswordPolicyViolationException( passwordPolicy.getDescription( false ), policyVioliations );
+ }
+
EntityManager em = emf.getEntityManager( applicationId );
User user = em.get(userId, User.class);
@@ -3051,6 +3087,7 @@ public class ManagementServiceImpl implements ManagementService {
@Override
public void setAppUserPassword( UUID applicationId, UUID userId, String oldPassword, String newPassword )
throws Exception {
+
if ( ( userId == null ) ) {
throw new IllegalArgumentException( "userId is required" );
}
@@ -3097,7 +3134,8 @@ public class ManagementServiceImpl implements ManagementService {
final CredentialsInfo ci = readUserPasswordCredentials( applicationId, userId, User.ENTITY_TYPE );
if ( ci == null ) {
- throw new EntityNotFoundException("Could not find credentials for user with id " + userId + " in application" + applicationId );
+ throw new EntityNotFoundException("Could not find credentials for user with id " + userId
+ + " in application" + applicationId );
}
return ci;
@@ -3242,7 +3280,8 @@ public class ManagementServiceImpl implements ManagementService {
/** read the user password credential's info */
- protected CredentialsInfo readUserPasswordCredentials( UUID appId, UUID ownerId, String ownerType ) throws Exception {
+ protected CredentialsInfo readUserPasswordCredentials( UUID appId, UUID ownerId, String ownerType )
+ throws Exception {
return readCreds( appId, ownerId, ownerType, USER_PASSWORD );
}
http://git-wip-us.apache.org/repos/asf/usergrid/blob/a30e1a56/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/a30e1a56/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..41cda7c
--- /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-uppercase-admin";
+ String MIN_DIGITS = "usergrid.password-policy.min-uppercase";
+
+ 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/a30e1a56/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/a30e1a56/stack/services/src/main/java/org/apache/usergrid/services/exceptions/PasswordPolicyViolationException.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/services/exceptions/PasswordPolicyViolationException.java b/stack/services/src/main/java/org/apache/usergrid/services/exceptions/PasswordPolicyViolationException.java
new file mode 100644
index 0000000..531e3fd
--- /dev/null
+++ b/stack/services/src/main/java/org/apache/usergrid/services/exceptions/PasswordPolicyViolationException.java
@@ -0,0 +1,46 @@
+/*
+ * 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.services.exceptions;
+
+
+import java.util.Collection;
+
+import static org.apache.usergrid.security.PasswordPolicy.ERROR_POLICY_VIOLIATION;
+
+
+public class PasswordPolicyViolationException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ private final Collection<String> violations;
+ private final String description;
+
+ public PasswordPolicyViolationException( String description, Collection<String> violations ) {
+ super( ERROR_POLICY_VIOLIATION );
+ this.violations = violations;
+ this.description = description;
+ }
+
+
+ public Collection<String> getViolations() {
+ return violations;
+ }
+
+
+ public String getDescription() {
+ return description;
+ }
+}
http://git-wip-us.apache.org/repos/asf/usergrid/blob/a30e1a56/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..c7f7d08 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
@@ -24,6 +24,7 @@ import com.google.inject.TypeLiteral;
import com.google.inject.multibindings.Multibinder;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.usergrid.corepersistence.ServiceModule;
+import org.apache.usergrid.corepersistence.index.CoreIndexFig;
import org.apache.usergrid.locking.guice.LockModule;
import org.apache.usergrid.management.AppInfoMigrationPlugin;
import org.apache.usergrid.persistence.cache.CacheFactory;
@@ -31,8 +32,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 +75,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 ) );
}
}
http://git-wip-us.apache.org/repos/asf/usergrid/blob/a30e1a56/stack/services/src/test/java/org/apache/usergrid/security/PasswordPolicyTest.java
----------------------------------------------------------------------
diff --git a/stack/services/src/test/java/org/apache/usergrid/security/PasswordPolicyTest.java b/stack/services/src/test/java/org/apache/usergrid/security/PasswordPolicyTest.java
new file mode 100644
index 0000000..1599b18
--- /dev/null
+++ b/stack/services/src/test/java/org/apache/usergrid/security/PasswordPolicyTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.apache.usergrid.ServiceITSetup;
+import org.apache.usergrid.ServiceITSetupImpl;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+
+public class PasswordPolicyTest {
+
+ @ClassRule
+ public static ServiceITSetup setup = new ServiceITSetupImpl();
+
+
+ @Test
+ public void testBasicOperation() {
+
+ PasswordPolicyImpl passwordPolicy =
+ (PasswordPolicyImpl)setup.getInjector().getInstance( PasswordPolicy.class );
+
+ Assert.assertEquals( 4, passwordPolicy.policyCheck( "secret", 12, 1, 1, 1 ).size() );
+ Assert.assertEquals( 3, passwordPolicy.policyCheck( "Secret", 12, 1, 1, 1 ).size() );
+ Assert.assertEquals( 2, passwordPolicy.policyCheck( "Secr3t", 12, 1, 1, 1 ).size() );
+ Assert.assertEquals( 1, passwordPolicy.policyCheck( "Secr3t!", 12, 1, 1, 1 ).size() );
+ Assert.assertEquals( 0, passwordPolicy.policyCheck( "Secr3t!longer", 12, 1, 1, 1 ).size() );
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/usergrid/blob/a30e1a56/stack/services/src/test/java/org/apache/usergrid/security/PasswordPolicyTestFig.java
----------------------------------------------------------------------
diff --git a/stack/services/src/test/java/org/apache/usergrid/security/PasswordPolicyTestFig.java b/stack/services/src/test/java/org/apache/usergrid/security/PasswordPolicyTestFig.java
new file mode 100644
index 0000000..27a74d0
--- /dev/null
+++ b/stack/services/src/test/java/org/apache/usergrid/security/PasswordPolicyTestFig.java
@@ -0,0 +1,161 @@
+/*
+ * 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.apache.usergrid.ServiceITSetup;
+import org.apache.usergrid.ServiceITSetupImpl;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.safehaus.guicyfig.Bypass;
+import org.safehaus.guicyfig.OptionState;
+import org.safehaus.guicyfig.Overrides;
+
+import java.beans.PropertyChangeListener;
+import java.util.Map;
+import java.util.Properties;
+
+
+public class PasswordPolicyTestFig implements PasswordPolicyFig {
+
+
+ @Override
+ public int getMinUppercaseAdmin() {
+ return 1;
+ }
+
+ @Override
+ public int getMinUppercase() {
+ return 1;
+ }
+
+ @Override
+ public int getMinDigitsAdmin() {
+ return 1;
+ }
+
+ @Override
+ public int getMinDigits() {
+ return 1;
+ }
+
+ @Override
+ public int getMinSpecialCharsAdmin() {
+ return 1;
+ }
+
+ @Override
+ public int getMinSpecialChars() {
+ return 1;
+ }
+
+ @Override
+ public int getMinLengthAdmin() {
+ return 1;
+ }
+
+ @Override
+ public int getMinLength() {
+ return 1;
+ }
+
+ @Override
+ public String getAllowedSpecialChars() {
+ return null;
+ }
+
+ @Override
+ public void addPropertyChangeListener(PropertyChangeListener listener) {
+
+ }
+
+ @Override
+ public void removePropertyChangeListener(PropertyChangeListener listener) {
+
+ }
+
+ @Override
+ public OptionState[] getOptions() {
+ return new OptionState[0];
+ }
+
+ @Override
+ public OptionState getOption(String key) {
+ return null;
+ }
+
+ @Override
+ public String getKeyByMethod(String methodName) {
+ return null;
+ }
+
+ @Override
+ public Object getValueByMethod(String methodName) {
+ return null;
+ }
+
+ @Override
+ public Properties filterOptions(Properties properties) {
+ return null;
+ }
+
+ @Override
+ public Map<String, Object> filterOptions(Map<String, Object> entries) {
+ return null;
+ }
+
+ @Override
+ public void override(String key, String override) {
+
+ }
+
+ @Override
+ public boolean setOverrides(Overrides overrides) {
+ return false;
+ }
+
+ @Override
+ public Overrides getOverrides() {
+ return null;
+ }
+
+ @Override
+ public void bypass(String key, String bypass) {
+
+ }
+
+ @Override
+ public boolean setBypass(Bypass bypass) {
+ return false;
+ }
+
+ @Override
+ public Bypass getBypass() {
+ return null;
+ }
+
+ @Override
+ public Class getFigInterface() {
+ return null;
+ }
+
+ @Override
+ public boolean isSingleton() {
+ return false;
+ }
+}