package org.zaproxy.zap.users; import static org.hamcrest.CoreMatchers.anyOf; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.greaterThan; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; import org.parosproxy.paros.network.HttpMessage; import org.zaproxy.zap.authentication.AuthenticationCredentials; import org.zaproxy.zap.authentication.AuthenticationMethod; import org.zaproxy.zap.authentication.AuthenticationMethodType; import org.zaproxy.zap.extension.authentication.ExtensionAuthentication; import org.zaproxy.zap.model.Context; import org.zaproxy.zap.session.SessionManagementMethod; import org.zaproxy.zap.session.WebSession; @RunWith(MockitoJUnitRunner.class) public class UserUnitTest { private static final String USER_NAME = "username"; private static int CONTEXT_ID = 23; private static ExtensionAuthentication mockedExtension; private static AuthenticationMethodType mockedType; private static AuthenticationMethod mockedAuthenticationMethod; private static Context mockedContext; private static AuthenticationCredentials mockedCredentials; private static SessionManagementMethod mockedSessionManagementMethod; @BeforeClass public static void classSetUp() { // Make sure something is returned for the encoder mockedCredentials = Mockito.mock(AuthenticationCredentials.class); when(mockedCredentials.encode(anyString())).thenReturn("[credentials]"); // Make sure fake identifier is returned and mocked credentials (for encoding) mockedType = Mockito.mock(AuthenticationMethodType.class); when(mockedType.getUniqueIdentifier()).thenReturn(99); when(mockedType.createAuthenticationCredentials()).thenReturn(mockedCredentials); // Make sure mocked type is returned (for encoding) and no actual authentication is done mockedAuthenticationMethod = Mockito.mock(AuthenticationMethod.class); when(mockedAuthenticationMethod.getType()).thenReturn(mockedType); when( mockedAuthenticationMethod.authenticate((SessionManagementMethod) anyObject(), (AuthenticationCredentials) anyObject(), (User) anyObject())).thenReturn( Mockito.mock(WebSession.class)); // Make sure no actual message processing is done mockedSessionManagementMethod = Mockito.mock(SessionManagementMethod.class); doNothing().when(mockedSessionManagementMethod).processMessageToMatchSession( (HttpMessage) anyObject(), (WebSession) anyObject()); // Make sure mocked session management and authentication methods are returned mockedContext = Mockito.mock(Context.class); when(mockedContext.getAuthenticationMethod()).thenReturn(mockedAuthenticationMethod); when(mockedContext.getSessionManagementMethod()).thenReturn(mockedSessionManagementMethod); // Make sure mocked type is returned for identifier mockedExtension = Mockito.mock(ExtensionAuthentication.class); when(mockedExtension.getAuthenticationMethodTypeForIdentifier(anyInt())).thenReturn(mockedType); } @Test public void shouldEncodeAndDecodeProperly() { // Given User user = spy(new User(CONTEXT_ID, USER_NAME)); user.setAuthenticationCredentials(mockedCredentials); doReturn(mockedContext).when(user).getContext(); // When String encoded = User.encode(user); User result = User.decode(CONTEXT_ID, encoded, mockedExtension); // Then assertEquals(user.getName(), result.getName()); assertEquals(user.isEnabled(), result.isEnabled()); assertEquals(user.getId(), result.getId()); assertEquals(user.getContextId(), result.getContextId()); } @SuppressWarnings("unchecked") @Test public void shouldGenerateUniqueIds() { // Given User u1 = new User(CONTEXT_ID, USER_NAME); User u2 = new User(CONTEXT_ID, USER_NAME); User u3 = new User(CONTEXT_ID, USER_NAME); User u4 = new User(CONTEXT_ID, USER_NAME); // When/Then assertThat(u1.getId(), not(anyOf(is(u2.getId()), is(u3.getId()), is(u4.getId())))); assertThat(u2.getId(), not(anyOf(is(u3.getId()), is(u4.getId())))); assertThat(u3.getId(), not(is(u4.getId()))); User u5 = new User(CONTEXT_ID, USER_NAME, u4.getId() + 5); User u6 = new User(CONTEXT_ID, USER_NAME); assertThat(u6.getId(), greaterThan(u5.getId())); } @Test public void shouldRequireAuthenticationAfterInitialization() { // Given User u = new User(CONTEXT_ID, USER_NAME); // When/Then assertTrue(u.requiresAuthentication()); } @Test public void shouldRequireAuthenticationAfterAuthentication() { // Given User u = new User(CONTEXT_ID, USER_NAME); // When u.setAuthenticatedSession(Mockito.mock(WebSession.class)); // Then assertFalse(u.requiresAuthentication()); } @Test public void shouldRequireAuthenticationAfterResetWithNewerMessage() { // Given User u = spy(new User(CONTEXT_ID, USER_NAME)); u.setAuthenticatedSession(Mockito.mock(WebSession.class)); doReturn(3500l).when(u).getLastSuccessfulAuthTime(); // When HttpMessage msg = Mockito.mock(HttpMessage.class); when(msg.getTimeSentMillis()).thenReturn(5000l); u.queueAuthentication(msg); // Then assertTrue(u.requiresAuthentication()); } @Test public void shouldRequireAuthenticationAfterResetWithOlderMessage() { // Given User u = spy(new User(CONTEXT_ID, USER_NAME)); u.setAuthenticatedSession(Mockito.mock(WebSession.class)); doReturn(3500l).when(u).getLastSuccessfulAuthTime(); // When HttpMessage msg = Mockito.mock(HttpMessage.class); when(msg.getTimeSentMillis()).thenReturn(3200l); u.queueAuthentication(msg); // Then verify(msg).getTimeSentMillis(); assertFalse(u.requiresAuthentication()); } @Test public void shouldAuthenticateWhenRequired() { // Given User user = spy(new User(CONTEXT_ID, USER_NAME)); doReturn(mockedContext).when(user).getContext(); // When doReturn(true).when(user).requiresAuthentication(); doNothing().when(user).authenticate(); user.processMessageToMatchUser(Mockito.mock(HttpMessage.class)); // Then verify(user).authenticate(); } @Test public void shouldNotAuthenticateIfNotRequired() { // Given User user = spy(new User(CONTEXT_ID, USER_NAME)); doReturn(mockedContext).when(user).getContext(); // When doReturn(false).when(user).requiresAuthentication(); doNothing().when(user).authenticate(); user.processMessageToMatchUser(Mockito.mock(HttpMessage.class)); // Then verify(user, never()).authenticate(); } @Test public void shouldNotRequireAuthenticationAfterAuthentication() { // Given User user = spy(new User(CONTEXT_ID, USER_NAME)); doReturn(mockedContext).when(user).getContext(); // When user.authenticate(); // Then assertFalse(user.requiresAuthentication()); } }