Skip to content

Commit

Permalink
Implement basic api authorizer
Browse files Browse the repository at this point in the history
  • Loading branch information
jordansimsmith committed Sep 18, 2024
1 parent 79c1e2a commit 002aac7
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 7 deletions.
1 change: 1 addition & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ maven.install(
"software.amazon.awssdk:bom:2.26.19",
"software.amazon.awssdk:dynamodb:2.26.19",
"software.amazon.awssdk:dynamodb-enhanced:2.26.19",
"software.amazon.awssdk:iam-policy-builder:2.28.3",
"com.amazonaws:aws-lambda-java-core:1.2.3",
"com.amazonaws:aws-lambda-java-events:3.13.0",
"com.google.guava:guava:33.2.1-jre",
Expand Down
3 changes: 2 additions & 1 deletion MODULE.bazel.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions immersion_tracker_api/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,27 @@ java_library(
],
)

java_binary(
name = "auth-handler",
srcs = glob(["src/main/java/com/jordansimsmith/immersiontracker/AuthHandler.java"]),
create_executable = False,
resources = glob([
"src/main/resources/logback.xml",
]),
deps = [
":lib",
"@maven//:ch_qos_logback_logback_classic",
"@maven//:ch_qos_logback_logback_core",
"@maven//:com_amazonaws_aws_lambda_java_core",
"@maven//:com_amazonaws_aws_lambda_java_events",
"@maven//:com_fasterxml_jackson_core_jackson_core",
"@maven//:com_fasterxml_jackson_core_jackson_databind",
"@maven//:com_google_code_findbugs_jsr305",
"@maven//:com_google_guava_guava",
"@maven//:software_amazon_awssdk_iam_policy_builder",
],
)

java_binary(
name = "get-progress-handler",
srcs = glob(["src/main/java/com/jordansimsmith/immersiontracker/GetProgressHandler.java"]),
Expand Down
45 changes: 39 additions & 6 deletions immersion_tracker_api/infra/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ resource "aws_dynamodb_table" "immersion_tracker_table" {
resource "aws_secretsmanager_secret" "users" {
name = "${local.application_id}_users"
recovery_window_in_days = 0
tags = local.tags
tags = local.tags
}

data "aws_iam_policy_document" "lambda_sts_allow_policy_document" {
Expand Down Expand Up @@ -154,6 +154,30 @@ resource "aws_iam_role_policy_attachment" "lambda_secretsmanager" {
policy_arn = aws_iam_policy.lambda_secretsmanager.arn
}

data "external" "auth_handler_location" {
program = ["bash", "${path.module}/resolve_location.sh"]

query = {
target = "//immersion_tracker_api:auth-handler_deploy.jar"
}
}

data "local_file" "auth_handler_file" {
filename = data.external.auth_handler_location.result.location
}

resource "aws_lambda_function" "auth" {
filename = data.local_file.auth_handler_file.filename
function_name = "${local.application_id}_auth"
role = aws_iam_role.lambda_role.arn
source_code_hash = data.local_file.auth_handler_file.content_base64sha256
handler = "com.jordansimsmith.immersiontracker.AuthHandler"
runtime = "java17"
memory_size = 512
timeout = 10
tags = local.tags
}

data "external" "get_progress_handler_location" {
program = ["bash", "${path.module}/resolve_location.sh"]

Expand All @@ -179,7 +203,7 @@ resource "aws_lambda_function" "get_progress" {
}

resource "aws_lambda_permission" "api_gateway" {
for_each = toset([aws_lambda_function.get_progress.function_name])
for_each = toset([aws_lambda_function.auth.function_name, aws_lambda_function.get_progress.function_name])

statement_id = "AllowAPIGatewayInvoke"
action = "lambda:InvokeFunction"
Expand All @@ -193,6 +217,13 @@ resource "aws_api_gateway_rest_api" "immersion_tracker" {
tags = local.tags
}

resource "aws_api_gateway_authorizer" "immersion_tracker" {
name = "${local.application_id}_authorizer"
rest_api_id = aws_api_gateway_rest_api.immersion_tracker.id
authorizer_uri = aws_lambda_function.auth.invoke_arn
type = "TOKEN"
}

resource "aws_api_gateway_resource" "get_progress" {
rest_api_id = aws_api_gateway_rest_api.immersion_tracker.id
parent_id = aws_api_gateway_rest_api.immersion_tracker.root_resource_id
Expand All @@ -203,7 +234,8 @@ resource "aws_api_gateway_method" "get_progress" {
rest_api_id = aws_api_gateway_rest_api.immersion_tracker.id
resource_id = aws_api_gateway_resource.get_progress.id
http_method = "GET"
authorization = "NONE"
authorization = "CUSTOM"
authorizer_id = aws_api_gateway_authorizer.immersion_tracker.id
}

resource "aws_api_gateway_integration" "get_progress" {
Expand All @@ -220,9 +252,10 @@ resource "aws_api_gateway_deployment" "immersion_tracker" {

triggers = {
redeployment = sha1(jsonencode([
aws_api_gateway_resource.get_progress.id,
aws_api_gateway_method.get_progress.id,
aws_api_gateway_integration.get_progress.id,
aws_api_gateway_authorizer.immersion_tracker,
aws_api_gateway_resource.get_progress,
aws_api_gateway_method.get_progress,
aws_api_gateway_integration.get_progress,
]))
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.jordansimsmith.immersiontracker;

import static com.jordansimsmith.immersiontracker.AuthHandler.AuthorizerEvent;
import static com.jordansimsmith.immersiontracker.AuthHandler.AuthorizerResponse;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import java.util.LinkedHashMap;
import software.amazon.awssdk.policybuilder.iam.IamEffect;
import software.amazon.awssdk.policybuilder.iam.IamPolicy;
import software.amazon.awssdk.policybuilder.iam.IamStatement;

public class AuthHandler implements RequestHandler<AuthorizerEvent, AuthorizerResponse> {
private final ObjectMapper objectMapper;

public record AuthorizerEvent(String authorizationToken, String methodArn) {}

public record AuthorizerResponse(String principalId, Object policyDocument) {}

public AuthHandler() {
this(ImmersionTrackerFactory.create());
}

@VisibleForTesting
AuthHandler(ImmersionTrackerFactory factory) {
this.objectMapper = factory.objectMapper();
}

@Override
public AuthorizerResponse handleRequest(AuthorizerEvent event, Context context) {
try {
return doHandleRequest(event, context);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}

public AuthorizerResponse doHandleRequest(AuthorizerEvent event, Context context)
throws Exception {
var token = event.authorizationToken.replace("Bearer ", "");

if (Strings.isNullOrEmpty(token)) {
throw new RuntimeException("Unauthorized");
}

if ("jordan".equals(token)) {
return response(token, IamEffect.ALLOW, event.methodArn());
}

return response(token, IamEffect.DENY, event.methodArn());
}

private AuthorizerResponse response(String principal, IamEffect effect, String resource)
throws JsonProcessingException {
var policy =
IamPolicy.builder()
.version("2012-10-17")
.addStatement(
IamStatement.builder()
.addAction("execute-api:Invoke")
.effect(effect)
.addResource(resource)
.build())
.build()
.toJson();
var policyMap = objectMapper.readValue(policy, LinkedHashMap.class);

return new AuthorizerResponse(principal, policyMap);
}
}

0 comments on commit 002aac7

Please sign in to comment.