diff --git a/community/security/pom.xml b/community/security/pom.xml index dcbcfc8392386..6b3d646f2d4b8 100644 --- a/community/security/pom.xml +++ b/community/security/pom.xml @@ -96,6 +96,12 @@ the relevant Commercial Agreement. test-jar test + + org.neo4j + neo4j-cypher + ${project.version} + test + org.neo4j neo4j-logging 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 f1fab88966f4e..38059bb71db46 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 @@ -20,6 +20,10 @@ package org.neo4j.server.security.auth; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; import org.neo4j.kernel.api.security.AuthSubject; import org.neo4j.kernel.api.security.exception.InvalidArgumentsException; @@ -34,9 +38,68 @@ public class AuthProcedures @Context public AuthSubject authSubject; + @Procedure( name = "dbms.communityAuth.createUser", mode = DBMS ) + public void createUser( @Name( "username" ) String username, @Name( "password" ) String password, + @Name( "requirePasswordChange" ) boolean requirePasswordChange ) + throws InvalidArgumentsException, IOException + { + BasicAuthSubject subject = BasicAuthSubject.castOrFail( authSubject ); + subject.getAuthManager().newUser( username, password, requirePasswordChange ); + } + + @Procedure( name = "dbms.communityAuth.deleteUser", mode = DBMS ) + public void deleteUser( @Name( "username" ) String username ) throws InvalidArgumentsException, IOException + { + BasicAuthSubject subject = BasicAuthSubject.castOrFail( authSubject ); + if ( subject.doesUsernameMatch( username ) ) + { + throw new InvalidArgumentsException( "Deleting yourself (user '" + username + "') is not allowed." ); + } + subject.getAuthManager().deleteUser( username ); + } + @Procedure( name = "dbms.changePassword", mode = DBMS ) public void changePassword( @Name( "password" ) String password ) throws InvalidArgumentsException, IOException { authSubject.setPassword( password ); } + + @Procedure( name = "dbms.communityAuth.showCurrentUser", mode = DBMS ) + public Stream showCurrentUser() throws InvalidArgumentsException, IOException + { + BasicAuthSubject subject = BasicAuthSubject.castOrFail( authSubject ); + return Stream.of( new UserResult( + subject.name(), + subject.getAuthManager().getUser( subject.name() ).getFlags() + ) ); + } + + @Procedure( name = "dbms.communityAuth.listUsers", mode = DBMS ) + public Stream listUsers() throws InvalidArgumentsException, IOException + { + BasicAuthSubject subject = BasicAuthSubject.castOrFail( authSubject ); + Set usernames = subject.getAuthManager().getAllUsernames(); + List results = new ArrayList<>(); + for ( String username : usernames ) + { + results.add( new UserResult( + username, + subject.getAuthManager().getUser( username ).getFlags() + ) ); + } + return results.stream(); + } + + public static class UserResult + { + public final String username; + public final List flags; + + UserResult( String username, Iterable flags ) + { + this.username = username; + this.flags = new ArrayList<>(); + for ( String f : flags ) {this.flags.add( f );} + } + } } 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 00251065fbc55..ccb0ed0ad2788 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 @@ -22,6 +22,7 @@ import java.io.IOException; import java.time.Clock; import java.util.Map; +import java.util.Set; import org.neo4j.graphdb.security.AuthorizationViolationException; import org.neo4j.kernel.api.security.AuthManager; @@ -35,7 +36,7 @@ /** * Manages server authentication and authorization. *

- * Through the BasicAuthManager you can create, update and delete users, and authenticate using credentials. + * Through the BasicAuthManager you can create, update and delete userRepository, and authenticate using credentials. *

> * NOTE: AuthManager will manage the lifecycle of the given UserRepository, * so the given UserRepository should not be added to another LifeSupport. @@ -44,33 +45,33 @@ public class BasicAuthManager implements AuthManager, UserManager, UserManagerSupplier { protected final AuthenticationStrategy authStrategy; - protected final UserRepository users; + protected final UserRepository userRepository; protected final PasswordPolicy passwordPolicy; - public BasicAuthManager( UserRepository users, PasswordPolicy passwordPolicy, AuthenticationStrategy authStrategy ) + public BasicAuthManager( UserRepository userRepository, PasswordPolicy passwordPolicy, AuthenticationStrategy authStrategy ) { - this.users = users; + this.userRepository = userRepository; this.passwordPolicy = passwordPolicy; this.authStrategy = authStrategy; } - public BasicAuthManager( UserRepository users, PasswordPolicy passwordPolicy, Clock clock ) + public BasicAuthManager( UserRepository userRepository, PasswordPolicy passwordPolicy, Clock clock ) { - this( users, passwordPolicy, new RateLimitedAuthenticationStrategy( clock, 3 ) ); + this( userRepository, passwordPolicy, new RateLimitedAuthenticationStrategy( clock, 3 ) ); } @Override public void init() throws Throwable { - users.init(); + userRepository.init(); } @Override public void start() throws Throwable { - users.start(); + userRepository.start(); - if ( users.numberOfUsers() == 0 ) + if ( userRepository.numberOfUsers() == 0 ) { newUser( "neo4j", "neo4j", true ); } @@ -79,22 +80,22 @@ public void start() throws Throwable @Override public void stop() throws Throwable { - users.stop(); + userRepository.stop(); } @Override public void shutdown() throws Throwable { - users.shutdown(); + userRepository.shutdown(); } @Override - public AuthSubject login( Map authToken ) throws InvalidAuthTokenException + public BasicAuthSubject login( Map authToken ) throws InvalidAuthTokenException { String username = AuthToken.safeCast( AuthToken.PRINCIPAL, authToken ); String password = AuthToken.safeCast( AuthToken.CREDENTIALS, authToken ); - User user = users.getUserByName( username ); + User user = userRepository.getUserByName( username ); AuthenticationResult result = AuthenticationResult.FAILURE; if ( user != null ) { @@ -111,30 +112,34 @@ public AuthSubject login( Map authToken ) throws InvalidAuthToken public User newUser( String username, String initialPassword, boolean requirePasswordChange ) throws IOException, InvalidArgumentsException { - assertValidName( username ); + assertValidUsername( username ); + + passwordPolicy.validatePassword( initialPassword ); + User user = new User.Builder() .withName( username ) .withCredentials( Credential.forPassword( initialPassword ) ) .withRequiredPasswordChange( requirePasswordChange ) .build(); - users.create( user ); + userRepository.create( user ); + return user; } @Override - public boolean deleteUser( String username ) throws IOException + public boolean deleteUser( String username ) throws IOException, InvalidArgumentsException { - User user = users.getUserByName( username ); - return user != null && users.delete( user ); + User user = getUser( username ); + return user != null && userRepository.delete( user ); } @Override public User getUser( String username ) throws InvalidArgumentsException { - User user = users.getUserByName( username ); + User user = userRepository.getUserByName( username ); if ( user == null ) { - throw new InvalidArgumentsException( "User '" + username + "' does not exist!" ); + throw new InvalidArgumentsException( "User '" + username + "' does not exist." ); } return user; } @@ -156,11 +161,7 @@ public void setPassword( AuthSubject authSubject, String username, String passwo public void setUserPassword( String username, String password ) throws IOException, InvalidArgumentsException { - User existingUser = users.getUserByName( username ); - if ( existingUser == null ) - { - throw new InvalidArgumentsException( "User '" + username + "' does not exist" ); - } + User existingUser = getUser( username ); passwordPolicy.validatePassword( password ); @@ -175,7 +176,7 @@ public void setUserPassword( String username, String password ) throws IOExcepti .withCredentials( Credential.forPassword( password ) ) .withRequiredPasswordChange( false ) .build(); - users.update( existingUser, updatedUser ); + userRepository.update( existingUser, updatedUser ); } catch ( ConcurrentModificationException e ) { // try again @@ -183,11 +184,23 @@ public void setUserPassword( String username, String password ) throws IOExcepti } } - private void assertValidName( String name ) throws InvalidArgumentsException + @Override + public Set getAllUsernames() { - if ( !users.isValidUsername( name ) ) + return userRepository.getAllUsernames(); + } + + private void assertValidUsername( String name ) throws InvalidArgumentsException + { + if ( name.isEmpty() ) + { + throw new InvalidArgumentsException( "The provided user name is empty." ); + } + if ( !userRepository.isValidUsername( name ) ) { - throw new InvalidArgumentsException( "User name contains illegal characters. Please use simple ascii characters and numbers." ); + throw new InvalidArgumentsException( + "User name '" + name + + "' contains illegal characters. Use simple ascii characters and numbers." ); } } diff --git a/community/security/src/main/java/org/neo4j/server/security/auth/BasicAuthSubject.java b/community/security/src/main/java/org/neo4j/server/security/auth/BasicAuthSubject.java index a50b9be063f87..d873ab7bfde1e 100644 --- a/community/security/src/main/java/org/neo4j/server/security/auth/BasicAuthSubject.java +++ b/community/security/src/main/java/org/neo4j/server/security/auth/BasicAuthSubject.java @@ -97,6 +97,11 @@ public void setPassword( String password ) throws IOException, InvalidArgumentsE } } + public BasicAuthManager getAuthManager() + { + return authManager; + } + public boolean doesUsernameMatch( String username ) { return user.name().equals( username ); @@ -135,6 +140,6 @@ public AuthorizationViolationException onViolation( String msg ) @Override public String name() { - return accessMode.name(); + return user.name(); } } diff --git a/community/security/src/main/java/org/neo4j/server/security/auth/UserManager.java b/community/security/src/main/java/org/neo4j/server/security/auth/UserManager.java index 9ebe2849bdc0c..95dcc5f6af76a 100644 --- a/community/security/src/main/java/org/neo4j/server/security/auth/UserManager.java +++ b/community/security/src/main/java/org/neo4j/server/security/auth/UserManager.java @@ -20,6 +20,7 @@ package org.neo4j.server.security.auth; import java.io.IOException; +import java.util.Set; import org.neo4j.kernel.api.security.exception.InvalidArgumentsException; @@ -33,4 +34,6 @@ User newUser( String username, String initialPassword, boolean requirePasswordCh User getUser( String username ) throws InvalidArgumentsException; void setUserPassword( String username, String password ) throws IOException, InvalidArgumentsException; + + Set getAllUsernames(); } diff --git a/community/security/src/test/java/org/neo4j/server/security/auth/AuthProceduresIT.java b/community/security/src/test/java/org/neo4j/server/security/auth/AuthProceduresIT.java new file mode 100644 index 0000000000000..a2d7c88f6a060 --- /dev/null +++ b/community/security/src/test/java/org/neo4j/server/security/auth/AuthProceduresIT.java @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2002-2016 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.server.security.auth; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.graphdb.ResourceIterator; +import org.neo4j.graphdb.Transaction; +import org.neo4j.graphdb.config.Setting; +import org.neo4j.graphdb.factory.GraphDatabaseSettings; +import org.neo4j.graphdb.mockfs.EphemeralFileSystemAbstraction; +import org.neo4j.kernel.api.KernelTransaction; +import org.neo4j.kernel.api.security.exception.InvalidArgumentsException; +import org.neo4j.kernel.api.security.exception.InvalidAuthTokenException; +import org.neo4j.kernel.internal.GraphDatabaseAPI; +import org.neo4j.test.TestGraphDatabaseBuilder; +import org.neo4j.test.TestGraphDatabaseFactory; + +import static junit.framework.TestCase.fail; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.neo4j.helpers.collection.MapUtil.map; +import static org.neo4j.kernel.api.security.AuthenticationResult.PASSWORD_CHANGE_REQUIRED; + +public class AuthProceduresIT +{ + static final String PWD_CHANGE = PASSWORD_CHANGE_REQUIRED.name().toLowerCase(); + + protected GraphDatabaseAPI db; + private EphemeralFileSystemAbstraction fs; + private BasicAuthManager authManager; + private BasicAuthSubject admin; + + //---------- change password ----------- + + @Test + public void shouldChangePassword() throws Throwable + { + + // Given + assertEmpty( admin, "CALL dbms.changePassword('abc')" ); + + assert( authManager.getUser( "neo4j" ).credentials().matchesPassword( "abc" ) ); + } + + @Test + public void shouldNotChangeOwnPasswordIfNewPasswordInvalid() throws Exception + { + assertFail( admin, "CALL dbms.changePassword( '' )", "Password cannot be empty." ); + assertFail( admin, "CALL dbms.changePassword( 'neo4j' )", "Old password and new password cannot be the same." ); + } + + //---------- create user ----------- + + @Test + public void shouldCreateUser() throws Exception + { + assertEmpty( admin, "CALL dbms.communityAuth.createUser('andres', '123', true)" ); + try + { + authManager.getUser( "andres" ); + } + catch ( Throwable t ) + { + fail( "Expected no exception!" ); + } + } + + @Test + public void shouldNotCreateUserIfInvalidUsername() throws Exception + { + assertFail( admin, "CALL dbms.communityAuth.createUser('', '1234', true)", "The provided user name is empty." ); + assertFail( admin, "CALL dbms.communityAuth.createUser('&%ss!', '1234', true)", + "User name '&%ss!' contains illegal characters." ); + assertFail( admin, "CALL dbms.communityAuth.createUser('&%ss!', '', true)", "User name '&%ss!' contains illegal characters." ); + } + + @Test + public void shouldNotCreateUserIfInvalidPassword() throws Exception + { + assertFail( admin, "CALL dbms.communityAuth.createUser('andres', '', true)", "Password cannot be empty." ); + } + + @Test + public void shouldNotCreateExistingUser() throws Exception + { + assertFail( admin, "CALL dbms.communityAuth.createUser('neo4j', '1234', true)", + "The specified user already exists" ); + assertFail( admin, "CALL dbms.communityAuth.createUser('neo4j', '', true)", "Password cannot be empty." ); + } + + //---------- delete user ----------- + + @Test + public void shouldDeleteUser() throws Exception + { + authManager.newUser( "andres", "123", false ); + assertEmpty( admin, "CALL dbms.communityAuth.deleteUser('andres')" ); + try + { + authManager.getUser( "andres" ); + fail("Andres should no longer exist, expected exception."); + } + catch ( InvalidArgumentsException e ) + { + assertThat( e.getMessage(), containsString( "User 'andres' does not exist." ) ); + } + catch ( Throwable t ) + { + assertThat( t.getClass(), equalTo( InvalidArgumentsException.class ) ); + } + } + + @Test + public void shouldNotDeleteNonExistentUser() throws Exception + { + assertFail( admin, "CALL dbms.communityAuth.deleteUser('nonExistentUser')", "User 'nonExistentUser' does not exist" ); + } + + //---------- list users ----------- + + @Test + public void shouldListUsers() throws Exception + { + authManager.newUser( "andres", "123", false ); + assertSuccess( admin, "CALL dbms.communityAuth.listUsers() YIELD username", + r -> assertKeyIs( r, "username", "neo4j", "andres" ) ); + } + + @Test + public void shouldReturnUsersWithFlags() throws Exception + { + authManager.newUser( "andres", "123", false ); + Map expected = map( + "neo4j", listOf( PWD_CHANGE ), + "andres", listOf() + ); + assertSuccess( admin, "CALL dbms.communityAuth.listUsers()", + r -> assertKeyIsMap( r, "username", "flags", expected ) ); + } + + @Test + public void shouldShowCurrentUser() throws Exception + { + assertSuccess( admin, "CALL dbms.communityAuth.showCurrentUser()", + r -> assertKeyIsMap( r, "username", "flags", map( "neo4j", listOf( PWD_CHANGE ) ) ) ); + + authManager.newUser( "andres", "123", false ); + BasicAuthSubject andres = login( "andres", "123" ); + assertSuccess( andres, "CALL dbms.communityAuth.showCurrentUser()", + r -> assertKeyIsMap( r, "username", "flags", map( "andres", listOf() ) ) ); + } + + //---------- utility ----------- + + @Before + public void setup() throws InvalidAuthTokenException + { + fs = new EphemeralFileSystemAbstraction(); + db = (GraphDatabaseAPI) createGraphDatabase( fs ); + authManager = db.getDependencyResolver().resolveDependency( BasicAuthManager.class ); + admin = login( "neo4j", "neo4j" ); + } + + @After + public void cleanup() throws Exception + { + db.shutdown(); + fs.shutdown(); + } + + protected GraphDatabaseService createGraphDatabase( EphemeralFileSystemAbstraction fs ) + { + + Map, String> settings = new HashMap<>(); + settings.put( GraphDatabaseSettings.auth_enabled, "true" ); + settings.put( GraphDatabaseSettings.auth_manager, "basic-auth-manager" ); + + TestGraphDatabaseBuilder graphDatabaseFactory = (TestGraphDatabaseBuilder) new TestGraphDatabaseFactory() + .setFileSystem( fs ) + .newImpermanentDatabaseBuilder() + .setConfig( GraphDatabaseSettings.auth_enabled, "true" ) + .setConfig( GraphDatabaseSettings.auth_manager, "basic-auth-manager" ); + + return graphDatabaseFactory.newGraphDatabase(); + } + + protected BasicAuthSubject login( String username, String password ) throws InvalidAuthTokenException + { + return authManager.login( SecurityTestUtils.authToken( username, password ) ); + } + + private void assertEmpty( BasicAuthSubject subject, String query ) + { + assertThat( + execute( subject, query, r -> { assert(!r.hasNext() ); } ), + equalTo( "" ) ); + } + + private void assertFail( BasicAuthSubject subject, String query, String partOfErrorMsg ) + { + assertThat( + execute( subject, query, r -> { assert(!r.hasNext() ); } ), + containsString( partOfErrorMsg ) ); + } + + void assertSuccess( BasicAuthSubject subject, String query, + Consumer>> resultConsumer ) + { + assertThat( + execute( subject, query, resultConsumer ), + equalTo( "" ) ); + } + + private String execute( BasicAuthSubject subject, String query, + Consumer>> resultConsumer ) + { + try ( Transaction tx = db.beginTransaction( KernelTransaction.Type.implicit, subject ) ) + { + resultConsumer.accept( db.execute( query ) ); + tx.success(); + return ""; + } + catch ( Exception e ) + { + return e.getMessage(); + } + } + + List getObjectsAsList( ResourceIterator> r, String key ) + { + return r.stream().map( s -> s.get( key ) ).collect( Collectors.toList() ); + } + + void assertKeyIs( ResourceIterator> r, String key, String... items ) + { + assertKeyIsArray( r, key, items ); + } + + void assertKeyIsArray( ResourceIterator> r, String key, String[] items ) + { + List results = getObjectsAsList( r, key ); + assertEquals( Arrays.asList( items ).size(), results.size() ); + Assert.assertThat( results, containsInAnyOrder( items ) ); + } + + protected void assertKeyIsMap( ResourceIterator> r, String keyKey, String valueKey, Map expected ) + { + List> result = r.stream().collect( Collectors.toList() ); + + assertEquals( "Results for should have size " + expected.size() + " but was " + result.size(), + expected.size(), result.size() ); + + for ( Map row : result ) + { + String key = (String) row.get( keyKey ); + assertTrue( "Unexpected key '" + key + "'", expected.containsKey( key ) ); + + assertTrue( "Value key '" + valueKey + "' not found in results", row.containsKey( valueKey ) ); + Object objectValue = row.get( valueKey ); + if ( objectValue instanceof List ) + { + List value = (List) objectValue; + List expectedValues = (List) expected.get( key ); + assertEquals( "Results for '" + key + "' should have size " + expectedValues.size() + " but was " + + value.size(), value.size(), expectedValues.size() ); + assertThat( value, containsInAnyOrder( expectedValues.toArray() ) ); + } + else + { + String value = objectValue.toString(); + String expectedValue = expected.get( key ).toString(); + assertTrue( + String.format( "Wrong value for '%s', expected '%s', got '%s'", key, expectedValue, value), + value.equals( expectedValue ) + ); + } + } + } + + protected String[] with( String[] strs, String... moreStr ) + { + return Stream.concat( Arrays.stream(strs), Arrays.stream( moreStr ) ).toArray( String[]::new ); + } + + protected List listOf( String... values ) + { + return Stream.of( values ).collect( Collectors.toList() ); + } +} diff --git a/community/security/src/test/java/org/neo4j/server/security/auth/AuthProceduresTest.java b/community/security/src/test/java/org/neo4j/server/security/auth/AuthProceduresTest.java index 4754f3610d739..d68c3c66643c8 100644 --- a/community/security/src/test/java/org/neo4j/server/security/auth/AuthProceduresTest.java +++ b/community/security/src/test/java/org/neo4j/server/security/auth/AuthProceduresTest.java @@ -39,39 +39,39 @@ public class AuthProceduresTest extends KernelIntegrationTest { @Test - public void callChangePasswordWithAccessModeInDbmsMode() throws Throwable + public void callChangePasswordWithAccessModeInDbmsMode() throws Throwable + { + // Given + Object[] inputArray = new Object[1]; + inputArray[0] = "newPassword"; + AuthSubject authSubject = mock( AuthSubject.class ); + + // When + RawIterator stream = dbmsOperations( authSubject ) + .procedureCallDbms( procedureName( "dbms", "changePassword" ), inputArray ); + + // Then + verify( authSubject ).setPassword( (String) inputArray[0] ); + assertThat( asList( stream ), emptyIterable() ); + } + + @Test + public void shouldFailWhenChangePasswordWithStaticAccessModeInDbmsMode() throws Throwable + { + try { // Given Object[] inputArray = new Object[1]; inputArray[0] = "newPassword"; - AuthSubject authSubject = mock( AuthSubject.class ); // When - RawIterator stream = dbmsOperations( authSubject ) - .procedureCallDbms( procedureName( "dbms", "changePassword" ), inputArray ); - - // Then - verify( authSubject ).setPassword( (String) inputArray[0] ); - assertThat( asList( stream ), emptyIterable() ); + dbmsOperations( AccessMode.Static.NONE ).procedureCallDbms( procedureName( "dbms", "changePassword" ), inputArray ); + fail( "Should have failed." ); } - - @Test - public void shouldFailWhenChangePasswordWithStaticAccessModeInDbmsMode() throws Throwable + catch ( Exception e ) { - try - { - // Given - Object[] inputArray = new Object[1]; - inputArray[0] = "newPassword"; - - // When - dbmsOperations( AccessMode.Static.NONE ).procedureCallDbms( procedureName( "dbms", "changePassword" ), inputArray ); - fail( "Should have failed." ); - } - catch ( Exception e ) - { - // Then - assertThat( e.getClass(), equalTo( ProcedureException.class ) ); - } + // Then + assertThat( e.getClass(), equalTo( ProcedureException.class ) ); } + } } 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 b565f8bf1d53e..f97ec85da3659 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 @@ -19,6 +19,8 @@ */ package org.neo4j.server.security.auth; +import junit.framework.TestCase; +import org.hamcrest.core.IsEqual; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -30,6 +32,7 @@ import org.neo4j.kernel.api.security.exception.InvalidArgumentsException; import org.neo4j.kernel.api.security.exception.InvalidAuthTokenException; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -149,13 +152,25 @@ public void shouldDeleteUser() throws Throwable } @Test - public void shouldDeleteUnknownUser() throws Throwable + public void shouldFailToDeleteUnknownUser() throws Throwable { // Given manager.newUser( "jake", "abc123", true ); - // When - manager.deleteUser( "unknown" ); + try + { + // When + manager.deleteUser( "nonExistentUser" ); + TestCase.fail("User 'nonExistentUser' should no longer exist, expected exception."); + } + catch ( InvalidArgumentsException e ) + { + assertThat( e.getMessage(), containsString( "User 'nonExistentUser' does not exist." ) ); + } + catch ( Throwable t ) + { + assertThat( t.getClass(), IsEqual.equalTo( InvalidArgumentsException.class ) ); + } // Then assertNotNull( users.getUserByName( "jake" ) ); diff --git a/community/server/src/test/java/org/neo4j/server/rest/dbms/AuthorizationFilterTest.java b/community/server/src/test/java/org/neo4j/server/rest/dbms/AuthorizationFilterTest.java index 14a6b9f3adfd3..0def973b09737 100644 --- a/community/server/src/test/java/org/neo4j/server/rest/dbms/AuthorizationFilterTest.java +++ b/community/server/src/test/java/org/neo4j/server/rest/dbms/AuthorizationFilterTest.java @@ -39,6 +39,7 @@ import org.neo4j.kernel.api.security.AuthenticationResult; import org.neo4j.logging.AssertableLogProvider; import org.neo4j.server.security.auth.BasicAuthManager; +import org.neo4j.server.security.auth.BasicAuthSubject; import static javax.servlet.http.HttpServletRequest.BASIC_AUTH; @@ -167,7 +168,7 @@ public void shouldNotAuthorizeInvalidCredentials() throws Exception // Given final AuthorizationEnabledFilter filter = new AuthorizationEnabledFilter( () -> authManager, logProvider ); String credentials = Base64.encodeBase64String( "foo:bar".getBytes( StandardCharsets.UTF_8 ) ); - AuthSubject authSubject = mock( AuthSubject.class ); + BasicAuthSubject authSubject = mock( BasicAuthSubject.class ); when( servletRequest.getMethod() ).thenReturn( "GET" ); when( servletRequest.getContextPath() ).thenReturn( "/db/data" ); when( servletRequest.getHeader( HttpHeaders.AUTHORIZATION ) ).thenReturn( "BASIC " + credentials ); @@ -195,7 +196,7 @@ public void shouldAuthorizeWhenPasswordChangeRequiredForWhitelistedPath() throws // Given final AuthorizationEnabledFilter filter = new AuthorizationEnabledFilter( () -> authManager, logProvider ); String credentials = Base64.encodeBase64String( "foo:bar".getBytes( StandardCharsets.UTF_8 ) ); - AuthSubject authSubject = mock( AuthSubject.class ); + BasicAuthSubject authSubject = mock( BasicAuthSubject.class ); when( servletRequest.getMethod() ).thenReturn( "GET" ); when( servletRequest.getContextPath() ).thenReturn( "/user/foo" ); when( servletRequest.getHeader( HttpHeaders.AUTHORIZATION ) ).thenReturn( "BASIC " + credentials ); @@ -216,7 +217,7 @@ public void shouldNotAuthorizeWhenPasswordChangeRequired() throws Exception // Given final AuthorizationEnabledFilter filter = new AuthorizationEnabledFilter( () -> authManager, logProvider ); String credentials = Base64.encodeBase64String( "foo:bar".getBytes( StandardCharsets.UTF_8 ) ); - AuthSubject authSubject = mock( AuthSubject.class ); + BasicAuthSubject authSubject = mock( BasicAuthSubject.class ); when( servletRequest.getMethod() ).thenReturn( "GET" ); when( servletRequest.getContextPath() ).thenReturn( "/db/data" ); when( servletRequest.getRequestURL() ).thenReturn( new StringBuffer( "http://bar.baz:7474/db/data/" ) ); @@ -243,7 +244,7 @@ public void shouldNotAuthorizeWhenTooManyAttemptsMade() throws Exception // Given final AuthorizationEnabledFilter filter = new AuthorizationEnabledFilter( () -> authManager, logProvider ); String credentials = Base64.encodeBase64String( "foo:bar".getBytes( StandardCharsets.UTF_8 ) ); - AuthSubject authSubject = mock( AuthSubject.class ); + BasicAuthSubject authSubject = mock( BasicAuthSubject.class ); when( servletRequest.getMethod() ).thenReturn( "GET" ); when( servletRequest.getContextPath() ).thenReturn( "/db/data" ); when( servletRequest.getHeader( HttpHeaders.AUTHORIZATION ) ).thenReturn( "BASIC " + credentials ); @@ -267,7 +268,7 @@ public void shouldAuthorizeWhenValidCredentialsSupplied() throws Exception // Given final AuthorizationEnabledFilter filter = new AuthorizationEnabledFilter( () -> authManager, logProvider ); String credentials = Base64.encodeBase64String( "foo:bar".getBytes( StandardCharsets.UTF_8 ) ); - AuthSubject authSubject = mock( AuthSubject.class ); + BasicAuthSubject authSubject = mock( BasicAuthSubject.class ); when( servletRequest.getMethod() ).thenReturn( "GET" ); when( servletRequest.getContextPath() ).thenReturn( "/db/data" ); when( servletRequest.getHeader( HttpHeaders.AUTHORIZATION ) ).thenReturn( "BASIC " + credentials ); 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 df736d0666a03..77b4087a025d1 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 @@ -31,8 +31,6 @@ public interface EnterpriseUserManager extends UserManager void activateUser( String username ) throws IOException, InvalidArgumentsException; - Set getAllUsernames(); - RoleRecord newRole( String roleName, String... usernames ) throws IOException, InvalidArgumentsException; RoleRecord getRole( String roleName ) throws InvalidArgumentsException;