@Override public boolean credentialsExpired() { return loginContext.subject().getAuthenticationResult() == org.neo4j.internal.kernel.api.security.AuthenticationResult.PASSWORD_CHANGE_REQUIRED; } }
public void assertCredentialsNotExpired() { if ( subject().getAuthenticationResult().equals( AuthenticationResult.PASSWORD_CHANGE_REQUIRED ) ) { throw mode().onViolation( PERMISSION_DENIED ); } }
@Test public void shouldAuthorizeWhenPasswordChangeRequiredForWhitelistedPath() throws Exception { // Given final AuthorizationEnabledFilter filter = new AuthorizationEnabledFilter( () -> authManager, logProvider ); String credentials = Base64.encodeBase64String( "foo:bar".getBytes( StandardCharsets.UTF_8 ) ); BasicLoginContext loginContext = mock( BasicLoginContext.class ); AuthSubject authSubject = mock( AuthSubject.class ); when( servletRequest.getMethod() ).thenReturn( "GET" ); when( servletRequest.getContextPath() ).thenReturn( "/user/foo" ); when( servletRequest.getHeader( HttpHeaders.AUTHORIZATION ) ).thenReturn( "BASIC " + credentials ); when( authManager.login( authTokenArgumentMatcher( authToken( "foo", "bar" ) ) ) ).thenReturn( loginContext ); when( loginContext.subject() ).thenReturn( authSubject ); when( authSubject.getAuthenticationResult() ).thenReturn( AuthenticationResult.PASSWORD_CHANGE_REQUIRED ); // When filter.doFilter( servletRequest, servletResponse, filterChain ); // Then verify( filterChain ).doFilter( eq( new AuthorizedRequestWrapper( BASIC_AUTH, "foo", servletRequest, AUTH_DISABLED ) ), same( servletResponse ) ); }
@Test public void shouldAuthorizeWhenValidCredentialsSupplied() throws Exception { // Given final AuthorizationEnabledFilter filter = new AuthorizationEnabledFilter( () -> authManager, logProvider ); String credentials = Base64.encodeBase64String( "foo:bar".getBytes( StandardCharsets.UTF_8 ) ); BasicLoginContext loginContext = mock( BasicLoginContext.class ); AuthSubject authSubject = mock( AuthSubject.class ); when( servletRequest.getMethod() ).thenReturn( "GET" ); when( servletRequest.getContextPath() ).thenReturn( "/db/data" ); when( servletRequest.getHeader( HttpHeaders.AUTHORIZATION ) ).thenReturn( "BASIC " + credentials ); when( authManager.login( authTokenArgumentMatcher( authToken( "foo", "bar" ) ) ) ).thenReturn( loginContext ); when( loginContext.subject() ).thenReturn( authSubject ); when( authSubject.getAuthenticationResult() ).thenReturn( AuthenticationResult.SUCCESS ); // When filter.doFilter( servletRequest, servletResponse, filterChain ); // Then verify( filterChain ).doFilter( eq( new AuthorizedRequestWrapper( BASIC_AUTH, "foo", servletRequest, AUTH_DISABLED ) ), same( servletResponse ) ); }
@Test public void shouldNotAuthorizeWhenTooManyAttemptsMade() throws Exception { // Given final AuthorizationEnabledFilter filter = new AuthorizationEnabledFilter( () -> authManager, logProvider ); String credentials = Base64.encodeBase64String( "foo:bar".getBytes( StandardCharsets.UTF_8 ) ); BasicLoginContext loginContext = mock( BasicLoginContext.class ); AuthSubject authSubject = mock( AuthSubject.class ); when( servletRequest.getMethod() ).thenReturn( "GET" ); when( servletRequest.getContextPath() ).thenReturn( "/db/data" ); when( servletRequest.getHeader( HttpHeaders.AUTHORIZATION ) ).thenReturn( "BASIC " + credentials ); when( authManager.login( authTokenArgumentMatcher( authToken( "foo", "bar" ) ) ) ).thenReturn( loginContext ); when( loginContext.subject() ).thenReturn( authSubject ); when( authSubject.getAuthenticationResult() ).thenReturn( AuthenticationResult.TOO_MANY_ATTEMPTS ); // When filter.doFilter( servletRequest, servletResponse, filterChain ); // Then verifyNoMoreInteractions( filterChain ); verify( servletResponse ).setStatus( 429 ); verify( servletResponse ).addHeader( HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8" ); assertThat( outputStream.toString( StandardCharsets.UTF_8.name() ), containsString( "\"code\" : \"Neo.ClientError.Security.AuthenticationRateLimit\"" ) ); assertThat( outputStream.toString( StandardCharsets.UTF_8.name() ), containsString( "\"message\" : \"Too many failed authentication requests. " + "Please wait 5 seconds and try again.\"" ) ); }
@Test public void shouldNotAuthorizeWhenPasswordChangeRequired() throws Exception { // Given final AuthorizationEnabledFilter filter = new AuthorizationEnabledFilter( () -> authManager, logProvider ); String credentials = Base64.encodeBase64String( "foo:bar".getBytes( StandardCharsets.UTF_8 ) ); BasicLoginContext loginContext = mock( BasicLoginContext.class ); AuthSubject authSubject = mock( AuthSubject.class ); when( servletRequest.getMethod() ).thenReturn( "GET" ); when( servletRequest.getContextPath() ).thenReturn( "/db/data" ); when( servletRequest.getRequestURL() ).thenReturn( new StringBuffer( "http://bar.baz:7474/db/data/" ) ); when( servletRequest.getRequestURI() ).thenReturn( "/db/data/" ); when( servletRequest.getHeader( HttpHeaders.AUTHORIZATION ) ).thenReturn( "BASIC " + credentials ); when( authManager.login( authTokenArgumentMatcher( authToken( "foo", "bar" ) ) ) ).thenReturn( loginContext ); when( loginContext.subject() ).thenReturn( authSubject ); when( authSubject.getAuthenticationResult() ).thenReturn( AuthenticationResult.PASSWORD_CHANGE_REQUIRED ); // When filter.doFilter( servletRequest, servletResponse, filterChain ); // Then verifyNoMoreInteractions( filterChain ); verify( servletResponse ).setStatus( 403 ); verify( servletResponse ).addHeader( HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8" ); assertThat( outputStream.toString( StandardCharsets.UTF_8.name() ), containsString( "\"password_change\" : \"http://bar.baz:7474/user/foo/password\"" ) ); assertThat( outputStream.toString( StandardCharsets.UTF_8.name() ), containsString( "\"code\" : \"Neo.ClientError.Security.Forbidden\"" ) ); assertThat( outputStream.toString( StandardCharsets.UTF_8.name() ), containsString( "\"message\" : \"User is required to change their password.\"" ) ); }
@Test public void shouldNotAuthorizeInvalidCredentials() throws Exception { // Given final AuthorizationEnabledFilter filter = new AuthorizationEnabledFilter( () -> authManager, logProvider ); String credentials = Base64.encodeBase64String( "foo:bar".getBytes( StandardCharsets.UTF_8 ) ); BasicLoginContext loginContext = mock( BasicLoginContext.class ); AuthSubject authSubject = mock( AuthSubject.class ); when( servletRequest.getMethod() ).thenReturn( "GET" ); when( servletRequest.getContextPath() ).thenReturn( "/db/data" ); when( servletRequest.getHeader( HttpHeaders.AUTHORIZATION ) ).thenReturn( "BASIC " + credentials ); when( servletRequest.getRemoteAddr() ).thenReturn( "remote_ip_address" ); when( authManager.login( authTokenArgumentMatcher( authToken( "foo", "bar" ) ) ) ).thenReturn( loginContext ); when( loginContext.subject() ).thenReturn( authSubject ); when( authSubject.getAuthenticationResult() ).thenReturn( AuthenticationResult.FAILURE ); // When filter.doFilter( servletRequest, servletResponse, filterChain ); // Then verifyNoMoreInteractions( filterChain ); logProvider.assertExactly( inLog( AuthorizationEnabledFilter.class ) .warn( "Failed authentication attempt for '%s' from %s", "foo", "remote_ip_address" ) ); verify( servletResponse ).setStatus( 401 ); verify( servletResponse ).addHeader( HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8" ); assertThat( outputStream.toString( StandardCharsets.UTF_8.name() ), containsString( "\"code\" : \"Neo.ClientError.Security.Unauthorized\"" ) ); assertThat( outputStream.toString( StandardCharsets.UTF_8.name() ), containsString( "\"message\" : \"Invalid username or password.\"" ) ); }
private void assertLoginGivesResult( String username, String password, AuthenticationResult expectedResult ) throws InvalidAuthTokenException { LoginContext securityContext = manager.login( authToken( username, password ) ); assertThat( securityContext.subject().getAuthenticationResult(), equalTo( expectedResult ) ); }
switch ( securityContext.subject().getAuthenticationResult() )
private AuthenticationResult doAuthenticate( Map<String,Object> authToken ) throws AuthenticationException { try { LoginContext loginContext = authManager.login( authToken ); switch ( loginContext.subject().getAuthenticationResult() ) { case SUCCESS: case PASSWORD_CHANGE_REQUIRED: break; case TOO_MANY_ATTEMPTS: throw new AuthenticationException( Status.Security.AuthenticationRateLimit ); default: throw new AuthenticationException( Status.Security.Unauthorized ); } return new BasicAuthenticationResult( loginContext ); } catch ( InvalidAuthTokenException e ) { throw new AuthenticationException( e.status(), e.getMessage() ); } }
switch ( loginContext.subject().getAuthenticationResult() )
@Override public boolean credentialsExpired() { return loginContext.subject().getAuthenticationResult() == org.neo4j.internal.kernel.api.security.AuthenticationResult.PASSWORD_CHANGE_REQUIRED; } }
public void assertCredentialsNotExpired() { if ( subject().getAuthenticationResult().equals( AuthenticationResult.PASSWORD_CHANGE_REQUIRED ) ) { throw mode().onViolation( PERMISSION_DENIED ); } }
switch ( securityContext.subject().getAuthenticationResult() )
private AuthenticationResult doAuthenticate( Map<String,Object> authToken ) throws AuthenticationException { try { LoginContext loginContext = authManager.login( authToken ); switch ( loginContext.subject().getAuthenticationResult() ) { case SUCCESS: case PASSWORD_CHANGE_REQUIRED: break; case TOO_MANY_ATTEMPTS: throw new AuthenticationException( Status.Security.AuthenticationRateLimit ); default: throw new AuthenticationException( Status.Security.Unauthorized ); } return new BasicAuthenticationResult( loginContext ); } catch ( InvalidAuthTokenException e ) { throw new AuthenticationException( e.status(), e.getMessage() ); } }
AuthenticationResult authenticationResult = securityContext.subject().getAuthenticationResult(); if ( authenticationResult == AuthenticationResult.SUCCESS )
switch ( loginContext.subject().getAuthenticationResult() )