diff --git a/community/bolt/src/main/java/org/neo4j/bolt/security/auth/BasicAuthentication.java b/community/bolt/src/main/java/org/neo4j/bolt/security/auth/BasicAuthentication.java index 7e5d38df20fe0..665b2629a5cca 100644 --- a/community/bolt/src/main/java/org/neo4j/bolt/security/auth/BasicAuthentication.java +++ b/community/bolt/src/main/java/org/neo4j/bolt/security/auth/BasicAuthentication.java @@ -91,16 +91,18 @@ private AuthenticationResult update( Map authToken ) { try { + // We need to copy the new password here since it will be cleared by login() + byte[] newPassword = AuthToken.safeCastCredentials( NEW_CREDENTIALS, authToken ).clone(); + LoginContext loginContext = authManager.login( authToken ); switch ( loginContext.subject().getAuthenticationResult() ) { case SUCCESS: case PASSWORD_CHANGE_REQUIRED: - String newPassword = AuthToken.safeCast( NEW_CREDENTIALS, authToken ); String username = AuthToken.safeCast( PRINCIPAL, authToken ); userManagerSupplier.getUserManager( loginContext.subject(), false ) - .setUserPassword( username, newPassword, false ); + .setUserPassword( username, newPassword, false ); // NOTE: This will overwrite newPassword with zeroes loginContext.subject().setPasswordChangeNoLongerRequired(); break; default: diff --git a/community/bolt/src/test/java/org/neo4j/bolt/security/auth/BasicAuthenticationTest.java b/community/bolt/src/test/java/org/neo4j/bolt/security/auth/BasicAuthenticationTest.java index 4e12a06df0f8b..7d4fd76931075 100644 --- a/community/bolt/src/test/java/org/neo4j/bolt/security/auth/BasicAuthenticationTest.java +++ b/community/bolt/src/test/java/org/neo4j/bolt/security/auth/BasicAuthenticationTest.java @@ -36,6 +36,7 @@ import org.neo4j.server.security.auth.BasicAuthManager; import org.neo4j.server.security.auth.InMemoryUserRepository; import org.neo4j.server.security.auth.UserRepository; +import org.neo4j.string.UTF8; import org.neo4j.time.Clocks; import static java.util.Collections.singletonList; @@ -57,7 +58,7 @@ public void shouldNotDoAnythingOnSuccess() throws Exception { // When AuthenticationResult result = - authentication.authenticate( map( "scheme", "basic", "principal", "mike", "credentials", "secret2" ) ); + authentication.authenticate( map( "scheme", "basic", "principal", "mike", "credentials", UTF8.encode( "secret2" ) ) ); // Then assertThat( result.getLoginContext().subject().username(), equalTo( "mike" ) ); @@ -72,7 +73,7 @@ public void shouldThrowAndLogOnFailure() throws Exception exception.expectMessage( "The client is unauthorized due to authentication failure." ); // When - authentication.authenticate( map( "scheme", "basic", "principal", "bob", "credentials", "banana" ) ); + authentication.authenticate( map( "scheme", "basic", "principal", "bob", "credentials", UTF8.encode( "banana" ) ) ); } @Test @@ -80,7 +81,7 @@ public void shouldIndicateThatCredentialsExpired() throws Exception { // When AuthenticationResult result = - authentication.authenticate( map( "scheme", "basic", "principal", "bob", "credentials", "secret" ) ); + authentication.authenticate( map( "scheme", "basic", "principal", "bob", "credentials", UTF8.encode( "secret" ) ) ); // Then assertTrue( result.credentialsExpired() ); @@ -97,7 +98,7 @@ public void shouldFailWhenTooManyAttempts() throws Exception { try { - auth.authenticate( map( "scheme", "basic", "principal", "bob", "credentials", "gelato" ) ); + auth.authenticate( map( "scheme", "basic", "principal", "bob", "credentials", UTF8.encode( "gelato" ) ) ); } catch ( AuthenticationException e ) { @@ -111,7 +112,7 @@ public void shouldFailWhenTooManyAttempts() throws Exception exception.expectMessage( "The client has provided incorrect authentication details too many times in a row." ); //When - auth.authenticate( map( "scheme", "basic", "principal", "bob", "credentials", "gelato" ) ); + auth.authenticate( map( "scheme", "basic", "principal", "bob", "credentials", UTF8.encode( "gelato" ) ) ); } @Test @@ -119,10 +120,11 @@ public void shouldBeAbleToUpdateCredentials() throws Exception { // When authentication.authenticate( - map( "scheme", "basic", "principal", "mike", "credentials", "secret2", "new_credentials", "secret" ) ); + map( "scheme", "basic", "principal", "mike", "credentials", UTF8.encode( "secret2" ), + "new_credentials", UTF8.encode( "secret" ) ) ); // Then - authentication.authenticate( map( "scheme", "basic", "principal", "mike", "credentials", "secret" ) ); + authentication.authenticate( map( "scheme", "basic", "principal", "mike", "credentials", UTF8.encode( "secret" ) ) ); } @Test @@ -130,7 +132,7 @@ public void shouldBeAbleToUpdateExpiredCredentials() throws Exception { // When AuthenticationResult result = authentication.authenticate( - map( "scheme", "basic", "principal", "bob", "credentials", "secret", "new_credentials", "secret2" ) ); + map( "scheme", "basic", "principal", "bob", "credentials", UTF8.encode( "secret" ), "new_credentials", UTF8.encode( "secret2" ) ) ); // Then assertThat(result.credentialsExpired(), equalTo( false )); @@ -145,8 +147,8 @@ public void shouldNotBeAbleToUpdateCredentialsIfOldCredentialsAreInvalid() throw exception.expectMessage( "The client is unauthorized due to authentication failure." ); // When - authentication.authenticate( map( "scheme", "basic", "principal", "bob", "credentials", "gelato", - "new_credentials", "secret2" ) ); + authentication.authenticate( map( "scheme", "basic", "principal", "bob", "credentials", UTF8.encode( "gelato" ), + "new_credentials", UTF8.encode( "secret2" ) ) ); } @Test @@ -157,7 +159,7 @@ public void shouldThrowWithNoScheme() throws Exception exception.expect( hasStatus( Status.Security.Unauthorized ) ); // When - authentication.authenticate( map( "principal", "bob", "credentials", "secret" ) ); + authentication.authenticate( map( "principal", "bob", "credentials", UTF8.encode( "secret" ) ) ); } @Test @@ -182,7 +184,7 @@ public void shouldFailOnMalformedToken() throws Exception // When authentication - .authenticate( map( "scheme", "basic", "principal", singletonList( "bob" ), "credentials", "secret" ) ); + .authenticate( map( "scheme", "basic", "principal", singletonList( "bob" ), "credentials", UTF8.encode( "secret" ) ) ); } @Before @@ -200,8 +202,8 @@ private static Authentication createAuthentication( int maxFailedAttempts ) thro BasicAuthManager manager = new BasicAuthManager( users, policy, Clocks.systemClock(), users, config ); Authentication authentication = new BasicAuthentication( manager, manager ); - manager.newUser( "bob", "secret", true ); - manager.newUser( "mike", "secret2", false ); + manager.newUser( "bob", UTF8.encode( "secret" ), true ); + manager.newUser( "mike", UTF8.encode( "secret2" ), false ); return authentication; } diff --git a/community/community-it/community-it/src/test/java/org/neo4j/server/security/auth/AuthProceduresIT.java b/community/community-it/community-it/src/test/java/org/neo4j/server/security/auth/AuthProceduresIT.java index 334b3e61de332..3cb9757676401 100644 --- a/community/community-it/community-it/src/test/java/org/neo4j/server/security/auth/AuthProceduresIT.java +++ b/community/community-it/community-it/src/test/java/org/neo4j/server/security/auth/AuthProceduresIT.java @@ -46,6 +46,7 @@ import org.neo4j.kernel.api.exceptions.InvalidArgumentsException; import org.neo4j.kernel.api.security.exception.InvalidAuthTokenException; import org.neo4j.kernel.internal.GraphDatabaseAPI; +import org.neo4j.string.UTF8; import org.neo4j.test.TestGraphDatabaseBuilder; import org.neo4j.test.TestGraphDatabaseFactory; @@ -109,7 +110,7 @@ public void shouldNotChangeOwnPasswordIfNewPasswordInvalid() public void newUserShouldBeAbleToChangePassword() throws Throwable { // Given - authManager.newUser( "andres", "banana", true ); + authManager.newUser( "andres", UTF8.encode( "banana" ), true ); // Then assertEmpty( login("andres", "banana"), "CALL dbms.changePassword('abc')" ); @@ -119,7 +120,7 @@ public void newUserShouldBeAbleToChangePassword() throws Throwable public void newUserShouldNotBeAbleToCallOtherProcedures() throws Throwable { // Given - authManager.newUser( "andres", "banana", true ); + authManager.newUser( "andres", UTF8.encode( "banana" ), true ); LoginContext user = login("andres", "banana"); // Then @@ -200,7 +201,7 @@ public void shouldNotCreateExistingUser() @Test public void shouldDeleteUser() throws Exception { - authManager.newUser( "andres", "123", false ); + authManager.newUser( "andres", UTF8.encode( "123" ), false ); assertEmpty( admin, "CALL dbms.security.deleteUser('andres')" ); try { @@ -228,7 +229,7 @@ public void shouldNotDeleteNonExistentUser() @Test public void shouldListUsers() throws Exception { - authManager.newUser( "andres", "123", false ); + authManager.newUser( "andres", UTF8.encode( "123" ), false ); assertSuccess( admin, "CALL dbms.security.listUsers() YIELD username", r -> assertKeyIs( r, "username", "neo4j", "andres" ) ); } @@ -236,7 +237,7 @@ public void shouldListUsers() throws Exception @Test public void shouldReturnUsersWithFlags() throws Exception { - authManager.newUser( "andres", "123", false ); + authManager.newUser( "andres", UTF8.encode( "123" ), false ); Map expected = map( "neo4j", listOf( PWD_CHANGE ), "andres", listOf() @@ -251,7 +252,7 @@ public void shouldShowCurrentUser() throws Exception assertSuccess( admin, "CALL dbms.showCurrentUser()", r -> assertKeyIsMap( r, "username", "flags", map( "neo4j", listOf( PWD_CHANGE ) ) ) ); - authManager.newUser( "andres", "123", false ); + authManager.newUser( "andres", UTF8.encode( "123" ), false ); LoginContext andres = login( "andres", "123" ); assertSuccess( andres, "CALL dbms.showCurrentUser()", r -> assertKeyIsMap( r, "username", "flags", map( "andres", listOf() ) ) ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/security/AuthManager.java b/community/kernel/src/main/java/org/neo4j/kernel/api/security/AuthManager.java index d9a99cd860eec..4062946a44b71 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/security/AuthManager.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/security/AuthManager.java @@ -32,6 +32,9 @@ public interface AuthManager extends Lifecycle { /** * Log in using the provided authentication token + * + * NOTE: The authToken will be cleared of any credentials + * * @param authToken The authentication token to login with. Typically contains principals and credentials. * @return An AuthSubject representing the newly logged-in user * @throws InvalidAuthTokenException if the authentication token is malformed @@ -66,6 +69,7 @@ public void shutdown() @Override public LoginContext login( Map authToken ) { + AuthToken.clearCredentials( authToken ); return LoginContext.AUTH_DISABLED; } }; diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/security/AuthToken.java b/community/kernel/src/main/java/org/neo4j/kernel/api/security/AuthToken.java index dfd7bc00884fa..e434a0f5eb5c2 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/security/AuthToken.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/security/AuthToken.java @@ -21,10 +21,12 @@ import org.apache.commons.lang3.StringUtils; +import java.util.Arrays; import java.util.Collections; import java.util.Map; import org.neo4j.kernel.api.security.exception.InvalidAuthTokenException; +import org.neo4j.string.UTF8; import static java.lang.String.format; import static org.neo4j.helpers.collection.MapUtil.map; @@ -55,6 +57,21 @@ else if ( !(value instanceof String) ) return (String) value; } + static byte[] safeCastCredentials( String key, Map authToken ) throws InvalidAuthTokenException + { + Object value = authToken.get( key ); + if ( value == null ) + { + throw invalidToken( "missing key `" + key + "`" ); + } + else if ( !(value instanceof byte[]) ) + { + throw invalidToken( "the value associated with the key `" + key + "` must be a byte[] but was: " + + value.getClass().getSimpleName() ); + } + return (byte[]) value; + } + static Map safeCastMap( String key, Map authToken ) throws InvalidAuthTokenException { @@ -75,6 +92,21 @@ else if ( value instanceof Map ) } } + static void clearCredentials( Map authToken ) + { + Object credentials = authToken.get( CREDENTIALS ); + if ( credentials != null && credentials instanceof byte[] ) + { + Arrays.fill( (byte[]) credentials, (byte) 0 ); + } + + Object newCredentials = authToken.get( NEW_CREDENTIALS ); + if ( newCredentials != null && newCredentials instanceof byte[] ) + { + Arrays.fill( (byte[]) newCredentials, (byte) 0 ); + } + } + static InvalidAuthTokenException invalidToken( String explanation ) { if ( StringUtils.isNotEmpty( explanation ) && !explanation.matches( "^[,.:;].*" ) ) @@ -84,28 +116,54 @@ static InvalidAuthTokenException invalidToken( String explanation ) return new InvalidAuthTokenException( format( "Unsupported authentication token%s", explanation ) ); } - static Map newBasicAuthToken( String username, String password ) + static Map newBasicAuthToken( String username, byte[] password ) { return map( AuthToken.SCHEME_KEY, BASIC_SCHEME, AuthToken.PRINCIPAL, username, AuthToken.CREDENTIALS, password ); } - static Map newBasicAuthToken( String username, String password, String realm ) + static Map newBasicAuthToken( String username, byte[] password, String realm ) { return map( AuthToken.SCHEME_KEY, BASIC_SCHEME, AuthToken.PRINCIPAL, username, AuthToken.CREDENTIALS, password, AuthToken.REALM_KEY, realm ); } - static Map newCustomAuthToken( String principle, String credentials, String realm, String scheme ) + static Map newCustomAuthToken( String principle, byte[] credentials, String realm, String scheme ) { return map( AuthToken.SCHEME_KEY, scheme, AuthToken.PRINCIPAL, principle, AuthToken.CREDENTIALS, credentials, AuthToken.REALM_KEY, realm ); } - static Map newCustomAuthToken( String principle, String credentials, String realm, String scheme, + static Map newCustomAuthToken( String principle, byte[] credentials, String realm, String scheme, Map parameters ) { return map( AuthToken.SCHEME_KEY, scheme, AuthToken.PRINCIPAL, principle, AuthToken.CREDENTIALS, credentials, AuthToken.REALM_KEY, realm, AuthToken.PARAMETERS, parameters ); } + + // For testing purposes only + static Map newBasicAuthToken( String username, String password ) + { + return newBasicAuthToken( username, UTF8.encode( password ) ); + } + + // For testing purposes only + static Map newBasicAuthToken( String username, String password, String realm ) + { + return newBasicAuthToken( username, UTF8.encode( password ), realm ); + } + + // For testing purposes only + static Map newCustomAuthToken( String principle, String credentials, String realm, String scheme ) + { + return newCustomAuthToken( principle, UTF8.encode( credentials ), realm, scheme ); + } + + // For testing purposes only + static Map newCustomAuthToken( String principle, String credentials, String realm, String scheme, + Map parameters ) + { + return newCustomAuthToken( principle, UTF8.encode( credentials ), realm, scheme, parameters ); + } + } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/security/PasswordPolicy.java b/community/kernel/src/main/java/org/neo4j/kernel/api/security/PasswordPolicy.java index b3d0fcd8672ac..773bd201c931b 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/security/PasswordPolicy.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/security/PasswordPolicy.java @@ -24,5 +24,5 @@ public interface PasswordPolicy { // TODO: We may want to reintroduce AuthSubject here to be able to check against repeating last used passwords etc. - void validatePassword( String password ) throws InvalidArgumentsException; + void validatePassword( byte[] password ) throws InvalidArgumentsException; } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/security/UserManager.java b/community/kernel/src/main/java/org/neo4j/kernel/api/security/UserManager.java index 1da45cab757bc..916a287973398 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/security/UserManager.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/security/UserManager.java @@ -20,6 +20,7 @@ package org.neo4j.kernel.api.security; import java.io.IOException; +import java.util.Arrays; import java.util.Set; import org.neo4j.kernel.api.exceptions.InvalidArgumentsException; @@ -30,7 +31,10 @@ public interface UserManager String INITIAL_USER_NAME = "neo4j"; String INITIAL_PASSWORD = "neo4j"; - User newUser( String username, String initialPassword, boolean requirePasswordChange ) + /** + * NOTE: The initialPassword byte array will be cleared (overwritten with zeroes) + */ + User newUser( String username, byte[] initialPassword, boolean requirePasswordChange ) throws IOException, InvalidArgumentsException; boolean deleteUser( String username ) throws IOException, InvalidArgumentsException; @@ -39,7 +43,10 @@ User newUser( String username, String initialPassword, boolean requirePasswordCh User silentlyGetUser( String username ); - void setUserPassword( String username, String password, boolean requirePasswordChange ) + /** + * NOTE: The password byte array will be cleared (overwritten with zeroes) + */ + void setUserPassword( String username, byte[] password, boolean requirePasswordChange ) throws IOException, InvalidArgumentsException; Set getAllUsernames(); @@ -47,8 +54,9 @@ void setUserPassword( String username, String password, boolean requirePasswordC UserManager NO_AUTH = new UserManager() { @Override - public User newUser( String username, String initialPassword, boolean requirePasswordChange ) + public User newUser( String username, byte[] initialPassword, boolean requirePasswordChange ) { + Arrays.fill( initialPassword, (byte) 0 ); return null; } @@ -71,8 +79,9 @@ public User silentlyGetUser( String username ) } @Override - public void setUserPassword( String username, String password, boolean requirePasswordChange ) + public void setUserPassword( String username, byte[] password, boolean requirePasswordChange ) { + Arrays.fill( password, (byte) 0 ); } @Override diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/security/Credential.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/security/Credential.java index 59cdd9d48e629..5d669614b1b6f 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/security/Credential.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/security/Credential.java @@ -21,14 +21,23 @@ public interface Credential { - boolean matchesPassword( String password ); + boolean matchesPassword( byte[] password ); + + /** + * For testing purposes only! + * Use method that takes byte[] + */ + default boolean matchesPassword( String password ) + { + throw new UnsupportedOperationException( "Use `boolean matchesPassword( byte[] password )` instead" ); + } String serialize(); Credential INACCESSIBLE = new Credential() { @Override - public boolean matchesPassword( String password ) + public boolean matchesPassword( byte[] password ) { return false; } diff --git a/community/security/src/main/java/org/neo4j/commandline/admin/security/SetInitialPasswordCommand.java b/community/security/src/main/java/org/neo4j/commandline/admin/security/SetInitialPasswordCommand.java index b9b504df13d9a..9c1f4a1918da2 100644 --- a/community/security/src/main/java/org/neo4j/commandline/admin/security/SetInitialPasswordCommand.java +++ b/community/security/src/main/java/org/neo4j/commandline/admin/security/SetInitialPasswordCommand.java @@ -37,6 +37,7 @@ import org.neo4j.server.security.auth.CommunitySecurityModule; import org.neo4j.server.security.auth.FileUserRepository; import org.neo4j.server.security.auth.ListSnapshot; +import org.neo4j.string.UTF8; import static org.neo4j.kernel.api.security.UserManager.INITIAL_PASSWORD; import static org.neo4j.kernel.api.security.UserManager.INITIAL_USER_NAME; @@ -101,7 +102,7 @@ private void setPassword( String password ) throws Throwable new FileUserRepository( fileSystem, file, NullLogProvider.getInstance() ); userRepository.start(); userRepository.create( - new User.Builder( INITIAL_USER_NAME, LegacyCredential.forPassword( password ) ) + new User.Builder( INITIAL_USER_NAME, LegacyCredential.forPassword( UTF8.encode( password ) ) ) .withRequiredPasswordChange( false ) .build() ); diff --git a/community/security/src/main/java/org/neo4j/server/security/auth/AuthProcedures.java b/community/security/src/main/java/org/neo4j/server/security/auth/AuthProcedures.java index bc7f8db1f33d6..64c177343db91 100644 --- a/community/security/src/main/java/org/neo4j/server/security/auth/AuthProcedures.java +++ b/community/security/src/main/java/org/neo4j/server/security/auth/AuthProcedures.java @@ -35,6 +35,7 @@ import org.neo4j.procedure.Description; import org.neo4j.procedure.Name; import org.neo4j.procedure.Procedure; +import org.neo4j.string.UTF8; import static java.util.Collections.emptyList; import static org.neo4j.procedure.Mode.DBMS; @@ -56,8 +57,9 @@ public void createUser( @Name( value = "requirePasswordChange", defaultValue = "true" ) boolean requirePasswordChange ) throws InvalidArgumentsException, IOException { + // TODO: Deprecate this and create a new procedure that takes password as a byte[] securityContext.assertCredentialsNotExpired(); - userManager.newUser( username, password, requirePasswordChange ); + userManager.newUser( username, UTF8.encode( password ), requirePasswordChange ); } @Description( "Delete the specified user." ) @@ -77,6 +79,7 @@ public void deleteUser( @Name( "username" ) String username ) throws InvalidArgu @Procedure( name = "dbms.changePassword", mode = DBMS, deprecatedBy = "dbms.security.changePassword" ) public void changePasswordDeprecated( @Name( "password" ) String password ) throws InvalidArgumentsException, IOException { + // TODO: Deprecate this and create a new procedure that takes password as a byte[] changePassword( password ); } @@ -84,11 +87,12 @@ public void changePasswordDeprecated( @Name( "password" ) String password ) thro @Procedure( name = "dbms.security.changePassword", mode = DBMS ) public void changePassword( @Name( "password" ) String password ) throws InvalidArgumentsException, IOException { + // TODO: Deprecate this and create a new procedure that takes password as a byte[] if ( securityContext.subject() == AuthSubject.ANONYMOUS ) { throw new AuthorizationViolationException( "Anonymous cannot change password" ); } - userManager.setUserPassword( securityContext.subject().username(), password, false ); + userManager.setUserPassword( securityContext.subject().username(), UTF8.encode( password ), false ); securityContext.subject().setPasswordChangeNoLongerRequired(); } diff --git a/community/security/src/main/java/org/neo4j/server/security/auth/AuthenticationStrategy.java b/community/security/src/main/java/org/neo4j/server/security/auth/AuthenticationStrategy.java index ad4aaad4a2b9f..2d941f2ec1bc8 100644 --- a/community/security/src/main/java/org/neo4j/server/security/auth/AuthenticationStrategy.java +++ b/community/security/src/main/java/org/neo4j/server/security/auth/AuthenticationStrategy.java @@ -30,5 +30,5 @@ public interface AuthenticationStrategy /** * Verify a user by password */ - AuthenticationResult authenticate( User user, String password ); + AuthenticationResult authenticate( User user, byte[] password ); } diff --git a/community/security/src/main/java/org/neo4j/server/security/auth/BasicAuthManager.java b/community/security/src/main/java/org/neo4j/server/security/auth/BasicAuthManager.java index 952af6dfa427b..b4dd0dea87526 100644 --- a/community/security/src/main/java/org/neo4j/server/security/auth/BasicAuthManager.java +++ b/community/security/src/main/java/org/neo4j/server/security/auth/BasicAuthManager.java @@ -21,10 +21,10 @@ import java.io.IOException; import java.time.Clock; +import java.util.Arrays; import java.util.Map; import java.util.Set; -import org.neo4j.graphdb.security.AuthorizationViolationException; import org.neo4j.internal.kernel.api.security.AuthSubject; import org.neo4j.internal.kernel.api.security.AuthenticationResult; import org.neo4j.internal.kernel.api.security.LoginContext; @@ -38,6 +38,7 @@ import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.impl.security.User; import org.neo4j.server.security.auth.exception.ConcurrentModificationException; +import org.neo4j.string.UTF8; import static org.neo4j.kernel.api.security.AuthToken.invalidToken; @@ -87,7 +88,7 @@ public void start() throws Throwable if ( userRepository.numberOfUsers() == 0 ) { - User neo4j = newUser( INITIAL_USER_NAME, INITIAL_PASSWORD, true ); + User neo4j = newUser( INITIAL_USER_NAME, UTF8.encode( INITIAL_PASSWORD ), true ); if ( initialUserRepository.numberOfUsers() > 0 ) { User user = initialUserRepository.getUserByName( INITIAL_USER_NAME ); @@ -116,40 +117,55 @@ public void shutdown() throws Throwable @Override public LoginContext login( Map authToken ) throws InvalidAuthTokenException { - assertValidScheme( authToken ); + try + { + assertValidScheme( authToken ); - String username = AuthToken.safeCast( AuthToken.PRINCIPAL, authToken ); - String password = AuthToken.safeCast( AuthToken.CREDENTIALS, authToken ); + String username = AuthToken.safeCast( AuthToken.PRINCIPAL, authToken ); + byte[] password = AuthToken.safeCastCredentials( AuthToken.CREDENTIALS, authToken ); - User user = userRepository.getUserByName( username ); - AuthenticationResult result = AuthenticationResult.FAILURE; - if ( user != null ) - { - result = authStrategy.authenticate( user, password ); - if ( result == AuthenticationResult.SUCCESS && user.passwordChangeRequired() ) + User user = userRepository.getUserByName( username ); + AuthenticationResult result = AuthenticationResult.FAILURE; + if ( user != null ) { - result = AuthenticationResult.PASSWORD_CHANGE_REQUIRED; + result = authStrategy.authenticate( user, password ); + if ( result == AuthenticationResult.SUCCESS && user.passwordChangeRequired() ) + { + result = AuthenticationResult.PASSWORD_CHANGE_REQUIRED; + } } + return new BasicLoginContext( user, result ); + } + finally + { + AuthToken.clearCredentials( authToken ); } - return new BasicLoginContext( user, result ); } @Override - public User newUser( String username, String initialPassword, boolean requirePasswordChange ) + public User newUser( String username, byte[] initialPassword, boolean requirePasswordChange ) throws IOException, InvalidArgumentsException { - userRepository.assertValidUsername( username ); + try + { + userRepository.assertValidUsername( username ); - passwordPolicy.validatePassword( initialPassword ); + passwordPolicy.validatePassword( initialPassword ); - User user = new User.Builder() - .withName( username ) - .withCredentials( LegacyCredential.forPassword( initialPassword ) ) - .withRequiredPasswordChange( requirePasswordChange ) - .build(); - userRepository.create( user ); + User user = new User.Builder() + .withName( username ) + .withCredentials( LegacyCredential.forPassword( initialPassword ) ) + .withRequiredPasswordChange( requirePasswordChange ) + .build(); + userRepository.create( user ); - return user; + return user; + } + finally + { + // Clear password + Arrays.fill( initialPassword, (byte) 0 ); + } } @Override @@ -176,42 +192,37 @@ public User silentlyGetUser( String username ) return userRepository.getUserByName( username ); } - void setPassword( AuthSubject authSubject, String username, String password, boolean requirePasswordChange ) - throws IOException, InvalidArgumentsException - { - if ( !authSubject.hasUsername( username ) ) - { - throw new AuthorizationViolationException( "Invalid attempt to change the password for user " + username ); - } - - setUserPassword( username, password, requirePasswordChange ); - } - @Override - public void setUserPassword( String username, String password, boolean requirePasswordChange ) + public void setUserPassword( String username, byte[] password, boolean requirePasswordChange ) throws IOException, InvalidArgumentsException { - User existingUser = getUser( username ); + try + { + User existingUser = getUser( username ); - passwordPolicy.validatePassword( password ); + passwordPolicy.validatePassword( password ); - if ( existingUser.credentials().matchesPassword( password ) ) - { - throw new InvalidArgumentsException( "Old password and new password cannot be the same." ); - } + if ( existingUser.credentials().matchesPassword( password ) ) + { + throw new InvalidArgumentsException( "Old password and new password cannot be the same." ); + } - try - { - User updatedUser = existingUser.augment() - .withCredentials( LegacyCredential.forPassword( password ) ) - .withRequiredPasswordChange( requirePasswordChange ) - .build(); - userRepository.update( existingUser, updatedUser ); + try + { + User updatedUser = existingUser.augment().withCredentials( LegacyCredential.forPassword( password ) ).withRequiredPasswordChange( + requirePasswordChange ).build(); + userRepository.update( existingUser, updatedUser ); + } + catch ( ConcurrentModificationException e ) + { + // try again + setUserPassword( username, password, requirePasswordChange ); + } } - catch ( ConcurrentModificationException e ) + finally { - // try again - setUserPassword( username, password, requirePasswordChange ); + // Clear password + Arrays.fill( password, (byte) 0 ); } } diff --git a/community/security/src/main/java/org/neo4j/server/security/auth/BasicPasswordPolicy.java b/community/security/src/main/java/org/neo4j/server/security/auth/BasicPasswordPolicy.java index 2bc2b76ef4394..97515bc34f4cc 100644 --- a/community/security/src/main/java/org/neo4j/server/security/auth/BasicPasswordPolicy.java +++ b/community/security/src/main/java/org/neo4j/server/security/auth/BasicPasswordPolicy.java @@ -25,10 +25,10 @@ public class BasicPasswordPolicy implements PasswordPolicy { @Override - public void validatePassword( String password ) + public void validatePassword( byte[] password ) throws InvalidArgumentsException { - if ( password == null || password.isEmpty() ) + if ( password == null || password.length == 0 ) { throw new InvalidArgumentsException( "A password cannot be empty." ); } diff --git a/community/security/src/main/java/org/neo4j/server/security/auth/LegacyCredential.java b/community/security/src/main/java/org/neo4j/server/security/auth/LegacyCredential.java index 9c228a51bd607..2ef5ab1aceb4f 100644 --- a/community/security/src/main/java/org/neo4j/server/security/auth/LegacyCredential.java +++ b/community/security/src/main/java/org/neo4j/server/security/auth/LegacyCredential.java @@ -44,12 +44,18 @@ public class LegacyCredential implements Credential private final byte[] salt; private final byte[] passwordHash; - public static LegacyCredential forPassword( String password ) + public static LegacyCredential forPassword( byte[] password ) { byte[] salt = randomSalt(); return new LegacyCredential( salt, hash( salt, password ) ); } + // For testing purposes only! + public static LegacyCredential forPassword( String password ) + { + return forPassword( UTF8.encode( password ) ); + } + public LegacyCredential( byte[] salt, byte[] passwordHash ) { this.salt = salt; @@ -67,11 +73,18 @@ public byte[] passwordHash() } @Override - public boolean matchesPassword( String password ) + public boolean matchesPassword( byte[] password ) { return byteEquals( passwordHash, hash( salt, password ) ); } + // For testing purposes only! + @Override + public boolean matchesPassword( String password ) + { + return byteEquals( passwordHash, hash( salt, UTF8.encode( password ) ) ); + } + @Override public String serialize() { @@ -149,14 +162,13 @@ public String toString() '}'; } - private static byte[] hash( byte[] salt, String password ) + private static byte[] hash( byte[] salt, byte[] password ) { try { - byte[] passwordBytes = UTF8.encode( password ); MessageDigest m = MessageDigest.getInstance( DIGEST_ALGO ); m.update( salt, 0, salt.length ); - m.update( passwordBytes, 0, passwordBytes.length ); + m.update( password, 0, password.length ); return m.digest(); } catch ( NoSuchAlgorithmException e ) diff --git a/community/security/src/main/java/org/neo4j/server/security/auth/RateLimitedAuthenticationStrategy.java b/community/security/src/main/java/org/neo4j/server/security/auth/RateLimitedAuthenticationStrategy.java index 41bda489baa91..ceb8455c12008 100644 --- a/community/security/src/main/java/org/neo4j/server/security/auth/RateLimitedAuthenticationStrategy.java +++ b/community/security/src/main/java/org/neo4j/server/security/auth/RateLimitedAuthenticationStrategy.java @@ -80,7 +80,7 @@ public RateLimitedAuthenticationStrategy( Clock clock, Config config ) } @Override - public AuthenticationResult authenticate( User user, String password ) + public AuthenticationResult authenticate( User user, byte[] password ) { AuthenticationMetadata authMetadata = authMetadataFor( user.name() ); diff --git a/community/security/src/test/java/org/neo4j/server/security/auth/BasicAuthManagerTest.java b/community/security/src/test/java/org/neo4j/server/security/auth/BasicAuthManagerTest.java index 30404b25f8826..23c81a4d8362b 100644 --- a/community/security/src/test/java/org/neo4j/server/security/auth/BasicAuthManagerTest.java +++ b/community/security/src/test/java/org/neo4j/server/security/auth/BasicAuthManagerTest.java @@ -24,6 +24,8 @@ import org.junit.Before; import org.junit.Test; +import java.nio.charset.StandardCharsets; + import org.neo4j.internal.kernel.api.security.AuthenticationResult; import org.neo4j.internal.kernel.api.security.LoginContext; import org.neo4j.kernel.api.exceptions.InvalidArgumentsException; @@ -84,7 +86,7 @@ public void shouldFindAndAuthenticateUserSuccessfully() throws Throwable final User user = user1; // When - when( authStrategy.authenticate( user, "abc123" )).thenReturn( SUCCESS ); + when( authStrategy.authenticate( user, password( "abc123" ) ) ).thenReturn( SUCCESS ); // Then assertLoginGivesResult( "jake", "abc123", SUCCESS ); @@ -100,7 +102,7 @@ public void shouldFindAndAuthenticateUserAndReturnAuthStrategyResult() throws Th final User user = user1; // When - when( authStrategy.authenticate( user, "abc123" )).thenReturn( TOO_MANY_ATTEMPTS ); + when( authStrategy.authenticate( user, password( "abc123" ) ) ).thenReturn( TOO_MANY_ATTEMPTS ); // Then assertLoginGivesResult( "jake", "abc123", TOO_MANY_ATTEMPTS ); @@ -116,7 +118,7 @@ public void shouldFindAndAuthenticateUserAndReturnPasswordChangeIfRequired() thr final User user = user1; // When - when( authStrategy.authenticate( user, "abc123" )).thenReturn( SUCCESS ); + when( authStrategy.authenticate( user, password( "abc123" ) )).thenReturn( SUCCESS ); // Then assertLoginGivesResult( "jake", "abc123", PASSWORD_CHANGE_REQUIRED ); @@ -141,7 +143,7 @@ public void shouldCreateUser() throws Throwable manager.start(); // When - manager.newUser( "foo", "bar", true ); + manager.newUser( "foo", password( "bar" ), true ); // Then User user = users.getUserByName( "foo" ); @@ -155,7 +157,7 @@ public void shouldDeleteUser() throws Throwable { // Given manager.start(); - manager.newUser( "jake", "abc123", true ); + manager.newUser( "jake", password( "abc123" ), true ); // When manager.deleteUser( "jake" ); @@ -169,7 +171,7 @@ public void shouldFailToDeleteUnknownUser() throws Throwable { // Given manager.start(); - manager.newUser( "jake", "abc123", true ); + manager.newUser( "jake", password( "abc123" ), true ); try { @@ -195,10 +197,10 @@ public void shouldSetPassword() throws Throwable { // Given manager.start(); - manager.newUser( "jake", "abc123", true ); + manager.newUser( "jake", password( "abc123" ), true ); // When - manager.setUserPassword( "jake", "hello, world!", false ); + manager.setUserPassword( "jake", password( "hello, world!" ), false ); // Then User user = manager.getUser( "jake" ); @@ -215,7 +217,7 @@ public void shouldReturnNullWhenSettingPasswordForUnknownUser() throws Throwable // When try { - manager.setUserPassword( "unknown", "hello, world!", false ); + manager.setUserPassword( "unknown", password( "hello, world!" ), false ); fail( "exception expected" ); } catch ( InvalidArgumentsException e ) @@ -267,4 +269,9 @@ protected AuthManager authManager() { return manager; } + + public static byte[] password( String passwordString ) + { + return passwordString.getBytes( StandardCharsets.UTF_8 ); + } } diff --git a/community/security/src/test/java/org/neo4j/server/security/auth/RateLimitedAuthenticationStrategyTest.java b/community/security/src/test/java/org/neo4j/server/security/auth/RateLimitedAuthenticationStrategyTest.java index e62892903c799..67ae76902f512 100644 --- a/community/security/src/test/java/org/neo4j/server/security/auth/RateLimitedAuthenticationStrategyTest.java +++ b/community/security/src/test/java/org/neo4j/server/security/auth/RateLimitedAuthenticationStrategyTest.java @@ -36,6 +36,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.neo4j.graphdb.factory.GraphDatabaseSettings.auth_lock_time; +import static org.neo4j.server.security.auth.BasicAuthManagerTest.password; public class RateLimitedAuthenticationStrategyTest { @@ -48,7 +49,7 @@ public void shouldReturnSuccessForValidAttempt() User user = new User.Builder( "user", LegacyCredential.forPassword( "right" ) ).build(); // Then - assertThat( authStrategy.authenticate( user, "right" ), equalTo( AuthenticationResult.SUCCESS ) ); + assertThat( authStrategy.authenticate( user, password( "right" ) ), equalTo( AuthenticationResult.SUCCESS ) ); } @Test @@ -60,7 +61,7 @@ public void shouldReturnFailureForInvalidAttempt() User user = new User.Builder( "user", LegacyCredential.forPassword( "right" ) ).build(); // Then - assertThat( authStrategy.authenticate( user, "wrong" ), equalTo( AuthenticationResult.FAILURE ) ); + assertThat( authStrategy.authenticate( user, password( "wrong" ) ), equalTo( AuthenticationResult.FAILURE ) ); } @Test @@ -72,11 +73,11 @@ public void shouldNotSlowRequestRateOnLessThanMaxFailedAttempts() User user = new User.Builder( "user", LegacyCredential.forPassword( "right" ) ).build(); // When we've failed two times - assertThat( authStrategy.authenticate( user, "wrong" ), equalTo( AuthenticationResult.FAILURE ) ); - assertThat( authStrategy.authenticate( user, "wrong" ), equalTo( AuthenticationResult.FAILURE ) ); + assertThat( authStrategy.authenticate( user, password( "wrong" ) ), equalTo( AuthenticationResult.FAILURE ) ); + assertThat( authStrategy.authenticate( user, password( "wrong" ) ), equalTo( AuthenticationResult.FAILURE ) ); // Then - assertThat( authStrategy.authenticate( user, "right" ), equalTo( AuthenticationResult.SUCCESS )); + assertThat( authStrategy.authenticate( user, password( "right" ) ), equalTo( AuthenticationResult.SUCCESS )); } @Test @@ -107,17 +108,17 @@ private void testSlowRequestRateOnMultipleFailedAttempts( int maxFailedAttempts, // When we've failed max number of times for ( int i = 0; i < maxFailedAttempts; i++ ) { - assertThat( authStrategy.authenticate( user, "wrong" ), equalTo( AuthenticationResult.FAILURE ) ); + assertThat( authStrategy.authenticate( user, password( "wrong" ) ), equalTo( AuthenticationResult.FAILURE ) ); } // Then - assertThat( authStrategy.authenticate( user, "wrong" ), equalTo( AuthenticationResult.TOO_MANY_ATTEMPTS ) ); + assertThat( authStrategy.authenticate( user, password( "wrong" ) ), equalTo( AuthenticationResult.TOO_MANY_ATTEMPTS ) ); // But when time heals all wounds clock.forward( lockDuration.plus( 1, SECONDS ) ); // Then things should be alright - assertThat( authStrategy.authenticate( user, "wrong" ), equalTo( AuthenticationResult.FAILURE ) ); + assertThat( authStrategy.authenticate( user, password( "wrong" ) ), equalTo( AuthenticationResult.FAILURE ) ); } private void testSlowRequestRateOnMultipleFailedAttemptsWhereAttemptIsValid( int maxFailedAttempts, Duration lockDuration ) @@ -130,17 +131,17 @@ private void testSlowRequestRateOnMultipleFailedAttemptsWhereAttemptIsValid( int // When we've failed max number of times for ( int i = 0; i < maxFailedAttempts; i++ ) { - assertThat( authStrategy.authenticate( user, "wrong" ), equalTo( AuthenticationResult.FAILURE ) ); + assertThat( authStrategy.authenticate( user, password( "wrong" ) ), equalTo( AuthenticationResult.FAILURE ) ); } // Then - assertThat( authStrategy.authenticate( user, "right" ), equalTo( AuthenticationResult.TOO_MANY_ATTEMPTS )); + assertThat( authStrategy.authenticate( user, password( "right" ) ), equalTo( AuthenticationResult.TOO_MANY_ATTEMPTS )); // But when time heals all wounds clock.forward( lockDuration.plus( 1, SECONDS ) ); // Then things should be alright - assertThat( authStrategy.authenticate( user, "right" ), equalTo( AuthenticationResult.SUCCESS ) ); + assertThat( authStrategy.authenticate( user, password( "right" ) ), equalTo( AuthenticationResult.SUCCESS ) ); } @Test @@ -164,7 +165,7 @@ private void testUnlimitedFailedAuthAttempts( int maxFailedAttempts ) int attempts = ThreadLocalRandom.current().nextInt( 5, 100 ); for ( int i = 0; i < attempts; i++ ) { - assertEquals( AuthenticationResult.FAILURE, authStrategy.authenticate( user, "wrong" ) ); + assertEquals( AuthenticationResult.FAILURE, authStrategy.authenticate( user, password( "wrong" ) ) ); } } diff --git a/community/security/src/test/java/org/neo4j/server/security/auth/SecurityContextDescriptionTest.java b/community/security/src/test/java/org/neo4j/server/security/auth/SecurityContextDescriptionTest.java index f8b61cf402531..600c4fe839e46 100644 --- a/community/security/src/test/java/org/neo4j/server/security/auth/SecurityContextDescriptionTest.java +++ b/community/security/src/test/java/org/neo4j/server/security/auth/SecurityContextDescriptionTest.java @@ -33,6 +33,7 @@ import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; +import static org.neo4j.server.security.auth.BasicAuthManagerTest.password; import static org.neo4j.server.security.auth.SecurityTestUtils.authToken; public class SecurityContextDescriptionTest @@ -52,7 +53,7 @@ public void setup() throws Throwable Config.defaults() ); manager.init(); manager.start(); - manager.newUser( "johan", "bar", false ); + manager.newUser( "johan", password( "bar" ), false ); context = manager.login( authToken( "johan", "bar" ) ).authorize( s -> -1, GraphDatabaseSettings.DEFAULT_DATABASE_NAME ); } diff --git a/community/server/src/main/java/org/neo4j/server/rest/dbms/AuthorizationEnabledFilter.java b/community/server/src/main/java/org/neo4j/server/rest/dbms/AuthorizationEnabledFilter.java index 74bff5fc37baf..e323d0ef86db7 100644 --- a/community/server/src/main/java/org/neo4j/server/rest/dbms/AuthorizationEnabledFilter.java +++ b/community/server/src/main/java/org/neo4j/server/rest/dbms/AuthorizationEnabledFilter.java @@ -45,6 +45,7 @@ import org.neo4j.logging.LogProvider; import org.neo4j.server.web.JettyHttpConnection; import org.neo4j.server.web.XForwardUtil; +import org.neo4j.string.UTF8; import static java.lang.String.format; import static java.util.Collections.singletonList; @@ -156,7 +157,7 @@ public void doFilter( ServletRequest servletRequest, ServletResponse servletResp private LoginContext authenticate( String username, String password ) throws InvalidAuthTokenException { AuthManager authManager = authManagerSupplier.get(); - Map authToken = newBasicAuthToken( username, password ); + Map authToken = newBasicAuthToken( username, UTF8.encode( password ) ); return authManager.login( authToken ); } diff --git a/enterprise/kernel/src/main/java/org/neo4j/kernel/enterprise/api/security/EnterpriseAuthManager.java b/enterprise/kernel/src/main/java/org/neo4j/kernel/enterprise/api/security/EnterpriseAuthManager.java index 030e9362a2c15..f745e16f823a6 100644 --- a/enterprise/kernel/src/main/java/org/neo4j/kernel/enterprise/api/security/EnterpriseAuthManager.java +++ b/enterprise/kernel/src/main/java/org/neo4j/kernel/enterprise/api/security/EnterpriseAuthManager.java @@ -25,6 +25,7 @@ import java.util.Map; import org.neo4j.kernel.api.security.AuthManager; +import org.neo4j.kernel.api.security.AuthToken; import org.neo4j.kernel.api.security.exception.InvalidAuthTokenException; public interface EnterpriseAuthManager extends AuthManager @@ -42,6 +43,7 @@ public interface EnterpriseAuthManager extends AuthManager @Override public EnterpriseLoginContext login( Map authToken ) { + AuthToken.clearCredentials( authToken ); return EnterpriseLoginContext.AUTH_DISABLED; } diff --git a/enterprise/query-logging/src/test/java/org/neo4j/kernel/impl/query/QueryLoggerIT.java b/enterprise/query-logging/src/test/java/org/neo4j/kernel/impl/query/QueryLoggerIT.java index f9945d8704f79..08804695a9c2c 100644 --- a/enterprise/query-logging/src/test/java/org/neo4j/kernel/impl/query/QueryLoggerIT.java +++ b/enterprise/query-logging/src/test/java/org/neo4j/kernel/impl/query/QueryLoggerIT.java @@ -86,6 +86,7 @@ import static org.neo4j.graphdb.factory.GraphDatabaseSettings.logs_directory; import static org.neo4j.helpers.collection.MapUtil.stringMap; import static org.neo4j.internal.kernel.api.security.AuthSubject.AUTH_DISABLED; +import static org.neo4j.server.security.auth.BasicAuthManagerTest.password; public class QueryLoggerIT { @@ -142,8 +143,8 @@ public void shouldLogCustomUserName() throws Throwable db = new EmbeddedInteraction( databaseBuilder, config ); // create users - db.getLocalUserManager().newUser( "mats", "neo4j", false ); - db.getLocalUserManager().newUser( "andres", "neo4j", false ); + db.getLocalUserManager().newUser( "mats", password( "neo4j" ), false ); + db.getLocalUserManager().newUser( "andres", password( "neo4j" ), false ); db.getLocalUserManager().addRoleToUser( "architect", "mats" ); db.getLocalUserManager().addRoleToUser( "reader", "andres" ); @@ -177,7 +178,7 @@ public void shouldLogTXMetaDataInQueryLog() throws Throwable db = new EmbeddedInteraction( databaseBuilder, Collections.emptyMap() ); GraphDatabaseFacade graph = db.getLocalGraph(); - db.getLocalUserManager().setUserPassword( "neo4j", "123", false ); + db.getLocalUserManager().setUserPassword( "neo4j", password( "123" ), false ); EnterpriseLoginContext subject = db.login( "neo4j", "123" ); db.executeQuery( subject, "UNWIND range(0, 10) AS i CREATE (:Foo {p: i})", Collections.emptyMap(), diff --git a/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/EnterpriseUserManager.java b/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/EnterpriseUserManager.java index caf489d91d683..1187a4057c1aa 100644 --- a/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/EnterpriseUserManager.java +++ b/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/EnterpriseUserManager.java @@ -23,6 +23,7 @@ package org.neo4j.server.security.enterprise.auth; import java.io.IOException; +import java.util.Arrays; import java.util.Set; import org.neo4j.kernel.api.exceptions.InvalidArgumentsException; @@ -142,8 +143,9 @@ public Set silentlyGetUsernamesForRole( String roleName ) } @Override - public User newUser( String username, String initialPassword, boolean requirePasswordChange ) + public User newUser( String username, byte[] initialPassword, boolean requirePasswordChange ) { + Arrays.fill( initialPassword, (byte) 0 ); return null; } @@ -166,8 +168,9 @@ public User silentlyGetUser( String username ) } @Override - public void setUserPassword( String username, String password, boolean requirePasswordChange ) + public void setUserPassword( String username, byte[] password, boolean requirePasswordChange ) { + Arrays.fill( password, (byte) 0 ); } @Override diff --git a/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/InternalFlatFileRealm.java b/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/InternalFlatFileRealm.java index f62ee82649254..e3b96cb8cf063 100644 --- a/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/InternalFlatFileRealm.java +++ b/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/InternalFlatFileRealm.java @@ -64,6 +64,7 @@ import org.neo4j.server.security.auth.exception.ConcurrentModificationException; import org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles; import org.neo4j.server.security.enterprise.configuration.SecuritySettings; +import org.neo4j.string.UTF8; import static java.lang.String.format; import static java.util.Collections.emptySet; @@ -227,7 +228,7 @@ private Set ensureDefaultUsers() throws Throwable { if ( userRepository.numberOfUsers() == 0 ) { - User neo4j = newUser( INITIAL_USER_NAME, INITIAL_PASSWORD, true ); + User neo4j = newUser( INITIAL_USER_NAME, UTF8.encode( INITIAL_PASSWORD ), true ); if ( initialUserRepository.numberOfUsers() > 0 ) { User initUser = initialUserRepository.getUserByName( INITIAL_USER_NAME ); @@ -393,11 +394,11 @@ protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token ShiroAuthToken shiroAuthToken = (ShiroAuthToken) token; String username; - String password; + byte[] password; try { username = AuthToken.safeCast( AuthToken.PRINCIPAL, shiroAuthToken.getAuthTokenMap() ); - password = AuthToken.safeCast( AuthToken.CREDENTIALS, shiroAuthToken.getAuthTokenMap() ); + password = AuthToken.safeCastCredentials( AuthToken.CREDENTIALS, shiroAuthToken.getAuthTokenMap() ); } catch ( InvalidAuthTokenException e ) { @@ -458,23 +459,31 @@ private int numberOfRoles() @Deprecated @Override - public User newUser( String username, String initialPassword, boolean requirePasswordChange ) + public User newUser( String username, byte[] initialPassword, boolean requirePasswordChange ) throws IOException, InvalidArgumentsException { - userRepository.assertValidUsername( username ); - passwordPolicy.validatePassword( initialPassword ); + try + { + userRepository.assertValidUsername( username ); + passwordPolicy.validatePassword( initialPassword ); - User user = new User.Builder() - .withName( username ) - .withCredentials( LegacyCredential.forPassword( initialPassword ) ) - .withRequiredPasswordChange( requirePasswordChange ) - .build(); - synchronized ( this ) + User user = new User.Builder() + .withName( username ) + .withCredentials( LegacyCredential.forPassword( initialPassword ) ) + .withRequiredPasswordChange( requirePasswordChange ) + .build(); + synchronized ( this ) + { + userRepository.create( user ); + } + + return user; + } + finally { - userRepository.create( user ); + // Clear password + Arrays.fill( initialPassword, (byte) 0 ); } - - return user; } @Deprecated @@ -634,34 +643,41 @@ public User silentlyGetUser( String username ) @Deprecated @Override - public void setUserPassword( String username, String password, boolean requirePasswordChange ) + public void setUserPassword( String username, byte[] password, boolean requirePasswordChange ) throws IOException, InvalidArgumentsException { - User existingUser = getUser( username ); - passwordPolicy.validatePassword( password ); - if ( existingUser.credentials().matchesPassword( password ) ) - { - throw new InvalidArgumentsException( "Old password and new password cannot be the same." ); - } - try { - User updatedUser = existingUser.augment() - .withCredentials( LegacyCredential.forPassword( password ) ) - .withRequiredPasswordChange( requirePasswordChange ) - .build(); - synchronized ( this ) + User existingUser = getUser( username ); + passwordPolicy.validatePassword( password ); + if ( existingUser.credentials().matchesPassword( password ) ) { - userRepository.update( existingUser, updatedUser ); + throw new InvalidArgumentsException( "Old password and new password cannot be the same." ); + } + + try + { + User updatedUser = existingUser.augment() + .withCredentials( LegacyCredential.forPassword( password ) ) + .withRequiredPasswordChange( requirePasswordChange ) + .build(); + synchronized ( this ) + { + userRepository.update( existingUser, updatedUser ); + } } + catch ( ConcurrentModificationException e ) + { + // try again + setUserPassword( username, password, requirePasswordChange ); + } + + clearCacheForUser( username ); } - catch ( ConcurrentModificationException e ) + finally { - // try again - setUserPassword( username, password, requirePasswordChange ); + Arrays.fill( password, (byte) 0 ); } - - clearCacheForUser( username ); } @Deprecated diff --git a/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/MultiRealmAuthManager.java b/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/MultiRealmAuthManager.java index 7ae448b4a7179..c91c85e97e1d8 100644 --- a/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/MultiRealmAuthManager.java +++ b/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/MultiRealmAuthManager.java @@ -55,6 +55,7 @@ import org.neo4j.graphdb.security.AuthProviderTimeoutException; import org.neo4j.internal.kernel.api.security.AuthSubject; import org.neo4j.internal.kernel.api.security.AuthenticationResult; +import org.neo4j.kernel.api.security.AuthToken; import org.neo4j.kernel.api.security.exception.InvalidAuthTokenException; import org.neo4j.kernel.enterprise.api.security.EnterpriseLoginContext; import org.neo4j.server.security.enterprise.log.SecurityLog; @@ -104,83 +105,90 @@ private SubjectDAO createSubjectDAO() @Override public EnterpriseLoginContext login( Map authToken ) throws InvalidAuthTokenException { - EnterpriseLoginContext securityContext; - - ShiroAuthToken token = new ShiroAuthToken( authToken ); - assertValidScheme( token ); - try { - securityContext = new StandardEnterpriseLoginContext( - this, (ShiroSubject) securityManager.login( null, token ) ); - AuthenticationResult authenticationResult = securityContext.subject().getAuthenticationResult(); - if ( authenticationResult == AuthenticationResult.SUCCESS ) + EnterpriseLoginContext securityContext; + + ShiroAuthToken token = new ShiroAuthToken( authToken ); + assertValidScheme( token ); + + try { - if ( logSuccessfulLogin ) + securityContext = new StandardEnterpriseLoginContext( + this, (ShiroSubject) securityManager.login( null, token ) ); + AuthenticationResult authenticationResult = securityContext.subject().getAuthenticationResult(); + if ( authenticationResult == AuthenticationResult.SUCCESS ) + { + if ( logSuccessfulLogin ) + { + securityLog.info( securityContext.subject(), "logged in" ); + } + } + else if ( authenticationResult == AuthenticationResult.PASSWORD_CHANGE_REQUIRED ) + { + securityLog.info( securityContext.subject(), "logged in (password change required)" ); + } + else { - securityLog.info( securityContext.subject(), "logged in" ); + String errorMessage = ((StandardEnterpriseLoginContext.NeoShiroSubject) securityContext.subject()) + .getAuthenticationFailureMessage(); + securityLog.error( "[%s]: failed to log in: %s", escape( token.getPrincipal().toString() ), errorMessage ); } + // No need to keep full Shiro authentication info around on the subject + ((StandardEnterpriseLoginContext.NeoShiroSubject) securityContext.subject()).clearAuthenticationInfo(); } - else if ( authenticationResult == AuthenticationResult.PASSWORD_CHANGE_REQUIRED ) + catch ( UnsupportedTokenException e ) { - securityLog.info( securityContext.subject(), "logged in (password change required)" ); + securityLog.error( "Unknown user failed to log in: %s", e.getMessage() ); + Throwable cause = e.getCause(); + if ( cause instanceof InvalidAuthTokenException ) + { + throw new InvalidAuthTokenException( cause.getMessage() + ": " + token ); + } + throw invalidToken( ": " + token ); } - else + catch ( ExcessiveAttemptsException e ) { - String errorMessage = ((StandardEnterpriseLoginContext.NeoShiroSubject) securityContext.subject()) - .getAuthenticationFailureMessage(); - securityLog.error( "[%s]: failed to log in: %s", escape( token.getPrincipal().toString() ), errorMessage ); + // NOTE: We only get this with single (internal) realm authentication + securityContext = new StandardEnterpriseLoginContext( this, + new ShiroSubject( securityManager, AuthenticationResult.TOO_MANY_ATTEMPTS ) ); + securityLog.error( "[%s]: failed to log in: too many failed attempts", + escape( token.getPrincipal().toString() ) ); } - // No need to keep full Shiro authentication info around on the subject - ((StandardEnterpriseLoginContext.NeoShiroSubject) securityContext.subject()).clearAuthenticationInfo(); - } - catch ( UnsupportedTokenException e ) - { - securityLog.error( "Unknown user failed to log in: %s", e.getMessage() ); - Throwable cause = e.getCause(); - if ( cause != null && cause instanceof InvalidAuthTokenException ) + catch ( AuthenticationException e ) { - throw new InvalidAuthTokenException( cause.getMessage() + ": " + token ); + if ( e.getCause() != null && e.getCause() instanceof AuthProviderTimeoutException ) + { + Throwable cause = e.getCause().getCause(); + securityLog.error( "[%s]: failed to log in: auth server timeout%s", + escape( token.getPrincipal().toString() ), + cause != null && cause.getMessage() != null ? " (" + cause.getMessage() + ")" : "" ); + throw new AuthProviderTimeoutException( e.getCause().getMessage(), e.getCause() ); + } + else if ( e.getCause() != null && e.getCause() instanceof AuthProviderFailedException ) + { + Throwable cause = e.getCause().getCause(); + securityLog.error( "[%s]: failed to log in: auth server connection refused%s", + escape( token.getPrincipal().toString() ), + cause != null && cause.getMessage() != null ? " (" + cause.getMessage() + ")" : "" ); + throw new AuthProviderFailedException( e.getCause().getMessage(), e.getCause() ); + } + securityContext = new StandardEnterpriseLoginContext( this, + new ShiroSubject( securityManager, AuthenticationResult.FAILURE ) ); + Throwable cause = e.getCause(); + Throwable causeCause = e.getCause() != null ? e.getCause().getCause() : null; + String errorMessage = String.format( "invalid principal or credentials%s%s", + cause != null && cause.getMessage() != null ? " (" + cause.getMessage() + ")" : "", + causeCause != null && causeCause.getMessage() != null ? " (" + causeCause.getMessage() + ")" : "" ); + securityLog.error( "[%s]: failed to log in: %s", escape( token.getPrincipal().toString() ), errorMessage ); } - throw invalidToken( ": " + token ); - } - catch ( ExcessiveAttemptsException e ) - { - // NOTE: We only get this with single (internal) realm authentication - securityContext = new StandardEnterpriseLoginContext( this, - new ShiroSubject( securityManager, AuthenticationResult.TOO_MANY_ATTEMPTS ) ); - securityLog.error( "[%s]: failed to log in: too many failed attempts", - escape( token.getPrincipal().toString() ) ); + + return securityContext; } - catch ( AuthenticationException e ) + finally { - if ( e.getCause() != null && e.getCause() instanceof AuthProviderTimeoutException ) - { - Throwable cause = e.getCause().getCause(); - securityLog.error( "[%s]: failed to log in: auth server timeout%s", - escape( token.getPrincipal().toString() ), - cause != null && cause.getMessage() != null ? " (" + cause.getMessage() + ")" : "" ); - throw new AuthProviderTimeoutException( e.getCause().getMessage(), e.getCause() ); - } - else if ( e.getCause() != null && e.getCause() instanceof AuthProviderFailedException ) - { - Throwable cause = e.getCause().getCause(); - securityLog.error( "[%s]: failed to log in: auth server connection refused%s", - escape( token.getPrincipal().toString() ), - cause != null && cause.getMessage() != null ? " (" + cause.getMessage() + ")" : "" ); - throw new AuthProviderFailedException( e.getCause().getMessage(), e.getCause() ); - } - securityContext = new StandardEnterpriseLoginContext( this, - new ShiroSubject( securityManager, AuthenticationResult.FAILURE ) ); - Throwable cause = e.getCause(); - Throwable causeCause = e.getCause() != null ? e.getCause().getCause() : null; - String errorMessage = String.format( "invalid principal or credentials%s%s", - cause != null && cause.getMessage() != null ? " (" + cause.getMessage() + ")" : "", - causeCause != null && causeCause.getMessage() != null ? " (" + causeCause.getMessage() + ")" : "" ); - securityLog.error( "[%s]: failed to log in: %s", escape( token.getPrincipal().toString() ), errorMessage ); + AuthToken.clearCredentials( authToken ); } - - return securityContext; } private void assertValidScheme( ShiroAuthToken token ) throws InvalidAuthTokenException diff --git a/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/PersonalUserManager.java b/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/PersonalUserManager.java index 413031ce3f477..72a58099cbe21 100644 --- a/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/PersonalUserManager.java +++ b/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/PersonalUserManager.java @@ -50,7 +50,7 @@ class PersonalUserManager implements EnterpriseUserManager } @Override - public User newUser( String username, String initialPassword, boolean requirePasswordChange ) + public User newUser( String username, byte[] initialPassword, boolean requirePasswordChange ) throws IOException, InvalidArgumentsException, AuthorizationViolationException { try @@ -181,7 +181,7 @@ public boolean deleteRole( String roleName ) } @Override - public void setUserPassword( String username, String password, boolean requirePasswordChange ) + public void setUserPassword( String username, byte[] password, boolean requirePasswordChange ) throws IOException, InvalidArgumentsException, AuthorizationViolationException { if ( subject.hasUsername( username ) ) diff --git a/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/UserManagementProcedures.java b/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/UserManagementProcedures.java index d176792dc6f62..2810b0883e78a 100644 --- a/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/UserManagementProcedures.java +++ b/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/UserManagementProcedures.java @@ -31,6 +31,7 @@ import org.neo4j.procedure.Description; import org.neo4j.procedure.Name; import org.neo4j.procedure.Procedure; +import org.neo4j.string.UTF8; import static org.neo4j.procedure.Mode.DBMS; @@ -45,7 +46,8 @@ public void createUser( @Name( "username" ) String username, @Name( "password" ) @Name( value = "requirePasswordChange", defaultValue = "true" ) boolean requirePasswordChange ) throws InvalidArgumentsException, IOException { - userManager.newUser( username, password, requirePasswordChange ); + // TODO: Deprecate this and create a new procedure that takes password as a byte[] + userManager.newUser( username, UTF8.encode( password ), requirePasswordChange ); } @Deprecated @@ -54,6 +56,7 @@ public void createUser( @Name( "username" ) String username, @Name( "password" ) public void changePasswordDeprecated( @Name( "password" ) String password ) throws InvalidArgumentsException, IOException { + // TODO: Deprecate this and create a new procedure that takes password as a byte[] changePassword( password, false ); } @@ -63,6 +66,7 @@ public void changePassword( @Name( "password" ) String password, @Name( value = "requirePasswordChange", defaultValue = "false" ) boolean requirePasswordChange ) throws InvalidArgumentsException, IOException { + // TODO: Deprecate this and create a new procedure that takes password as a byte[] setUserPassword( securityContext.subject().username(), password, requirePasswordChange ); } @@ -72,6 +76,7 @@ public void changeUserPassword( @Name( "username" ) String username, @Name( "new @Name( value = "requirePasswordChange", defaultValue = "true" ) boolean requirePasswordChange ) throws InvalidArgumentsException, IOException { + // TODO: Deprecate this and create a new procedure that takes password as a byte[] securityContext.assertCredentialsNotExpired(); setUserPassword( username, newPassword, requirePasswordChange ); } @@ -186,7 +191,7 @@ public void deleteRole( @Name( "roleName" ) String roleName ) throws InvalidArgu private void setUserPassword( String username, String newPassword, boolean requirePasswordChange ) throws IOException, InvalidArgumentsException { - userManager.setUserPassword( username, newPassword, requirePasswordChange ); + userManager.setUserPassword( username, UTF8.encode( newPassword ), requirePasswordChange ); if ( securityContext.subject().hasUsername( username ) ) { securityContext.subject().setPasswordChangeNoLongerRequired(); diff --git a/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/plugin/PluginApiAuthToken.java b/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/plugin/PluginApiAuthToken.java index 0761c921982ed..c400649aa07c1 100644 --- a/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/plugin/PluginApiAuthToken.java +++ b/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/plugin/PluginApiAuthToken.java @@ -22,6 +22,8 @@ */ package org.neo4j.server.security.enterprise.auth.plugin; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.util.Map; import org.neo4j.kernel.api.security.exception.InvalidAuthTokenException; @@ -75,26 +77,27 @@ public static AuthToken createFromMap( Map authTokenMap ) throws // Always require principal String principal = org.neo4j.kernel.api.security.AuthToken.safeCast( PRINCIPAL, authTokenMap ); - String credentials = null; + byte[] credentials = null; if ( scheme.equals( org.neo4j.kernel.api.security.AuthToken.BASIC_SCHEME ) ) { // Basic scheme requires credentials - credentials = org.neo4j.kernel.api.security.AuthToken.safeCast( CREDENTIALS, authTokenMap ); + credentials = org.neo4j.kernel.api.security.AuthToken.safeCastCredentials( CREDENTIALS, authTokenMap ); } else { // Otherwise credentials are optional Object credentialsObject = authTokenMap.get( CREDENTIALS ); - if ( credentialsObject instanceof String ) + if ( credentialsObject instanceof byte[] ) { - credentials = (String) credentialsObject; + credentials = (byte[]) credentialsObject; } } Map parameters = org.neo4j.kernel.api.security.AuthToken.safeCastMap( PARAMETERS, authTokenMap ); return PluginApiAuthToken.of( principal, - credentials != null ? credentials.toCharArray() : null, + // Convert UTF8 byte[] to char[] (this should not create any intermediate copies) + credentials != null ? StandardCharsets.UTF_8.decode( ByteBuffer.wrap( credentials ) ).array() : null, parameters ); } } diff --git a/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/plugin/PluginRealm.java b/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/plugin/PluginRealm.java index dc3859495cf95..c3d7fcf4f72fc 100644 --- a/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/plugin/PluginRealm.java +++ b/enterprise/security/src/main/java/org/neo4j/server/security/enterprise/auth/plugin/PluginRealm.java @@ -33,6 +33,7 @@ import java.nio.file.Path; import java.time.Clock; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Map; import java.util.Optional; @@ -187,28 +188,36 @@ protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token { AuthToken pluginAuthToken = PluginApiAuthToken.createFromMap( ((ShiroAuthToken) token).getAuthTokenMap() ); - if ( authPlugin != null ) + try { - AuthInfo authInfo = authPlugin.authenticateAndAuthorize( pluginAuthToken ); - if ( authInfo != null ) + if ( authPlugin != null ) { - PluginAuthInfo pluginAuthInfo = - PluginAuthInfo.createCacheable( authInfo, getName(), secureHasher ); + AuthInfo authInfo = authPlugin.authenticateAndAuthorize( pluginAuthToken ); + if ( authInfo != null ) + { + PluginAuthInfo pluginAuthInfo = + PluginAuthInfo.createCacheable( authInfo, getName(), secureHasher ); - cacheAuthorizationInfo( pluginAuthInfo ); + cacheAuthorizationInfo( pluginAuthInfo ); - return pluginAuthInfo; + return pluginAuthInfo; + } } - } - else if ( authenticationPlugin != null ) - { - org.neo4j.server.security.enterprise.auth.plugin.spi.AuthenticationInfo authenticationInfo = - authenticationPlugin.authenticate( pluginAuthToken ); - if ( authenticationInfo != null ) + else if ( authenticationPlugin != null ) { - return PluginAuthenticationInfo.createCacheable( authenticationInfo, getName(), secureHasher ); + org.neo4j.server.security.enterprise.auth.plugin.spi.AuthenticationInfo authenticationInfo = + authenticationPlugin.authenticate( pluginAuthToken ); + if ( authenticationInfo != null ) + { + return PluginAuthenticationInfo.createCacheable( authenticationInfo, getName(), secureHasher ); + } } } + finally + { + // Clear credentials + Arrays.fill( pluginAuthToken.credentials(), (char) 0 ); + } } catch ( org.neo4j.server.security.enterprise.auth.plugin.api.AuthenticationException | InvalidAuthTokenException e ) @@ -365,7 +374,15 @@ public boolean doCredentialsMatch( AuthenticationToken token, AuthenticationInfo try { AuthToken pluginApiAuthToken = PluginApiAuthToken.createFromMap( authToken ); - return customCredentialsMatcher.doCredentialsMatch( pluginApiAuthToken ); + try + { + return customCredentialsMatcher.doCredentialsMatch( pluginApiAuthToken ); + } + finally + { + // Clear credentials + Arrays.fill( pluginApiAuthToken.credentials(), (char) 0 ); + } } catch ( InvalidAuthTokenException e ) { diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/AuthProceduresInteractionTestBase.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/AuthProceduresInteractionTestBase.java index 5cebdd9e16c73..d34db8734eeb0 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/AuthProceduresInteractionTestBase.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/AuthProceduresInteractionTestBase.java @@ -46,6 +46,7 @@ import static org.neo4j.graphdb.security.AuthorizationViolationException.PERMISSION_DENIED; import static org.neo4j.helpers.collection.MapUtil.map; import static org.neo4j.internal.kernel.api.security.AuthenticationResult.PASSWORD_CHANGE_REQUIRED; +import static org.neo4j.server.security.auth.BasicAuthManagerTest.password; import static org.neo4j.server.security.enterprise.auth.InternalFlatFileRealm.IS_SUSPENDED; import static org.neo4j.server.security.enterprise.auth.ProcedureInteractionTestBase.ClassWithProcedures.exceptionsInProcedure; import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.ADMIN; @@ -891,7 +892,7 @@ public void shouldNotClearAuthCacheIfNotAdmin() @Test public void shouldPrintUserAndRolesWhenPermissionDenied() throws Throwable { - userManager.newUser( "mats", "foo", false ); + userManager.newUser( "mats", password( "foo" ), false ); userManager.newRole( "failer", "mats" ); S mats = neo.login( "mats", "foo" ); diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BuiltInProceduresInteractionTestBase.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BuiltInProceduresInteractionTestBase.java index 4e9ec13df374d..513d3c2ad8c74 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BuiltInProceduresInteractionTestBase.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/BuiltInProceduresInteractionTestBase.java @@ -83,6 +83,7 @@ import static org.neo4j.helpers.collection.Iterables.single; import static org.neo4j.helpers.collection.MapUtil.map; import static org.neo4j.helpers.collection.MapUtil.stringMap; +import static org.neo4j.server.security.auth.BasicAuthManagerTest.password; import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.PUBLISHER; import static org.neo4j.test.assertion.Assert.assertEventually; import static org.neo4j.test.matchers.CommonMatchers.matchesOneToOneInAnyOrder; @@ -859,7 +860,7 @@ public void shouldTerminateLongRunningProcedureThatChecksTheGuardRegularlyIfKill public void shouldHandleWriteAfterAllowedReadProcedureForWriteUser() throws Throwable { userManager = neo.getLocalUserManager(); - userManager.newUser( "role1Subject", "abc", false ); + userManager.newUser( "role1Subject", password( "abc" ), false ); userManager.newRole( "role1" ); userManager.addRoleToUser( "role1", "role1Subject" ); userManager.addRoleToUser( PUBLISHER, "role1Subject" ); @@ -871,7 +872,7 @@ public void shouldHandleWriteAfterAllowedReadProcedureForWriteUser() throws Thro public void shouldNotAllowNonWriterToWriteAfterCallingAllowedWriteProc() throws Exception { userManager = neo.getLocalUserManager(); - userManager.newUser( "nopermission", "abc", false ); + userManager.newUser( "nopermission", password( "abc" ), false ); userManager.newRole( "role1" ); userManager.addRoleToUser( "role1", "nopermission" ); // should be able to invoke allowed procedure @@ -886,7 +887,7 @@ public void shouldNotAllowNonWriterToWriteAfterCallingAllowedWriteProc() throws public void shouldNotAllowUnauthorizedAccessToProcedure() throws Exception { userManager = neo.getLocalUserManager(); - userManager.newUser( "nopermission", "abc", false ); + userManager.newUser( "nopermission", password( "abc" ), false ); // should not be able to invoke any procedure assertFail( neo.login( "nopermission", "abc" ), "CALL test.staticReadProcedure()", READ_OPS_NOT_ALLOWED ); assertFail( neo.login( "nopermission", "abc" ), "CALL test.staticWriteProcedure()", WRITE_OPS_NOT_ALLOWED ); @@ -897,7 +898,7 @@ public void shouldNotAllowUnauthorizedAccessToProcedure() throws Exception public void shouldNotAllowNonReaderToReadAfterCallingAllowedReadProc() throws Exception { userManager = neo.getLocalUserManager(); - userManager.newUser( "nopermission", "abc", false ); + userManager.newUser( "nopermission", password( "abc" ), false ); userManager.newRole( "role1" ); userManager.addRoleToUser( "role1", "nopermission" ); // should not be able to invoke any procedure @@ -911,7 +912,7 @@ public void shouldNotAllowNonReaderToReadAfterCallingAllowedReadProc() throws Ex public void shouldHandleNestedReadProcedures() throws Throwable { userManager = neo.getLocalUserManager(); - userManager.newUser( "role1Subject", "abc", false ); + userManager.newUser( "role1Subject", password( "abc" ), false ); userManager.newRole( "role1" ); userManager.addRoleToUser( "role1", "role1Subject" ); assertSuccess( neo.login( "role1Subject", "abc" ), @@ -923,7 +924,7 @@ public void shouldHandleNestedReadProcedures() throws Throwable public void shouldHandleDoubleNestedReadProcedures() throws Throwable { userManager = neo.getLocalUserManager(); - userManager.newUser( "role1Subject", "abc", false ); + userManager.newUser( "role1Subject", password( "abc" ), false ); userManager.newRole( "role1" ); userManager.addRoleToUser( "role1", "role1Subject" ); assertSuccess( neo.login( "role1Subject", "abc" ), @@ -935,7 +936,7 @@ public void shouldHandleDoubleNestedReadProcedures() throws Throwable public void shouldFailNestedAllowedWriteProcedureFromAllowedReadProcedure() throws Throwable { userManager = neo.getLocalUserManager(); - userManager.newUser( "role1Subject", "abc", false ); + userManager.newUser( "role1Subject", password( "abc" ), false ); userManager.newRole( "role1" ); userManager.addRoleToUser( "role1", "role1Subject" ); assertFail( neo.login( "role1Subject", "abc" ), @@ -947,7 +948,7 @@ public void shouldFailNestedAllowedWriteProcedureFromAllowedReadProcedure() thro public void shouldFailNestedAllowedWriteProcedureFromAllowedReadProcedureEvenIfAdmin() throws Throwable { userManager = neo.getLocalUserManager(); - userManager.newUser( "role1Subject", "abc", false ); + userManager.newUser( "role1Subject", password( "abc" ), false ); userManager.newRole( "role1" ); userManager.addRoleToUser( "role1", "role1Subject" ); userManager.addRoleToUser( PredefinedRoles.ADMIN, "role1Subject" ); @@ -960,7 +961,7 @@ public void shouldFailNestedAllowedWriteProcedureFromAllowedReadProcedureEvenIfA public void shouldRestrictNestedReadProcedureFromAllowedWriteProcedures() throws Throwable { userManager = neo.getLocalUserManager(); - userManager.newUser( "role1Subject", "abc", false ); + userManager.newUser( "role1Subject", password( "abc" ), false ); userManager.newRole( "role1" ); userManager.addRoleToUser( "role1", "role1Subject" ); assertFail( neo.login( "role1Subject", "abc" ), @@ -972,7 +973,7 @@ public void shouldRestrictNestedReadProcedureFromAllowedWriteProcedures() throws public void shouldHandleNestedReadProcedureWithDifferentAllowedRole() throws Throwable { userManager = neo.getLocalUserManager(); - userManager.newUser( "role1Subject", "abc", false ); + userManager.newUser( "role1Subject", password( "abc" ), false ); userManager.newRole( "role1" ); userManager.addRoleToUser( "role1", "role1Subject" ); assertSuccess( neo.login( "role1Subject", "abc" ), @@ -985,7 +986,7 @@ public void shouldHandleNestedReadProcedureWithDifferentAllowedRole() throws Thr public void shouldFailNestedAllowedWriteProcedureFromNormalReadProcedure() throws Throwable { userManager = neo.getLocalUserManager(); - userManager.newUser( "role1Subject", "abc", false ); + userManager.newUser( "role1Subject", password( "abc" ), false ); userManager.newRole( "role1" ); userManager.addRoleToUser( "role1", "role1Subject" ); userManager.addRoleToUser( PredefinedRoles.PUBLISHER, "role1Subject" ); // Even if subject has WRITE permission @@ -1000,7 +1001,7 @@ public void shouldHandleFunctionWithAllowed() throws Throwable { userManager = neo.getLocalUserManager(); - userManager.newUser( "role1Subject", "abc", false ); + userManager.newUser( "role1Subject", password( "abc" ), false ); userManager.newRole( "role1" ); userManager.addRoleToUser( "role1", "role1Subject" ); assertSuccess( neo.login( "role1Subject", "abc" ), @@ -1013,7 +1014,7 @@ public void shouldHandleNestedFunctionsWithAllowed() throws Throwable { userManager = neo.getLocalUserManager(); - userManager.newUser( "role1Subject", "abc", false ); + userManager.newUser( "role1Subject", password( "abc" ), false ); userManager.newRole( "role1" ); userManager.addRoleToUser( "role1", "role1Subject" ); assertSuccess( neo.login( "role1Subject", "abc" ), @@ -1026,7 +1027,7 @@ public void shouldHandleNestedFunctionWithDifferentAllowedRole() throws Throwabl { userManager = neo.getLocalUserManager(); - userManager.newUser( "role1Subject", "abc", false ); + userManager.newUser( "role1Subject", password( "abc" ), false ); userManager.newRole( "role1" ); userManager.addRoleToUser( "role1", "role1Subject" ); assertSuccess( neo.login( "role1Subject", "abc" ), diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EnterpriseSecurityContextDescriptionTest.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EnterpriseSecurityContextDescriptionTest.java index f25899ebaee62..514c948fb7300 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EnterpriseSecurityContextDescriptionTest.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/EnterpriseSecurityContextDescriptionTest.java @@ -41,6 +41,7 @@ import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; +import static org.neo4j.server.security.auth.BasicAuthManagerTest.password; import static org.neo4j.server.security.auth.SecurityTestUtils.authToken; import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.PUBLISHER; @@ -58,7 +59,7 @@ public void setUp() throws Throwable { authManagerRule.getManager().start(); manager = authManagerRule.getManager().getUserManager(); - manager.newUser( "mats", "foo", false ); + manager.newUser( "mats", password( "foo" ), false ); } @Test diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/InternalFlatFileRealmTest.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/InternalFlatFileRealmTest.java index b2af832e831e3..c5be2c7a3ac9f 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/InternalFlatFileRealmTest.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/InternalFlatFileRealmTest.java @@ -71,6 +71,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.neo4j.server.security.auth.BasicAuthManagerTest.password; import static org.neo4j.server.security.auth.SecurityTestUtils.authToken; import static org.neo4j.server.security.enterprise.auth.AuthTestUtil.listOf; @@ -104,7 +105,7 @@ public void setup() throws Throwable authManager.init(); authManager.start(); - authManager.getUserManager().newUser( "mike", "123", false ); + authManager.getUserManager().newUser( "mike", password( "123" ), false ); } @Test diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/LdapCachingTest.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/LdapCachingTest.java index 5f59dd186f59c..1e87cee5af8f8 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/LdapCachingTest.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/LdapCachingTest.java @@ -57,6 +57,7 @@ import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import static org.neo4j.helpers.collection.MapUtil.stringMap; +import static org.neo4j.server.security.auth.BasicAuthManagerTest.password; import static org.neo4j.server.security.auth.SecurityTestUtils.authToken; import static org.neo4j.server.security.enterprise.auth.AuthTestUtil.listOf; @@ -93,8 +94,8 @@ public void setup() throws Throwable authManager.init(); authManager.start(); - authManager.getUserManager().newUser( "mike", "123", false ); - authManager.getUserManager().newUser( "mats", "456", false ); + authManager.getUserManager().newUser( "mike", password( "123" ), false ); + authManager.getUserManager().newUser( "mats", password( "456" ), false ); } private static Config getLdapConfig() diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/MultiRealmAuthManagerTest.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/MultiRealmAuthManagerTest.java index 2718f5603d78b..6470fe1f59079 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/MultiRealmAuthManagerTest.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/MultiRealmAuthManagerTest.java @@ -71,6 +71,7 @@ import static org.neo4j.helpers.Strings.escape; import static org.neo4j.helpers.collection.MapUtil.map; import static org.neo4j.logging.AssertableLogProvider.inLog; +import static org.neo4j.server.security.auth.BasicAuthManagerTest.password; import static org.neo4j.server.security.auth.SecurityTestUtils.authToken; import static org.neo4j.test.assertion.Assert.assertException; @@ -332,7 +333,7 @@ public void shouldCreateUser() throws Throwable manager.start(); // When - userManager.newUser( "foo", "bar", true ); + userManager.newUser( "foo", password( "bar" ), true ); // Then User user = users.getUserByName( "foo" ); @@ -435,7 +436,7 @@ public void shouldActivateActiveUser() throws Throwable final User user = newUser( "jake", "abc123", false ); users.create( user ); manager.start(); - when( authStrategy.authenticate( user, "abc123" ) ).thenReturn( AuthenticationResult.SUCCESS ); + when( authStrategy.authenticate( user, password( "abc123" ) ) ).thenReturn( AuthenticationResult.SUCCESS ); // When userManager.activateUser( "jake", false ); @@ -492,7 +493,7 @@ public void shouldSetPassword() throws Throwable manager.start(); // When - userManager.setUserPassword( "jake", "hello, world!", false ); + userManager.setUserPassword( "jake", password( "hello, world!" ), false ); // Then User user = userManager.getUser( "jake" ); @@ -525,7 +526,7 @@ public void shouldReturnNullWhenSettingPasswordForUnknownUser() throws Throwable // When try { - userManager.setUserPassword( "unknown", "hello, world!", false ); + userManager.setUserPassword( "unknown", password( "hello, world!" ), false ); fail( "exception expected" ); } catch ( InvalidArgumentsException e ) @@ -536,23 +537,23 @@ public void shouldReturnNullWhenSettingPasswordForUnknownUser() throws Throwable private void createTestUsers() throws Throwable { - userManager.newUser( "morpheus", "abc123", false ); + userManager.newUser( "morpheus", password( "abc123" ), false ); userManager.newRole( "admin", "morpheus" ); setMockAuthenticationStrategyResult( "morpheus", "abc123", AuthenticationResult.SUCCESS ); - userManager.newUser( "trinity", "abc123", false ); + userManager.newUser( "trinity", password( "abc123" ), false ); userManager.newRole( "architect", "trinity" ); setMockAuthenticationStrategyResult( "trinity", "abc123", AuthenticationResult.SUCCESS ); - userManager.newUser( "tank", "abc123", false ); + userManager.newUser( "tank", password( "abc123" ), false ); userManager.newRole( "publisher", "tank" ); setMockAuthenticationStrategyResult( "tank", "abc123", AuthenticationResult.SUCCESS ); - userManager.newUser( "neo", "abc123", false ); + userManager.newUser( "neo", password( "abc123" ), false ); userManager.newRole( "reader", "neo" ); setMockAuthenticationStrategyResult( "neo", "abc123", AuthenticationResult.SUCCESS ); - userManager.newUser( "smith", "abc123", false ); + userManager.newUser( "smith", password( "abc123" ), false ); userManager.newRole( "agent", "smith" ); setMockAuthenticationStrategyResult( "smith", "abc123", AuthenticationResult.SUCCESS ); } @@ -567,7 +568,7 @@ public void defaultUserShouldHaveCorrectPermissions() throws Throwable // When SecurityContext securityContext = manager.login( authToken( "neo4j", "neo4j" ) ) .authorize( token, GraphDatabaseSettings.DEFAULT_DATABASE_NAME ); - userManager.setUserPassword( "neo4j", "1234", false ); + userManager.setUserPassword( "neo4j", password( "1234" ), false ); securityContext.subject().logout(); setMockAuthenticationStrategyResult( "neo4j", "1234", AuthenticationResult.SUCCESS ); @@ -706,7 +707,7 @@ private AssertableLogProvider.LogMatcher error( String message, String... argume private void setMockAuthenticationStrategyResult( String username, String password, AuthenticationResult result ) { final User user = users.getUserByName( username ); - when( authStrategy.authenticate( user, password ) ).thenReturn( result ); + when( authStrategy.authenticate( user, password( password ) ) ).thenReturn( result ); } @Override diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/PersonalUserManagerTest.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/PersonalUserManagerTest.java index deb6faccf4ec4..5b184536bc5c6 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/PersonalUserManagerTest.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/PersonalUserManagerTest.java @@ -44,6 +44,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.neo4j.server.security.auth.BasicAuthManagerTest.password; public class PersonalUserManagerTest { @@ -65,7 +66,7 @@ public void shouldHandleFailureToCreateUser() throws Exception expectedException.expectMessage( "newUserException" ); // When - userManager.newUser( "hewhoshallnotbenamed", "avada kedavra", false ); + userManager.newUser( "hewhoshallnotbenamed", password( "avada kedavra" ), false ); verify( log ).error( withSubject( SecurityContext.AUTH_DISABLED.subject(), "tried to create user `%s`: %s" ), "hewhoshallnotbenamed", "newUserException" ); } @@ -103,7 +104,7 @@ void setFailNextCall() } @Override - public User newUser( String username, String password, boolean changeRequired ) + public User newUser( String username, byte[] password, boolean changeRequired ) throws IOException, InvalidArgumentsException { if ( failNextCall ) @@ -143,7 +144,7 @@ public User silentlyGetUser( String username ) } @Override - public void setUserPassword( String username, String password, boolean requirePasswordChange ) + public void setUserPassword( String username, byte[] password, boolean requirePasswordChange ) throws IOException, InvalidArgumentsException { if ( failNextCall ) diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/ProcedureInteractionTestBase.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/ProcedureInteractionTestBase.java index 668bc5563b295..595049e3f2459 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/ProcedureInteractionTestBase.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/ProcedureInteractionTestBase.java @@ -105,6 +105,7 @@ import static org.neo4j.kernel.api.exceptions.Status.Transaction.TransactionTimedOut; import static org.neo4j.procedure.Mode.READ; import static org.neo4j.procedure.Mode.WRITE; +import static org.neo4j.server.security.auth.BasicAuthManagerTest.password; import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.ADMIN; import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.ARCHITECT; import static org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles.EDITOR; @@ -185,13 +186,13 @@ void configuredSetup( Map config ) throws Throwable procedures.registerProcedure( ClassWithProcedures.class ); procedures.registerFunction( ClassWithFunctions.class ); userManager = neo.getLocalUserManager(); - userManager.newUser( "noneSubject", "abc", false ); - userManager.newUser( "pwdSubject", "abc", true ); - userManager.newUser( "adminSubject", "abc", false ); - userManager.newUser( "schemaSubject", "abc", false ); - userManager.newUser( "writeSubject", "abc", false ); - userManager.newUser( "editorSubject", "abc", false ); - userManager.newUser( "readSubject", "123", false ); + userManager.newUser( "noneSubject", password( "abc" ), false ); + userManager.newUser( "pwdSubject", password( "abc" ), true ); + userManager.newUser( "adminSubject", password( "abc" ), false ); + userManager.newUser( "schemaSubject", password( "abc" ), false ); + userManager.newUser( "writeSubject", password( "abc" ), false ); + userManager.newUser( "editorSubject", password( "abc" ), false ); + userManager.newUser( "readSubject", password( "123" ), false ); // Currently admin role is created by default userManager.addRoleToUser( ADMIN, "adminSubject" ); userManager.addRoleToUser( ARCHITECT, "schemaSubject" ); diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/integration/bolt/BoltInitChangePasswordTest.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/integration/bolt/BoltInitChangePasswordTest.java index b4d988624012c..3790dcca455ee 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/integration/bolt/BoltInitChangePasswordTest.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/integration/bolt/BoltInitChangePasswordTest.java @@ -38,6 +38,7 @@ import org.neo4j.server.security.enterprise.auth.MultiRealmAuthManagerRule.FullSecurityLog; import static org.neo4j.helpers.collection.MapUtil.map; +import static org.neo4j.server.security.auth.BasicAuthManagerTest.password; import static org.neo4j.test.assertion.Assert.assertException; public class BoltInitChangePasswordTest @@ -51,7 +52,7 @@ public class BoltInitChangePasswordTest public void setup() throws Throwable { authentication = new BasicAuthentication( authManagerRule.getManager(), authManagerRule.getManager() ); - authManagerRule.getManager().getUserManager().newUser( "neo4j", "123", true ); + authManagerRule.getManager().getUserManager().newUser( "neo4j", password( "123" ), true ); } @Test diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/integration/bolt/LdapAuthIT.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/integration/bolt/LdapAuthIT.java index 531862ab9a7d1..66a5dffe19787 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/integration/bolt/LdapAuthIT.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/integration/bolt/LdapAuthIT.java @@ -83,6 +83,7 @@ import static org.neo4j.bolt.v1.runtime.spi.StreamMatchers.eqRecord; import static org.neo4j.bolt.v1.transport.integration.TransportTestUtil.eventuallyDisconnects; import static org.neo4j.bolt.v1.transport.integration.TransportTestUtil.eventuallyReceives; +import static org.neo4j.server.security.auth.BasicAuthManagerTest.password; import static org.neo4j.server.security.enterprise.auth.LdapRealm.LDAP_AUTHORIZATION_FAILURE_CLIENT_MESSAGE; import static org.neo4j.server.security.enterprise.auth.LdapRealm.LDAP_CONNECTION_REFUSED_CLIENT_MESSAGE; import static org.neo4j.server.security.enterprise.auth.LdapRealm.LDAP_CONNECTION_TIMEOUT_CLIENT_MESSAGE; @@ -1395,7 +1396,7 @@ private void createNativeUser( String username, String password, String... roles gds.getDependencyResolver().resolveDependency( EnterpriseAuthAndUserManager.class ); authManager.getUserManager( AuthSubject.AUTH_DISABLED, true ) - .newUser( username, password, false ); + .newUser( username, password( password ), false ); for ( String role : roles ) { diff --git a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/plugin/PropertyLevelSecurityIT.java b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/plugin/PropertyLevelSecurityIT.java index 6dfcb022a2ad5..037ab47edb7db 100644 --- a/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/plugin/PropertyLevelSecurityIT.java +++ b/enterprise/security/src/test/java/org/neo4j/server/security/enterprise/auth/plugin/PropertyLevelSecurityIT.java @@ -61,6 +61,7 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.neo4j.internal.kernel.api.Transaction.Type.explicit; +import static org.neo4j.server.security.auth.BasicAuthManagerTest.password; import static org.neo4j.server.security.auth.SecurityTestUtils.authToken; public class PropertyLevelSecurityIT @@ -88,10 +89,10 @@ public void setUp() throws Throwable Procedures procedures = db.getDependencyResolver().resolveDependency( Procedures.class ); procedures.registerProcedure( TestProcedure.class ); EnterpriseUserManager userManager = authManager.getUserManager(); - userManager.newUser( "Neo", "eon", false ); - userManager.newUser( "Smith", "mr", false ); - userManager.newUser( "Jones", "mr", false ); - userManager.newUser( "Morpheus", "dealwithit", false ); + userManager.newUser( "Neo", password( "eon" ), false ); + userManager.newUser( "Smith", password( "mr" ), false ); + userManager.newUser( "Jones", password( "mr" ), false ); + userManager.newUser( "Morpheus", password( "dealwithit" ), false ); userManager.newRole( "procRole", "Jones" ); userManager.newRole( "Agent", "Smith", "Jones" ); diff --git a/integrationtests/src/test/java/org/neo4j/auth/FlatFileChaoticStressIT.java b/integrationtests/src/test/java/org/neo4j/auth/FlatFileChaoticStressIT.java index 37329c3660ec6..264f96af4d6c5 100644 --- a/integrationtests/src/test/java/org/neo4j/auth/FlatFileChaoticStressIT.java +++ b/integrationtests/src/test/java/org/neo4j/auth/FlatFileChaoticStressIT.java @@ -33,6 +33,7 @@ import org.neo4j.io.fs.FileSystemAbstraction; import org.neo4j.kernel.api.exceptions.InvalidArgumentsException; +import org.neo4j.string.UTF8; import org.neo4j.test.rule.fs.EphemeralFileSystemRule; public class FlatFileChaoticStressIT extends FlatFileStressBase @@ -105,7 +106,7 @@ private void createUser() String password = deviousPassword(); try { - flatFileRealm.newUser( username, password, false ); + flatFileRealm.newUser( username, UTF8.encode( password ), false ); } catch ( IOException e ) { @@ -140,7 +141,7 @@ private void changePassword() String password = deviousPassword(); try { - flatFileRealm.setUserPassword( username, password, false ); + flatFileRealm.setUserPassword( username, UTF8.encode( password ), false ); } catch ( IOException e ) { diff --git a/integrationtests/src/test/java/org/neo4j/auth/FlatFilePredictableStressIT.java b/integrationtests/src/test/java/org/neo4j/auth/FlatFilePredictableStressIT.java index b8a40b7732f97..b5d6ed8b35a74 100644 --- a/integrationtests/src/test/java/org/neo4j/auth/FlatFilePredictableStressIT.java +++ b/integrationtests/src/test/java/org/neo4j/auth/FlatFilePredictableStressIT.java @@ -31,6 +31,7 @@ import org.neo4j.io.fs.FileSystemAbstraction; import org.neo4j.kernel.api.exceptions.InvalidArgumentsException; import org.neo4j.server.security.enterprise.auth.plugin.api.PredefinedRoles; +import org.neo4j.string.UTF8; import org.neo4j.test.rule.fs.EphemeralFileSystemRule; public class FlatFilePredictableStressIT extends FlatFileStressBase @@ -84,7 +85,7 @@ private void createUser() { try { - flatFileRealm.newUser( username, password, false ); + flatFileRealm.newUser( username, UTF8.encode( password ), false ); exists = true; } catch ( IOException e ) @@ -125,7 +126,7 @@ private void changePassword() String newPassword = deviousPassword(); try { - flatFileRealm.setUserPassword( username, newPassword, false ); + flatFileRealm.setUserPassword( username, UTF8.encode( newPassword ), false ); password = newPassword; } catch ( IOException e )