org.phenotips.security.authorization.remote.internal.RemoteAuthorizationModuleTest.java Source code

Java tutorial

Introduction

Here is the source code for org.phenotips.security.authorization.remote.internal.RemoteAuthorizationModuleTest.java

Source

/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.phenotips.security.authorization.remote.internal;

import org.phenotips.data.Patient;
import org.phenotips.data.PatientRepository;
import org.phenotips.security.authorization.AuthorizationModule;

import org.xwiki.cache.Cache;
import org.xwiki.cache.CacheException;
import org.xwiki.cache.CacheFactory;
import org.xwiki.cache.config.CacheConfiguration;
import org.xwiki.component.manager.ComponentLookupException;
import org.xwiki.component.phase.InitializationException;
import org.xwiki.component.util.ReflectionUtils;
import org.xwiki.configuration.ConfigurationSource;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.security.authorization.Right;
import org.xwiki.test.mockito.MockitoComponentMockingRule;
import org.xwiki.users.User;

import java.io.IOException;

import org.apache.commons.httpclient.HttpStatus;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

/**
 * Tests for the {@link RemoteAuthorizationModule remote} {@link AuthorizationModule} component.
 *
 * @version $Id: 9abb783cdf4b02df512ae18c1dde7660d555de83 $
 */
public class RemoteAuthorizationModuleTest {
    @Rule
    public final MockitoComponentMockingRule<AuthorizationModule> mocker = new MockitoComponentMockingRule<AuthorizationModule>(
            RemoteAuthorizationModule.class);

    @Mock
    private User user;

    @Mock
    private Right access;

    private DocumentReference document = new DocumentReference("xwiki", "data", "P0000001");

    @Mock
    private Patient patient;

    @Mock
    private CloseableHttpClient client;

    @Mock
    private CloseableHttpResponse response;

    @Mock
    private StatusLine status;

    @Mock
    private Cache<Boolean> cache;

    private String url = "http://host.net/checkAuthorization";

    @Test(expected = InitializationException.class)
    public void noConfigurationThrowsInitializationException() throws Throwable {
        try {
            this.mocker.getComponentUnderTest().hasAccess(this.user, this.access, this.document);
        } catch (ComponentLookupException ex) {
            Assert.assertTrue(ex.getCause().getMessage().contains("requires a valid URL to be configured"));
            throw ex.getCause();
        }
    }

    @Test(expected = InitializationException.class)
    public void invalidConfigurationThrowsInitializationException() throws Throwable {
        ConfigurationSource configuration = this.mocker.getInstance(ConfigurationSource.class, "restricted");
        when(configuration.getProperty(RemoteAuthorizationModule.CONFIGURATION_KEY)).thenReturn(":NotAnURL");
        try {
            this.mocker.getComponentUnderTest().hasAccess(this.user, this.access, this.document);
        } catch (ComponentLookupException ex) {
            Assert.assertEquals("Invalid URL configured for RemoteAuthorizationModule: :NotAnURL",
                    ex.getCause().getMessage());
            throw ex.getCause();
        }
    }

    @Test(expected = InitializationException.class)
    public void cacheMisconfigurationThrowsInitializationException() throws Throwable {
        ConfigurationSource configuration = this.mocker.getInstance(ConfigurationSource.class, "restricted");
        when(configuration.getProperty(RemoteAuthorizationModule.CONFIGURATION_KEY)).thenReturn(this.url);
        CacheFactory cf = this.mocker.getInstance(CacheFactory.class, "infinispan");
        when(cf.newCache(any(CacheConfiguration.class))).thenThrow(new CacheException("Bad Cache"));
        try {
            this.mocker.getComponentUnderTest().hasAccess(this.user, this.access, this.document);
        } catch (ComponentLookupException ex) {
            Assert.assertEquals("Failed to create authorization cache: Bad Cache", ex.getCause().getMessage());
            throw ex.getCause();
        }
    }

    @Test
    public void noActionWithNullArguments() throws Exception {
        setupNeededComponents();
        Assert.assertNull(this.mocker.getComponentUnderTest().hasAccess(null, this.access, this.document));
        Assert.assertNull(this.mocker.getComponentUnderTest().hasAccess(this.user, null, this.document));
        Assert.assertNull(this.mocker.getComponentUnderTest().hasAccess(this.user, this.access, null));
    }

    @Test
    public void noActionWithNonPatient() throws Exception {
        setupNeededComponents();
        PatientRepository repo = this.mocker.getInstance(PatientRepository.class);
        when(repo.getPatientById(this.document.toString())).thenReturn(null);
        Assert.assertNull(this.mocker.getComponentUnderTest().hasAccess(this.user, this.access, this.document));
    }

    @Test
    public void hasAccessWithCachedResponse() throws Exception {
        setupNeededComponents();
        when(this.cache.get("jdoe::edit::P0000001")).thenReturn(true);
        Assert.assertTrue(this.mocker.getComponentUnderTest().hasAccess(this.user, this.access, this.document));
        when(this.cache.get("jdoe::edit::P0000001")).thenReturn(false);
        Assert.assertFalse(this.mocker.getComponentUnderTest().hasAccess(this.user, this.access, this.document));
        verify(this.client, never()).execute(any(HttpPost.class));
    }

    @Test
    public void grantsAccessWithOKResponse() throws Exception {
        setupNeededComponents();
        when(this.client.execute(any(HttpPost.class))).thenReturn(this.response);
        when(this.response.getStatusLine()).thenReturn(this.status);
        when(this.status.getStatusCode()).thenReturn(HttpStatus.SC_OK);
        Assert.assertTrue(this.mocker.getComponentUnderTest().hasAccess(this.user, this.access, this.document));
        verify(this.cache).set("jdoe::edit::P0000001", true);
        verify(this.response).close();
    }

