package org.simbasecurity.dwclient.gateway; import com.google.common.base.Optional; import com.sun.jersey.spi.container.ContainerRequest; import org.apache.thrift.TException; import org.apache.thrift.transport.THttpClient; import org.apache.thrift.transport.TTransportException; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.mockito.Mock; import org.mockito.internal.util.reflection.Whitebox; import org.simbasecurity.api.service.thrift.ActionDescriptor; import org.simbasecurity.api.service.thrift.ActionType; import org.simbasecurity.api.service.thrift.AuthenticationFilterService.Client; import org.simbasecurity.api.service.thrift.RequestData; import org.simbasecurity.api.service.thrift.SSOToken; import org.simbasecurity.dwclient.dropwizard.credentials.SimbaCredentials; import org.simbasecurity.dwclient.dropwizard.credentials.SimbaCredentialsBuilderForTests; import org.simbasecurity.dwclient.dropwizard.credentials.SimbaCredentialsFactory; import org.simbasecurity.dwclient.dropwizard.credentials.SimbaPrincipal; import org.simbasecurity.dwclient.exception.SimbaUnavailableException; import org.simbasecurity.dwclient.test.rule.MockitoRule; import org.simbasecurity.dwclient.test.stub.simba.ActionDescriptorBuilderForTests; import java.net.SocketException; import static org.fest.assertions.api.Assertions.assertThat; import static org.mockito.Mockito.*; import static org.simbasecurity.dwclient.gateway.SimbaGateway.*; public class SimbaGatewayTest { @Rule public MockitoRule mockitoRule = MockitoRule.create(); @Rule public ExpectedException expectedException = ExpectedException.none(); private static final String SIMBA_WEB_URL = "http://simba.wayneindustries.com/simba"; @Mock private SimbaServiceFactory simbaServiceFactoryMock; @Mock private SimbaCredentialsFactory simbaCredentialsFactoryMock; private SimbaGateway simbaGateway; @Before public void setUp() { simbaGateway = new SimbaGateway(SIMBA_WEB_URL, simbaServiceFactoryMock, simbaCredentialsFactoryMock); } @Test public void createAuthenticationService_WhenConnectionWithSimbaFails_ThrowsSimbaUnavailableException() throws Exception { when(simbaServiceFactoryMock.createTHttpClient(SIMBA_WEB_URL + "/" + SIMBA_AUTHENTICATION_SERVICE)).thenThrow(new TTransportException()); expectedException.expect(SimbaUnavailableException.class); simbaGateway.createAuthenticationService(); } @Test public void createAuthenticationService_WhenConnectionToSimbaEstablished_ReturnsClient() throws Exception { Client expectedClient = setupSimbaServiceToReturnASimbaAuthenticationService(); Client actual = simbaGateway.createAuthenticationService(); assertThat(actual).isEqualTo(expectedClient); } @Test public void createAuthenticationService_WhenTHttpClientIsNotOpen_ReturnsClientByEstablishingANewConnection() throws Exception { Client originalClient = mock(Client.class); THttpClient tHttpClientMock = mock(THttpClient.class); Whitebox.setInternalState(simbaGateway, "tHttpClient", tHttpClientMock); Whitebox.setInternalState(simbaGateway, "authenticationFilterService", originalClient); THttpClient newlyCreatedTHttpClient = new THttpClient(SIMBA_WEB_URL); when(simbaServiceFactoryMock.createTHttpClient(SIMBA_WEB_URL + "/" + SIMBA_AUTHENTICATION_SERVICE)).thenReturn(newlyCreatedTHttpClient); Client expectedClient = new Client(null); when(simbaServiceFactoryMock.createJSONAuthenticationFilterService(newlyCreatedTHttpClient)).thenReturn(expectedClient); when(tHttpClientMock.isOpen()).thenReturn(false); Client actual = simbaGateway.createAuthenticationService(); assertThat(actual).isEqualTo(expectedClient); verify(simbaServiceFactoryMock, times(1)).createTHttpClient(SIMBA_WEB_URL + "/" + SIMBA_AUTHENTICATION_SERVICE); verify(simbaServiceFactoryMock, times(1)).createJSONAuthenticationFilterService(any(THttpClient.class)); } @Test public void authenticate_WhenAuthenticationCallWentWrong_ThrowsSimbaUnavailableException() throws Exception { SimbaCredentials credentials = mock(SimbaCredentials.class); RequestData requestData = mock(RequestData.class); when(credentials.asRequestData()).thenReturn(requestData); Client authenticationServiceMock = setupSimbaServiceToReturnASimbaAuthenticationService(); when(authenticationServiceMock.processRequest(requestData, SESSION_AUTHENTICATE_CHAIN)).thenThrow(new TException()); expectedException.expect(SimbaUnavailableException.class); simbaGateway.authenticate(credentials); } @Test public void authenticate_WhenPrincipalWasSet_ReturnPrincipal() throws Exception { SimbaCredentials credentials = mock(SimbaCredentials.class); RequestData requestData = mock(RequestData.class); when(credentials.asRequestData()).thenReturn(requestData); Client authenticationServiceMock = setupSimbaServiceToReturnASimbaAuthenticationService(); String principal = "simbaUsername"; String token = "token"; ActionDescriptor actionDescriptor = new ActionDescriptorBuilderForTests() .withActionTypes(ActionType.DO_FILTER_AND_SET_PRINCIPAL) .withPrincipal(principal) .withSsoToken(new SSOToken(token)) .build(); when(authenticationServiceMock.processRequest(requestData, SESSION_AUTHENTICATE_CHAIN)).thenReturn(actionDescriptor); Optional<SimbaPrincipal> simbaPrincipal = simbaGateway.authenticate(credentials); assertThat(simbaPrincipal.get()).isEqualTo(new SimbaPrincipal(principal, token)); } @Test public void authenticate_WhenPrincipalWasNotSet_ReturnsAbsentPrincipal() throws Exception { SimbaCredentials credentials = mock(SimbaCredentials.class); RequestData requestData = mock(RequestData.class); when(credentials.asRequestData()).thenReturn(requestData); Client authenticationServiceMock = setupSimbaServiceToReturnASimbaAuthenticationService(); String principal = "simbaUsername"; String ssoToken = "ssotoken"; ActionDescriptor actionDescriptor = new ActionDescriptorBuilderForTests() .withActionTypes(ActionType.ADD_PARAMETER_TO_TARGET) .withPrincipal(principal) .withSsoToken(new SSOToken(ssoToken)) .build(); when(authenticationServiceMock.processRequest(requestData, SimbaGateway.SESSION_AUTHENTICATE_CHAIN)).thenReturn(actionDescriptor); Optional<SimbaPrincipal> simbaPrincipal = simbaGateway.authenticate(credentials); assertThat(simbaPrincipal.isPresent()).isFalse(); } @Test public void authenticate_WhenClientIsABrowser_ExecuteBrowserLoginChain() throws Exception { SimbaCredentials credentials = mock(SimbaCredentials.class); when(credentials.isClientABrowser()).thenReturn(true); Client authenticationServiceMock = setupSimbaServiceToReturnASimbaAuthenticationService(); simbaGateway.authenticate(credentials); verify(authenticationServiceMock).processRequest(any(RequestData.class), eq(SimbaGateway.SESSION_AUTHENTICATE_CHAIN)); } @Test public void authenticate_WhenClientIsNotABrowser_ExecuteWsLoginChain() throws Exception { SimbaCredentials credentials = mock(SimbaCredentials.class); when(credentials.isClientABrowser()).thenReturn(false); Client authenticationServiceMock = setupSimbaServiceToReturnASimbaAuthenticationService(); simbaGateway.authenticate(credentials); verify(authenticationServiceMock).processRequest(any(RequestData.class), eq(SimbaGateway.SESSION_AUTHENTICATE_CHAIN)); } @Test public void authenticate_THttpClientAlwaysGetsClosed() throws Exception { Client expectedClient = mock(Client.class); THttpClient tHttpClientMock = mock(THttpClient.class); when(simbaServiceFactoryMock.createTHttpClient(SIMBA_WEB_URL + "/" + SIMBA_AUTHENTICATION_SERVICE)).thenReturn(tHttpClientMock); when(simbaServiceFactoryMock.createJSONAuthenticationFilterService(tHttpClientMock)).thenReturn(expectedClient); Client authenticationServiceMock = expectedClient; when(authenticationServiceMock.processRequest(any(RequestData.class), eq(SimbaGateway.SESSION_AUTHENTICATE_CHAIN))) .thenReturn(new ActionDescriptorBuilderForTests().withActionTypes().build()); simbaGateway.authenticate(new SimbaCredentialsBuilderForTests().build()); verify(tHttpClientMock, times(1)).close(); } @Test public void authenticate_THttpClientEvenGetsClosedAfterAnExceptionOccurred() throws Exception { Client expectedClient = mock(Client.class); THttpClient tHttpClientMock = mock(THttpClient.class); when(simbaServiceFactoryMock.createTHttpClient(SIMBA_WEB_URL + SIMBA_AUTHENTICATION_SERVICE)).thenReturn(tHttpClientMock); when(simbaServiceFactoryMock.createJSONAuthenticationFilterService(tHttpClientMock)).thenReturn(expectedClient); Client authenticationServiceMock = expectedClient; when(authenticationServiceMock.processRequest(any(RequestData.class), any(String.class))).thenThrow(new TException()); expectedException.expect(SimbaUnavailableException.class); simbaGateway.authenticate(new SimbaCredentialsBuilderForTests().build()); verify(tHttpClientMock, times(1)).close(); } @Test public void login() throws Exception { Client authenticationServicemock = setupSimbaServiceToReturnASimbaAuthenticationService(); ContainerRequest containerRequestMock = mock(ContainerRequest.class); SimbaCredentials simbaCredentials = mock(SimbaCredentials.class); RequestData requestData = mock(RequestData.class); SSOToken expectedSSOToken = new SSOToken("token"); ActionDescriptor actionDescriptor = new ActionDescriptorBuilderForTests() .withActionTypes(ActionType.MAKE_COOKIE) .withSsoToken(expectedSSOToken) .build(); when(simbaCredentialsFactoryMock.create(containerRequestMock, false)).thenReturn(simbaCredentials); when(simbaCredentials.asRequestData()).thenReturn(requestData); when(authenticationServicemock.processRequest(requestData, LOGIN_AUTHENTICATE_CHAIN)).thenReturn(actionDescriptor); Optional<String> actualSSOToken = simbaGateway.login(containerRequestMock); assertThat(actualSSOToken.isPresent()).isTrue(); assertThat(actualSSOToken.get()).isEqualTo(expectedSSOToken.getToken()); } @Test public void login_WhenActionDescriptorActionTypesIsNull_ThenReturnsEmptySSOToken() throws Exception { Client authenticationServicemock = setupSimbaServiceToReturnASimbaAuthenticationService(); ContainerRequest containerRequestMock = mock(ContainerRequest.class); SimbaCredentials simbaCredentials = mock(SimbaCredentials.class); RequestData requestData = mock(RequestData.class); ActionDescriptor actionDescriptor = new ActionDescriptorBuilderForTests().build(); when(simbaCredentialsFactoryMock.create(containerRequestMock, false)).thenReturn(simbaCredentials); when(simbaCredentials.asRequestData()).thenReturn(requestData); when(authenticationServicemock.processRequest(requestData, LOGIN_AUTHENTICATE_CHAIN)).thenReturn(actionDescriptor); Optional<String> ssoToken = simbaGateway.login(containerRequestMock); assertThat(ssoToken.isPresent()).isFalse(); } @Test public void login_WhenActionDescriptorActionTypesIsEmpty_ThenReturnsEmptySSOToken() throws Exception { Client authenticationServicemock = setupSimbaServiceToReturnASimbaAuthenticationService(); ContainerRequest containerRequestMock = mock(ContainerRequest.class); SimbaCredentials simbaCredentials = mock(SimbaCredentials.class); RequestData requestData = mock(RequestData.class); ActionDescriptor actionDescriptor = new ActionDescriptorBuilderForTests().withActionTypes().build(); when(simbaCredentialsFactoryMock.create(containerRequestMock, false)).thenReturn(simbaCredentials); when(simbaCredentials.asRequestData()).thenReturn(requestData); when(authenticationServicemock.processRequest(requestData, LOGIN_AUTHENTICATE_CHAIN)).thenReturn(actionDescriptor); Optional<String> ssoToken = simbaGateway.login(containerRequestMock); assertThat(ssoToken.isPresent()).isFalse(); } @Test public void login_WhenActionDescriptorMissesMAKECOOKIE_ReturnsEmptySSOToken() throws Exception { Client authenticationServicemock = setupSimbaServiceToReturnASimbaAuthenticationService(); ContainerRequest containerRequestMock = mock(ContainerRequest.class); SimbaCredentials simbaCredentials = mock(SimbaCredentials.class); RequestData requestData = mock(RequestData.class); ActionDescriptor actionDescriptor = new ActionDescriptorBuilderForTests().withActionTypes(ActionType.REDIRECT).build(); when(simbaCredentialsFactoryMock.create(containerRequestMock, false)).thenReturn(simbaCredentials); when(simbaCredentials.asRequestData()).thenReturn(requestData); when(authenticationServicemock.processRequest(requestData, LOGIN_AUTHENTICATE_CHAIN)).thenReturn(actionDescriptor); Optional<String> ssoToken = simbaGateway.login(containerRequestMock); assertThat(ssoToken.isPresent()).isFalse(); } @Test public void login_WithUsernameAndPassword() throws Exception { String username = "appUser"; String password = "appPassword"; Client authenticationServicemock = setupSimbaServiceToReturnASimbaAuthenticationService(); SimbaCredentials simbaCredentials = mock(SimbaCredentials.class); RequestData requestData = mock(RequestData.class); SSOToken ssoToken = new SSOToken("token"); ActionDescriptor actionDescriptor = new ActionDescriptorBuilderForTests() .withActionTypes(ActionType.MAKE_COOKIE) .withSsoToken(ssoToken) .build(); when(simbaCredentialsFactoryMock.createForLogin(username, password)).thenReturn(simbaCredentials); when(simbaCredentials.asRequestData()).thenReturn(requestData); when(authenticationServicemock.processRequest(requestData, LOGIN_AUTHENTICATE_CHAIN)).thenReturn(actionDescriptor); Optional<String> actual = simbaGateway.login(username, password); assertThat(actual.get()).isEqualTo(ssoToken.getToken()); } @Test public void logout() throws Exception { Client authenticationServicemock = setupSimbaServiceToReturnASimbaAuthenticationService(); ContainerRequest containerRequestMock = mock(ContainerRequest.class); SimbaCredentials simbaCredentials = mock(SimbaCredentials.class); RequestData requestData = mock(RequestData.class); when(simbaCredentialsFactoryMock.create(containerRequestMock, true)).thenReturn(simbaCredentials); when(simbaCredentials.asRequestData()).thenReturn(requestData); simbaGateway.logout(containerRequestMock); verify(authenticationServicemock).processRequest(requestData, LOGOUT_CHAIN); } @Test public void isSimbaAlive_WhenTHttpFlushThrewSocketException_ReturnFalse() throws Exception { when(simbaServiceFactoryMock.createTHttpClient(SIMBA_WEB_URL + "/" + SIMBA_AUTHENTICATION_SERVICE)).thenThrow( new TTransportException(new SocketException())); assertThat(simbaGateway.isSimbaAlive()).isFalse(); } @Test public void isSimbaAlive_WhenTHttpCouldFlushWithoutSocketException_ReturnTrue() throws Exception { when(simbaServiceFactoryMock.createTHttpClient(SIMBA_WEB_URL + "/" + SIMBA_AUTHENTICATION_SERVICE)).thenThrow( new TTransportException("HTTP Response code: 404")); assertThat(simbaGateway.isSimbaAlive()).isTrue(); } private Client setupSimbaServiceToReturnASimbaAuthenticationService() throws TTransportException { Client expectedClient = mock(Client.class); THttpClient tHttpClientMock = mock(THttpClient.class); when(simbaServiceFactoryMock.createTHttpClient(SIMBA_WEB_URL + "/" + SIMBA_AUTHENTICATION_SERVICE)).thenReturn(tHttpClientMock); when(simbaServiceFactoryMock.createJSONAuthenticationFilterService(tHttpClientMock)).thenReturn(expectedClient); return expectedClient; } }