Skip to content

Commit

Permalink
Pass region and AWS credentials with AWS API requests (#92)
Browse files Browse the repository at this point in the history
* Require POST object containing region and credentials for all requests

Specifically adds a POST body requirement for the getKinesisSteams and getLogGroupNames methods.

* Use snake_case for paths

* Update region api call (#110)

* Migrate Regions request from a list to a full response object with total

* Update Region API call to include label and value

* Reformat code
  • Loading branch information
Dan Torrey authored and bernd committed Jun 25, 2019
1 parent f1bc2fb commit 5012a68
Show file tree
Hide file tree
Showing 16 changed files with 360 additions and 200 deletions.
100 changes: 63 additions & 37 deletions src/main/java/org/graylog/integrations/aws/resources/AWSResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,29 @@
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.graylog.integrations.aws.service.KinesisService;
import org.graylog.integrations.aws.service.CloudWatchService;
import org.graylog.integrations.aws.resources.requests.AWSRequestImpl;
import org.graylog.integrations.aws.resources.requests.KinesisHealthCheckRequest;
import org.graylog.integrations.aws.resources.responses.AvailableAWSServiceSummmary;
import org.graylog.integrations.aws.resources.responses.KinesisHealthCheckResponse;
import org.graylog.integrations.aws.resources.responses.RegionResponse;
import org.graylog.integrations.aws.resources.responses.AvailableServiceResponse;
import org.graylog.integrations.aws.resources.responses.HealthCheckResponse;
import org.graylog.integrations.aws.resources.responses.LogGroupsResponse;
import org.graylog.integrations.aws.resources.responses.RegionsResponse;
import org.graylog.integrations.aws.resources.responses.StreamsResponse;
import org.graylog.integrations.aws.service.AWSService;
import org.graylog.integrations.aws.service.CloudWatchService;
import org.graylog.integrations.aws.service.KinesisService;
import org.graylog2.plugin.rest.PluginRestResource;

import javax.inject.Inject;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.ExecutionException;

/**
Expand Down Expand Up @@ -55,36 +56,62 @@ public AWSResource(AWSService awsService, KinesisService kinesisService, CloudWa
@Timed
@Path("/regions")
@ApiOperation(value = "Get all available AWS regions")
public List<RegionResponse> getAwsRegions() {
public RegionsResponse getAwsRegions() {
return awsService.getAvailableRegions();
}

@GET
@Timed
@Path("/availableServices")
@Path("/available_services")
@ApiOperation(value = "Get all available AWS services")
public AvailableAWSServiceSummmary getAvailableServices() {
public AvailableServiceResponse getAvailableServices() {
return awsService.getAvailableServices();
}

// TODO: Rework to accept a form post body with credentials
@GET
/**
* Get all available AWS CloudWatch log groups names for the specified region.
*
* Example request:
* curl 'http://user:pass@localhost:9000/api/plugins/org.graylog.integrations/aws/cloudWatch/logGroups' \
* -X POST \
* -H 'X-Requested-By: XMLHttpRequest' \
* -H 'Content-Type: application/json' \
* -H 'Accept: application/json' \
* --data-binary '{
* "region": "us-east-1",
* "aws_access_key_id": "some-key",
* "aws_secret_access_key": "some-secret"
* }'
*/
@POST
@Timed
@Path("/cloudWatch/logGroups/{regionName}")
@ApiOperation(value = "Get all available AWS CloudWatch log groups names for the specified region")
public List<String> getLogGroupNames(@ApiParam(name = "regionName", required = true)
@PathParam("regionName") String regionName) {
return cloudWatchService.getLogGroupNames(regionName);
@Path("/cloudwatch/log_groups")
@ApiOperation(value = "Get all available AWS CloudWatch log groups names for the specified region.")
public LogGroupsResponse getLogGroupNames(@ApiParam(name = "JSON body", required = true) @Valid @NotNull AWSRequestImpl awsRequest) {
return cloudWatchService.getLogGroupNames(awsRequest.region(), awsRequest.awsAccessKeyId(), awsRequest.awsSecretAccessKey());
}

// TODO: Rework to accept a form post body with credentials
@GET
/**
* Get all available Kinesis streams for the specified region.
*
* Example request:
* curl 'http://user:pass@localhost:9000/api/plugins/org.graylog.integrations/aws/kinesis/streams' \
* -X POST \
* -H 'X-Requested-By: XMLHttpRequest' \
* -H 'Content-Type: application/json' \
* -H 'Accept: application/json' \
* --data-binary '{
* "region": "us-east-1",
* "aws_access_key_id": "some-key",
* "aws_secret_access_key": "some-secret"
* }'
*/
@POST
@Timed
@Path("/kinesis/streams/{regionName}")
@ApiOperation(value = "Get all available AWS Kinesis streams for the specified region")
public List<String> getKinesisStreams(@ApiParam(name = "regionName", required = true)
@PathParam("regionName") String regionName) throws ExecutionException {
return kinesisService.getKinesisStreams(regionName, null, null);
@Path("/kinesis/streams")
@ApiOperation(value = "Get all available Kinesis streams for the specified region.")
public StreamsResponse getKinesisStreams(@ApiParam(name = "JSON body", required = true) @Valid @NotNull AWSRequestImpl awsRequest) throws ExecutionException {
return kinesisService.getKinesisStreamNames(awsRequest.region(), awsRequest.awsAccessKeyId(), awsRequest.awsSecretAccessKey());
}

/**
Expand All @@ -93,29 +120,28 @@ public List<String> getKinesisStreams(@ApiParam(name = "regionName", required =
* Sample CURL command for executing this method. Use this to model the UI request.
* Note the --data-binary param that includes the put body JSON with region and AWS credentials.
*
* curl 'http://someuser:somepass@localhost:9000/api/plugins/org.graylog.integrations/aws/kinesis/healthCheck' \
* -X PUT \
* curl 'http://user:pass@localhost:9000/api/plugins/org.graylog.integrations/aws/kinesis/healthCheck' \
* -X POST \
* -H 'X-Requested-By: XMLHttpRequest' \
* -H 'Content-Type: application/json' \
* -H 'Accept: application/json' \
* --data-binary '{
* "region": "us-east-1",
* "aws_access_key_id": "some-key",
* "aws_secret_access_key": "some-secret",
* "stream_name": "a-stream",
* "log_group_name": "a-log-group"
* "region": "us-east-1",
* "aws_access_key_id": "some-key",
* "aws_secret_access_key": "some-secret",
* "stream_name": "a-stream",
* "log_group_name": "a-log-group"
* }'
*
*/
@PUT
@POST
@Timed
@Path("/kinesis/healthCheck")
@Path("/kinesis/health_check")
@ApiOperation(
value = "Attempt to retrieve logs from the indicated AWS log group with the specified credentials.",
response = KinesisHealthCheckResponse.class
response = HealthCheckResponse.class
)
public Response kinesisHealthCheck(@ApiParam(name = "JSON body", required = true) @Valid @NotNull KinesisHealthCheckRequest heathCheckRequest) throws ExecutionException, IOException {
KinesisHealthCheckResponse response = kinesisService.healthCheck(heathCheckRequest);
HealthCheckResponse response = kinesisService.healthCheck(heathCheckRequest);
return Response.accepted().entity(response).build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.graylog.integrations.aws.resources.requests;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.auto.value.AutoValue;
import org.graylog.autovalue.WithBeanGetter;

/**
* A common implementation on AWSRequest, which can be used for any AWS request that just needs region and credentials.
*/
@JsonAutoDetect
@AutoValue
@WithBeanGetter
public abstract class AWSRequestImpl implements AWSRequest {

@JsonProperty(REGION)
public abstract String region();

@JsonProperty(AWS_ACCESS_KEY_ID)
public abstract String awsAccessKeyId();

@JsonProperty(AWS_SECRET_ACCESS_KEY)
public abstract String awsSecretAccessKey();

@JsonCreator
public static AWSRequestImpl create(@JsonProperty(REGION) String region,
@JsonProperty(AWS_ACCESS_KEY_ID) String awsAccessKeyId,
@JsonProperty(AWS_SECRET_ACCESS_KEY) String awsSecretAccessKey) {
return new AutoValue_AWSRequestImpl(region, awsAccessKeyId, awsSecretAccessKey);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.graylog.integrations.aws.resources.responses;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.auto.value.AutoValue;
import org.graylog.autovalue.WithBeanGetter;

@JsonAutoDetect
@AutoValue
@WithBeanGetter
public abstract class AWSRegion {

private static final String VALUE = "value";
private static final String LABEL = "label";

// eu-west-2
@JsonProperty(VALUE)
public abstract String regionId();

// The combination of both the name and description for display in the UI:
// EU (London): eu-west-2
@JsonProperty(LABEL)
public abstract String displayValue();

public static AWSRegion create(@JsonProperty(VALUE) String value,
@JsonProperty(LABEL) String label) {
return new AutoValue_AWSRegion(value, label);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
@JsonAutoDetect
@AutoValue
@WithBeanGetter
public abstract class AvailableAWSService {
public abstract class AvailableService {

private static final String NAME = "name";
private static final String DESCRIPTION = "description";
Expand All @@ -31,11 +31,11 @@ public abstract class AvailableAWSService {
@JsonProperty(LEARN_MORE_LINK)
public abstract String LearnMoreLink();

public static AvailableAWSService create(@JsonProperty(NAME) String name,
@JsonProperty(DESCRIPTION) String description,
@JsonProperty(POLICY) String policy,
@JsonProperty(HELPER_TEXT) String helperText,
@JsonProperty(LEARN_MORE_LINK) String LearnMoreLink) {
return new AutoValue_AvailableAWSService(name, description, policy, helperText, LearnMoreLink);
public static AvailableService create(@JsonProperty(NAME) String name,
@JsonProperty(DESCRIPTION) String description,
@JsonProperty(POLICY) String policy,
@JsonProperty(HELPER_TEXT) String helperText,
@JsonProperty(LEARN_MORE_LINK) String LearnMoreLink) {
return new AutoValue_AvailableService(name, description, policy, helperText, LearnMoreLink);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@
@JsonAutoDetect
@AutoValue
@WithBeanGetter
public abstract class AvailableAWSServiceSummmary {
public abstract class AvailableServiceResponse {

private static final String SERVICES = "services";
private static final String TOTAL = "total";

@JsonProperty(SERVICES)
public abstract List<AvailableAWSService> services();
public abstract List<AvailableService> services();

@JsonProperty(TOTAL)
public abstract long total();

public static AvailableAWSServiceSummmary create(@JsonProperty(SERVICES) List<AvailableAWSService> services,
@JsonProperty(TOTAL) long total) {
return new AutoValue_AvailableAWSServiceSummmary(services, total);
public static AvailableServiceResponse create(@JsonProperty(SERVICES) List<AvailableService> services,
@JsonProperty(TOTAL) long total) {
return new AutoValue_AvailableServiceResponse(services, total);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
@JsonAutoDetect
@AutoValue
@WithBeanGetter
public abstract class KinesisHealthCheckResponse {
public abstract class HealthCheckResponse {

private static final String SUCCESS = "success";
private static final String LOG_TYPE = "log_type";
Expand All @@ -36,10 +36,10 @@ public abstract class KinesisHealthCheckResponse {
@JsonProperty(MESSAGE_SUMMARY)
public abstract String messageSummary();

public static KinesisHealthCheckResponse create(@JsonProperty(SUCCESS) boolean success,
@JsonProperty(LOG_TYPE) String logType,
@JsonProperty(EXPLANATION) String explanation,
@JsonProperty(MESSAGE_SUMMARY) String messageSummary) {
return new AutoValue_KinesisHealthCheckResponse(success, logType, explanation, messageSummary);
public static HealthCheckResponse create(@JsonProperty(SUCCESS) boolean success,
@JsonProperty(LOG_TYPE) String logType,
@JsonProperty(EXPLANATION) String explanation,
@JsonProperty(MESSAGE_SUMMARY) String messageSummary) {
return new AutoValue_HealthCheckResponse(success, logType, explanation, messageSummary);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.graylog.integrations.aws.resources.responses;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.auto.value.AutoValue;
import org.graylog.autovalue.WithBeanGetter;

import java.util.List;

@JsonAutoDetect
@AutoValue
@WithBeanGetter
public abstract class LogGroupsResponse {

private static final String LOG_GROUPS = "log_groups";
private static final String TOTAL = "total";

@JsonProperty(LOG_GROUPS)
public abstract List<String> logGroups();

@JsonProperty(TOTAL)
public abstract long total();

public static LogGroupsResponse create(@JsonProperty(LOG_GROUPS) List<String> logGroups,
@JsonProperty(TOTAL) long total) {
return new AutoValue_LogGroupsResponse(logGroups, total);
}
}

This file was deleted.

Loading

0 comments on commit 5012a68

Please sign in to comment.