    @Test
    public void refusesAccessWithForbiddenResponse() throws Exception {
        setupNeededComponents();
        when(this.client.execute(any(HttpPost.class))).thenReturn(this.response);
        when(this.response.getStatusLine()).thenReturn(this.status);
        when(this.status.getStatusCode()).thenReturn(HttpStatus.SC_FORBIDDEN);
        Assert.assertFalse(this.mocker.getComponentUnderTest().hasAccess(this.user, this.access, this.document));
        verify(this.cache).set("jdoe::edit::P0000001", false);
    }

    @Test
    public void noActionWithOtherResponses() throws Exception {
        setupNeededComponents();
        when(this.client.execute(any(HttpPost.class))).thenReturn(this.response);
        when(this.response.getStatusLine()).thenReturn(this.status);
        for (int i = 0; i < 600; ++i) {
            if (i == HttpStatus.SC_OK || i == HttpStatus.SC_FORBIDDEN) {
                continue;
            }
            when(this.status.getStatusCode()).thenReturn(i);
            Assert.assertNull(this.mocker.getComponentUnderTest().hasAccess(this.user, this.access, this.document));
        }
        // Other responses are not cached
        verify(this.cache, never()).set(Matchers.anyString(), Matchers.anyBoolean());
    }

    @Test
    public void noActionWithHttpExceptions() throws Exception {
        setupNeededComponents();
        when(this.client.execute(any(HttpPost.class))).thenThrow(new ClientProtocolException(), new IOException());
        Assert.assertNull(this.mocker.getComponentUnderTest().hasAccess(this.user, this.access, this.document));
        Assert.assertNull(this.mocker.getComponentUnderTest().hasAccess(this.user, this.access, this.document));
        verify(this.cache, never()).set(Matchers.anyString(), Matchers.anyBoolean());
    }

    @Test
    public void exceptionWhileClosingRequestIsIgnored() throws Exception {
        setupNeededComponents();
        when(this.client.execute(any(HttpPost.class))).thenReturn(this.response);
        when(this.response.getStatusLine()).thenReturn(this.status);
        when(this.status.getStatusCode()).thenReturn(HttpStatus.SC_OK);
        Mockito.doThrow(new IOException()).when(this.response).close();
        Assert.assertTrue(this.mocker.getComponentUnderTest().hasAccess(this.user, this.access, this.document));
        verify(this.cache).set("jdoe::edit::P0000001", true);
    }

    @Test
    public void cacheDenyHeadersRespected() throws Exception {
        setupNeededComponents();
        when(this.client.execute(any(HttpPost.class))).thenReturn(this.response);
        when(this.response.getStatusLine()).thenReturn(this.status);
        when(this.status.getStatusCode()).thenReturn(HttpStatus.SC_OK);
        Header header = mock(Header.class);
        when(this.response.getLastHeader("Cache-Control")).thenReturn(header);
        HeaderElement element = mock(HeaderElement.class);
        HeaderElement[] elements = new HeaderElement[] { element };
        when(header.getElements()).thenReturn(elements);
        when(element.getName()).thenReturn("no-cache", "no-store");
        Assert.assertTrue(this.mocker.getComponentUnderTest().hasAccess(this.user, this.access, this.document));
        Assert.assertTrue(this.mocker.getComponentUnderTest().hasAccess(this.user, this.access, this.document));
        verify(this.cache, never()).set(Matchers.anyString(), Matchers.anyBoolean());
        verify(this.cache, times(2)).remove("jdoe::edit::P0000001");
    }

    @Test
    public void otherCacheHeadersIgnored() throws Exception {
        setupNeededComponents();
        when(this.client.execute(any(HttpPost.class))).thenReturn(this.response);
        when(this.response.getStatusLine()).thenReturn(this.status);
        when(this.status.getStatusCode()).thenReturn(HttpStatus.SC_OK);
        Header header = mock(Header.class);
        when(this.response.getLastHeader("Cache-Control")).thenReturn(header);
        HeaderElement element = mock(HeaderElement.class);
        HeaderElement[] elements = new HeaderElement[] { element };
        when(header.getElements()).thenReturn(elements);
        when(element.getName()).thenReturn("public");
        Assert.assertTrue(this.mocker.getComponentUnderTest().hasAccess(this.user, this.access, this.document));
        verify(this.cache).set("jdoe::edit::P0000001", true);
    }

    @Test
    public void expectedPriority() throws Exception {
        setupNeededComponents();
        Assert.assertEquals(500, this.mocker.getComponentUnderTest().getPriority());
    }

    private void setupNeededComponents() throws ComponentLookupException, CacheException {
        MockitoAnnotations.initMocks(this);

        ConfigurationSource configuration = this.mocker.getInstance(ConfigurationSource.class, "restricted");
        when(configuration.getProperty(RemoteAuthorizationModule.CONFIGURATION_KEY)).thenReturn(this.url);

        CacheFactory cf = this.mocker.getInstance(CacheFactory.class, "infinispan");
        when(cf.<Boolean>newCache(any(CacheConfiguration.class))).thenReturn(this.cache);
        ReflectionUtils.setFieldValue(this.mocker.getComponentUnderTest(), "client", this.client);

        PatientRepository repo = this.mocker.getInstance(PatientRepository.class);
        when(repo.getPatientById(this.document.toString())).thenReturn(this.patient);

        when(this.user.getUsername()).thenReturn("jdoe");
        when(this.patient.getId()).thenReturn("P0000001");
        when(this.patient.getExternalId()).thenReturn("P_1234");
        when(this.access.getName()).thenReturn("edit");
    }
}