keywhiz.service.resources.admin.SecretsResourceTest.java Source code

Java tutorial

Introduction

Here is the source code for keywhiz.service.resources.admin.SecretsResourceTest.java

Source

/*
 * Copyright (C) 2015 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package keywhiz.service.resources.admin;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import io.dropwizard.jersey.params.LongParam;
import java.net.URI;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import keywhiz.api.ApiDate;
import keywhiz.api.CreateSecretRequest;
import keywhiz.api.SecretDetailResponse;
import keywhiz.api.automation.v2.CreateOrUpdateSecretRequestV2;
import keywhiz.api.automation.v2.PartialUpdateSecretRequestV2;
import keywhiz.api.model.Client;
import keywhiz.api.model.Group;
import keywhiz.api.model.SanitizedSecret;
import keywhiz.api.model.Secret;
import keywhiz.auth.User;
import keywhiz.log.AuditLog;
import keywhiz.log.SimpleLogger;
import keywhiz.service.daos.AclDAO;
import keywhiz.service.daos.SecretController;
import keywhiz.service.daos.SecretDAO;
import keywhiz.service.exceptions.ConflictException;
import org.apache.http.HttpStatus;
import org.jooq.exception.DataAccessException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class SecretsResourceTest {
    private static final ApiDate NOW = ApiDate.now();
    private static final ApiDate NOWPLUS = new ApiDate(NOW.toEpochSecond() + 10000);

    @Rule
    public MockitoRule mockito = MockitoJUnit.rule();

    @Mock
    AclDAO aclDAO;
    @Mock
    SecretDAO secretDAO;
    @Mock
    SecretController secretController;

    User user = User.named("user");
    ImmutableMap<String, String> emptyMap = ImmutableMap.of();

    Secret secret = new Secret(22, "name", "desc", () -> "secret", "checksum", NOW, "creator", NOW, "updater",
            emptyMap, null, null, 1136214245, 1L);

    AuditLog auditLog = new SimpleLogger();

    SecretsResource resource;

    @Before
    public void setUp() {
        resource = new SecretsResource(secretController, aclDAO, secretDAO, auditLog);
    }

    @Test
    public void listSecrets() {
        SanitizedSecret secret1 = SanitizedSecret.of(1, "name1", "desc", "checksum", NOW, "user", NOW, "user",
                emptyMap, null, null, 1136214245, 125L);
        SanitizedSecret secret2 = SanitizedSecret.of(2, "name2", "desc", "checksum", NOW, "user", NOW, "user",
                emptyMap, null, null, 1136214245, 250L);
        when(secretController.getSanitizedSecrets(null, null)).thenReturn(ImmutableList.of(secret1, secret2));

        List<SanitizedSecret> response = resource.listSecrets(user);
        assertThat(response).containsOnly(secret1, secret2);
    }

    @Test
    public void listSecretsBatched() {
        SanitizedSecret secret1 = SanitizedSecret.of(1, "name1", "desc", "checksum", NOW, "user", NOW, "user",
                emptyMap, null, null, 1136214245, 125L);
        SanitizedSecret secret2 = SanitizedSecret.of(2, "name2", "desc", "checksum", NOWPLUS, "user", NOWPLUS,
                "user", emptyMap, null, null, 1136214245, 250L);
        when(secretController.getSecretsBatched(0, 1, false)).thenReturn(ImmutableList.of(secret1));
        when(secretController.getSecretsBatched(0, 1, true)).thenReturn(ImmutableList.of(secret2));
        when(secretController.getSecretsBatched(1, 1, false)).thenReturn(ImmutableList.of(secret2));

        List<SanitizedSecret> response = resource.listSecretsBatched(user, 0, 1, false);
        assertThat(response).containsOnly(secret1);

        response = resource.listSecretsBatched(user, 1, 1, false);
        assertThat(response).containsOnly(secret2);

        response = resource.listSecretsBatched(user, 0, 1, true);
        assertThat(response).containsOnly(secret2);
    }

    @Test
    public void createsSecret() throws Exception {
        when(secretController.getSecretById(secret.getId())).thenReturn(Optional.of(secret));

        SecretController.SecretBuilder secretBuilder = mock(SecretController.SecretBuilder.class);
        when(secretController.builder(secret.getName(), secret.getSecret(), user.getName(), 0))
                .thenReturn(secretBuilder);
        when(secretBuilder.create()).thenReturn(secret);

        CreateSecretRequest req = new CreateSecretRequest(secret.getName(), secret.getDescription(),
                secret.getSecret(), emptyMap, 0);
        Response response = resource.createSecret(user, req);

        assertThat(response.getStatus()).isEqualTo(201);
        assertThat(response.getMetadata().get(HttpHeaders.LOCATION))
                .containsExactly(new URI("/admin/secrets/" + secret.getId()));
    }

    @Test
    public void createOrUpdateSecret() throws Exception {
        when(secretController.getSecretById(secret.getId())).thenReturn(Optional.of(secret));

        SecretController.SecretBuilder secretBuilder = mock(SecretController.SecretBuilder.class);
        when(secretController.builder(secret.getName(), secret.getSecret(), user.getName(), 0))
                .thenReturn(secretBuilder);
        when(secretBuilder.withDescription(any())).thenReturn(secretBuilder);
        when(secretBuilder.withMetadata(any())).thenReturn(secretBuilder);
        when(secretBuilder.withType(any())).thenReturn(secretBuilder);
        when(secretBuilder.createOrUpdate()).thenReturn(secret);

        CreateOrUpdateSecretRequestV2 req = CreateOrUpdateSecretRequestV2.builder()
                .description(secret.getDescription()).content(secret.getSecret()).build();

        Response response = resource.createOrUpdateSecret(user, secret.getName(), req);

        assertThat(response.getStatus()).isEqualTo(201);
        assertThat(response.getMetadata().get(HttpHeaders.LOCATION))
                .containsExactly(new URI("/admin/secrets/" + secret.getName()));
    }

    @Test
    public void partialUpdateSecret() throws Exception {
        when(secretController.getSecretById(secret.getId())).thenReturn(Optional.of(secret));

        PartialUpdateSecretRequestV2 req = PartialUpdateSecretRequestV2.builder()
                .description(secret.getDescription()).descriptionPresent(true)
                .metadata(ImmutableMap.of("owner", "keywhizAdmin")).metadataPresent(true).expiry(1487268151L)
                .expiryPresent(true).type("test").typePresent(true).content(secret.getSecret()).contentPresent(true)
                .build();

        when(secretDAO.partialUpdateSecret(eq(secret.getName()), any(), eq(req))).thenReturn(secret.getId());

        Response response = resource.partialUpdateSecret(user, secret.getName(), req);

        assertThat(response.getStatus()).isEqualTo(201);
        assertThat(response.getMetadata().get(HttpHeaders.LOCATION))
                .containsExactly(new URI("/admin/secrets/" + secret.getName() + "/partialupdate"));
    }

    @Test
    public void listSecretVersions() {
        SanitizedSecret secret1 = SanitizedSecret.of(1, "name1", "desc", "checksum", NOW, "user", NOW, "user",
                emptyMap, null, null, 1136214245, 125L);
        SanitizedSecret secret2 = SanitizedSecret.of(1, "name1", "desc", "checksum2", NOWPLUS, "user", NOWPLUS,
                "user", emptyMap, null, null, 1136214245, 250L);

        when(secretDAO.getSecretVersionsByName("name1", 0, 10))
                .thenReturn(Optional.of(ImmutableList.of(secret2, secret1)));
        when(secretDAO.getSecretVersionsByName("name1", 1, 5)).thenReturn(Optional.of(ImmutableList.of(secret1)));
        when(secretDAO.getSecretVersionsByName("name1", 2, 10)).thenReturn(Optional.of(ImmutableList.of()));

        List<SanitizedSecret> response = resource.secretVersions(user, "name1", 0, 10);
        assertThat(response).containsExactly(secret2, secret1);

        response = resource.secretVersions(user, "name1", 1, 5);
        assertThat(response).containsExactly(secret1);

        response = resource.secretVersions(user, "name1", 2, 10);
        assertThat(response).isEmpty();
    }

    @Test(expected = NotFoundException.class)
    public void listSecretVersionsThrowsException() {
        when(secretDAO.getSecretVersionsByName(eq("name2"), anyInt(), anyInt())).thenReturn(Optional.empty());
        resource.secretVersions(user, "name2", 0, 10);
    }

    @Test
    public void rollbackSuccess() {
        Secret secret1 = new Secret(1, "name1", "desc", () -> "secret", "checksum", NOW, "user", NOW, "user",
                emptyMap, null, null, 1136214245, 125L);

        when(secretController.getSecretByName("name1")).thenReturn(Optional.of(secret1));

        Response response = resource.resetSecretVersion(user, "name1", new LongParam("125"));
        assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_CREATED);
    }

    @Test(expected = NotFoundException.class)
    public void rollbackThrowsException() {
        doThrow(new NotFoundException()).when(secretDAO).setCurrentSecretVersionByName(eq("name2"), anyLong());
        resource.resetSecretVersion(user, "name2", new LongParam("125"));
    }

    @Test
    public void canDelete() {
        when(secretController.getSecretById(0xdeadbeef)).thenReturn(Optional.of(secret));
        HashSet<Group> groups = new HashSet<>();
        groups.add(new Group(0, "group1", "", NOW, null, NOW, null, null));
        groups.add(new Group(0, "group2", "", NOW, null, NOW, null, null));
        when(aclDAO.getGroupsFor(secret)).thenReturn(groups);

        Response response = resource.deleteSecret(user, new LongParam(Long.toString(0xdeadbeef)));
        verify(secretDAO).deleteSecretsByName("name");
        assertThat(response.getStatus()).isEqualTo(204);
    }

    @Test(expected = NotFoundException.class)
    public void deleteErrorsOnNotFound() {
        when(secretController.getSecretById(0xdeadbeef)).thenReturn(Optional.empty());
        resource.deleteSecret(user, new LongParam(Long.toString(0xdeadbeef)));
    }

    @Test(expected = ConflictException.class)
    public void triesToCreateDuplicateSecret() throws Exception {
        SecretController.SecretBuilder secretBuilder = mock(SecretController.SecretBuilder.class);
        when(secretController.builder("name", "content", user.getName(), 0)).thenReturn(secretBuilder);
        DataAccessException exception = new DataAccessException("");
        doThrow(exception).when(secretBuilder).create();

        CreateSecretRequest req = new CreateSecretRequest("name", "desc", "content", emptyMap, 0);
        resource.createSecret(user, req);
    }

    @Test
    public void includesTheSecret() {
        when(secretController.getSecretById(22)).thenReturn(Optional.of(secret));
        when(aclDAO.getGroupsFor(secret)).thenReturn(Collections.emptySet());
        when(aclDAO.getClientsFor(secret)).thenReturn(Collections.emptySet());

        SecretDetailResponse response = resource.retrieveSecret(user, new LongParam("22"));

        assertThat(response.id).isEqualTo(secret.getId());
        assertThat(response.name).isEqualTo(secret.getName());
        assertThat(response.description).isEqualTo(secret.getDescription());
        assertThat(response.createdAt).isEqualTo(secret.getCreatedAt());
        assertThat(response.createdBy).isEqualTo(secret.getCreatedBy());
        assertThat(response.updatedAt).isEqualTo(secret.getUpdatedAt());
        assertThat(response.updatedBy).isEqualTo(secret.getUpdatedBy());
        assertThat(response.metadata).isEqualTo(secret.getMetadata());
    }

    @Test
    public void handlesNoAssociations() {
        when(secretController.getSecretById(22)).thenReturn(Optional.of(secret));
        when(aclDAO.getGroupsFor(secret)).thenReturn(Collections.emptySet());
        when(aclDAO.getClientsFor(secret)).thenReturn(Collections.emptySet());

        SecretDetailResponse response = resource.retrieveSecret(user, new LongParam("22"));
        assertThat(response.groups).isEmpty();
        assertThat(response.clients).isEmpty();
    }

    @Test
    public void includesAssociations() {
        Client client = new Client(0, "client", null, null, null, null, null, null, false, false);
        Group group1 = new Group(0, "group1", null, null, null, null, null, null);
        Group group2 = new Group(0, "group2", null, null, null, null, null, null);

        when(secretController.getSecretById(22)).thenReturn(Optional.of(secret));
        when(aclDAO.getGroupsFor(secret)).thenReturn(Sets.newHashSet(group1, group2));
        when(aclDAO.getClientsFor(secret)).thenReturn(Sets.newHashSet(client));

        SecretDetailResponse response = resource.retrieveSecret(user, new LongParam("22"));
        assertThat(response.groups).containsOnly(group1, group2);
        assertThat(response.clients).containsOnly(client);
    }

    @Test(expected = NotFoundException.class)
    public void badIdNotFound() {
        when(secretController.getSecretById(0xbad1d)).thenReturn(Optional.empty());
        resource.retrieveSecret(user, new LongParam(Long.toString(0xbad1d)));
    }

    @Test
    public void findSecretByNameAndVersion() {
        when(secretController.getSecretByName(secret.getName())).thenReturn(Optional.of(secret));
        assertThat(resource.retrieveSecret(user, "name")).isEqualTo(SanitizedSecret.fromSecret(secret));
    }

    @Test(expected = NotFoundException.class)
    public void badNameNotFound() {
        when(secretController.getSecretByName("non-existent")).thenReturn(Optional.empty());
        resource.retrieveSecret(user, "non-existent");
    }
}