package keywhiz.service.resources.automation.v2;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableSet;
import io.dropwizard.jackson.Jackson;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.Set;
import keywhiz.IntegrationTestRule;
import keywhiz.KeywhizService;
import keywhiz.TestClients;
import keywhiz.api.automation.v2.ClientDetailResponseV2;
import keywhiz.api.automation.v2.CreateClientRequestV2;
import keywhiz.api.automation.v2.CreateGroupRequestV2;
import keywhiz.api.automation.v2.ModifyClientRequestV2;
import keywhiz.api.automation.v2.ModifyGroupsRequestV2;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.rules.RuleChain;
import static java.lang.String.format;
import static javax.ws.rs.core.HttpHeaders.LOCATION;
import static keywhiz.TestClients.clientRequest;
import static keywhiz.client.KeywhizClient.JSON;
import static org.assertj.core.api.Assertions.assertThat;
public class ClientResourceTest {
private static final ObjectMapper mapper = KeywhizService.customizeObjectMapper(Jackson.newObjectMapper());
OkHttpClient mutualSslClient;
@ClassRule public static final RuleChain chain = IntegrationTestRule.rule();
@Before public void setUp() {
mutualSslClient = TestClients.mutualSslClient();
}
@Test public void createClient_success() throws Exception {
Response httpResponse = create(CreateClientRequestV2.builder().name("client1").build());
assertThat(httpResponse.code()).isEqualTo(201);
URI location = URI.create(httpResponse.header(LOCATION));
assertThat(location.getPath()).isEqualTo("/automation/v2/clients/client1");
}
@Test public void createClient_duplicate() throws Exception {
CreateClientRequestV2 request = CreateClientRequestV2.builder().name("client2").build();
// Initial request OK
create(request);
// Duplicate request fails
Response httpResponse = create(request);
assertThat(httpResponse.code()).isEqualTo(409);
}
@Test public void clientInfo_notFound() throws Exception {
Request get = clientRequest("/automation/v2/clients/non-existent").get().build();
Response httpResponse = mutualSslClient.newCall(get).execute();
assertThat(httpResponse.code()).isEqualTo(404);
}
@Test public void clientInfo_groupExists() throws Exception {
// Sample client
create(CreateClientRequestV2.builder().name("client3").build());
ClientDetailResponseV2 clientDetail = lookup("client3");
assertThat(clientDetail.name()).isEqualTo("client3");
assertThat(clientDetail.description()).isEmpty();
assertThat(clientDetail.createdBy()).isEqualTo(clientDetail.updatedBy()).isEqualTo("client");
}
@Test public void clientListing() throws Exception {
Set<String> clientsBefore = listing();
Set<String> expected = ImmutableSet.<String>builder()
.addAll(clientsBefore)
.add("client4")
.build();
create(CreateClientRequestV2.builder().name("client4").build());
assertThat(listing()).containsAll(expected);
}
@Test public void clientDelete_success() throws Exception {
// Sample client
create(CreateClientRequestV2.builder().name("to-delete").build());
// Deleting is successful
Response httpResponse = delete("to-delete");
assertThat(httpResponse.code()).isEqualTo(204);
// Deleting again produces not-found
httpResponse = delete("to-delete");
assertThat(httpResponse.code()).isEqualTo(404);
}
@Test public void clientDelete_notFound() throws Exception {
Response httpResponse = delete("non-existent");
assertThat(httpResponse.code()).isEqualTo(404);
}
@Test public void clientGroupsListing_notFound() throws Exception {
Request get = clientRequest("/automation/v2/clients/non-existent/groups").get().build();
Response httpResponse = mutualSslClient.newCall(get).execute();
assertThat(httpResponse.code()).isEqualTo(404);
}
@Test public void clientGroupsListing_nonExistingGroup() throws Exception {
create(CreateClientRequestV2.builder().name("client5").groups("non-existent").build());
assertThat(groupListing("client5")).isEmpty();
}
@Test public void clientGroupsListing_groupExists() throws Exception {
// Sample group and client
createGroup("group6");
create(CreateClientRequestV2.builder().name("client6").groups("group6").build());
assertThat(groupListing("client6")).containsOnly("group6");
}
@Test public void clientSecretsListing_notFound() throws Exception {
Request get = clientRequest("/automation/v2/clients/non-existent/secrets").get().build();
Response httpResponse = mutualSslClient.newCall(get).execute();
assertThat(httpResponse.code()).isEqualTo(404);
}
@Ignore
@Test public void clientSecretsListing_secretExists() throws Exception {
createGroup("group7");
// TODO: create secret 'secret7' in group 'group7'
create(CreateClientRequestV2.builder().name("client7").groups("group7").build());
assertThat(secretListing("client7")).containsOnly("secret7");
}
@Test public void modifyClientGroups_notFound() throws Exception {
ModifyGroupsRequestV2 request = ModifyGroupsRequestV2.builder().build();
RequestBody body = RequestBody.create(JSON, mapper.writeValueAsString(request));
Request put = clientRequest("/automation/v2/clients/non-existent/groups").put(body).build();
Response httpResponse = mutualSslClient.newCall(put).execute();
assertThat(httpResponse.code()).isEqualTo(404);
}
@Test public void modifyClientGroups_success() throws Exception {
// Create sample client and groups
createGroup("group8a");
createGroup("group8b");
createGroup("group8c");
create(CreateClientRequestV2.builder().name("client8").groups("group8a", "group8b").build());
// Modify client
ModifyGroupsRequestV2 request = ModifyGroupsRequestV2.builder()
.addGroups("group8c", "non-existent1")
.removeGroups("group8a", "non-existent2")
.build();
List<String> groups = modifyGroups("client8", request);
assertThat(groups).containsOnly("group8b", "group8c");
}
@Test public void modifyClient_notFound() throws Exception {
ModifyClientRequestV2 request = ModifyClientRequestV2.forName("non-existent");
RequestBody body = RequestBody.create(JSON, mapper.writeValueAsString(request));
Request post = clientRequest("/automation/v2/clients/non-existent").post(body).build();
Response httpResponse = mutualSslClient.newCall(post).execute();
assertThat(httpResponse.code()).isEqualTo(404);
}
@Ignore
@Test public void modifyClient_success() throws Exception {
// Create sample client
create(CreateClientRequestV2.builder().name("client9").build());
ClientDetailResponseV2 originalClient = lookup("client9");
// Modify client
ModifyClientRequestV2 request = ModifyClientRequestV2.forName("client9b");
ClientDetailResponseV2 clientDetail = modify("client9", request);
assertThat(clientDetail.name()).isEqualTo("client9b");
assertThat(clientDetail).isEqualToIgnoringGivenFields(originalClient, "name", "updateDate");
assertThat(clientDetail.updatedAtSeconds()).isGreaterThan(originalClient.updatedAtSeconds());
}
private Response createGroup(String name) throws IOException {
GroupResourceTest groupResourceTest = new GroupResourceTest();
groupResourceTest.mutualSslClient = mutualSslClient;
return groupResourceTest.create(CreateGroupRequestV2.builder().name(name).build());
}
Response create(CreateClientRequestV2 request) throws IOException {
RequestBody body = RequestBody.create(JSON, mapper.writeValueAsString(request));
Request post = clientRequest("/automation/v2/clients").post(body).build();
return mutualSslClient.newCall(post).execute();
}
ClientDetailResponseV2 lookup(String client) throws IOException {
Request get = clientRequest("/automation/v2/clients/" + client).get().build();
Response httpResponse = mutualSslClient.newCall(get).execute();
assertThat(httpResponse.code()).isEqualTo(200);
return mapper.readValue(httpResponse.body().byteStream(), ClientDetailResponseV2.class);
}
Set<String> listing() throws IOException {
Request get = clientRequest("/automation/v2/clients").get().build();
Response httpResponse = mutualSslClient.newCall(get).execute();
assertThat(httpResponse.code()).isEqualTo(200);
return mapper.readValue(httpResponse.body().byteStream(), new TypeReference<Set<String>>(){});
}
ClientDetailResponseV2 modify(String client, ModifyClientRequestV2 request) throws IOException {
RequestBody body = RequestBody.create(JSON, mapper.writeValueAsString(request));
Request post = clientRequest("/automation/v2/clients/" + client).post(body).build();
Response httpResponse = mutualSslClient.newCall(post).execute();
assertThat(httpResponse.code()).isEqualTo(200);
return mapper.readValue(httpResponse.body().byteStream(), ClientDetailResponseV2.class);
}
List<String> modifyGroups(String client, ModifyGroupsRequestV2 request) throws IOException {
RequestBody body = RequestBody.create(JSON, mapper.writeValueAsString(request));
Request put = clientRequest(format("/automation/v2/clients/%s/groups", client)).put(body).build();
Response httpResponse = mutualSslClient.newCall(put).execute();
assertThat(httpResponse.code()).isEqualTo(200);
return mapper.readValue(httpResponse.body().byteStream(), new TypeReference<List<String>>(){});
}
Response delete(String name) throws IOException {
Request delete = clientRequest("/automation/v2/clients/" + name).delete().build();
return mutualSslClient.newCall(delete).execute();
}
List<String> groupListing(String client) throws IOException {
Request get = clientRequest(format("/automation/v2/clients/%s/groups", client)).get().build();
Response httpResponse = mutualSslClient.newCall(get).execute();
assertThat(httpResponse.code()).isEqualTo(200);
return mapper.readValue(httpResponse.body().byteStream(), new TypeReference<List<String>>() {
});
}
List<String> secretListing(String client) throws IOException {
Request get = clientRequest(format("/automation/v2/clients/%s/secrets", client)).get().build();
Response httpResponse = mutualSslClient.newCall(get).execute();
assertThat(httpResponse.code()).isEqualTo(200);
return mapper.readValue(httpResponse.body().byteStream(), new TypeReference<List<String>>(){});
}
}