Skip to content

Commit

Permalink
Feat/ssm 24 (#29)
Browse files Browse the repository at this point in the history
* feat/SSM-24: added auth middleware and refactored components.

* feat/SSM-24: fixed invalid creds string for auth middleware_test.go.

* feat/SSM-24: fixed service_cases_test.go.

* feat/SSM-24: refactored solution to provide more pluggable auth handlers.

* feat/SSM-24: minor clean-up, removed duplication.

* feat/SSM-24: changed routes.

* feat/SSM-24: minor fixes based on latest review of PR.

* feat/SSM-24: removed redundant HashPassword

* feat/SSM-24: added test authenticator on creds and added segregation to authenticator logic.
  • Loading branch information
j1mb0b authored Jan 14, 2025
1 parent 781a454 commit c0cde3c
Show file tree
Hide file tree
Showing 21 changed files with 732 additions and 317 deletions.
13 changes: 7 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
.PHONY: all test clean build start
.PHONY: all test build start clean

all: build test start clean

build:
@echo "Building the application image using Docker Compose..."
@docker-compose build || { echo "Failed to build the application image"; exit 1; }
all: test start clean

test:
@echo "Running tests in the service-app-test container..."
@docker-compose build service-app-test || { echo "Failed to build the service-app-test image"; exit 1; }
@docker-compose run --rm service-app-test || { echo "Tests failed"; exit 1; }
@docker-compose down --remove-orphans --volumes service-app-test

build:
@echo "Building the application..."
@docker-compose build || { echo "Failed to build the application image"; exit 1; }

start:
@${MAKE} build
@echo "Running the application using Docker Compose..."
@docker-compose up -d || { echo "Failed to start Docker Compose"; exit 1; }

Expand Down
7 changes: 4 additions & 3 deletions service-app/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ type (
}

Auth struct {
ApiUsername string `envconfig:"API_USERNAME" default:"[email protected]"`
JWTSecretARN string `envconfig:"JWT_SECRET_ARN" default:"local/jwt-key"`
JWTExpiration int `envconfig:"JWT_EXPIRATION" default:"3600"`
ApiUsername string `envconfig:"API_USERNAME" default:"[email protected]"`
JWTSecretARN string `envconfig:"JWT_SECRET_ARN" default:"local/jwt-key"`
CredentialsARN string `envconfig:"CREDENTIALS_ARN" default:"/local/local-credentials"`
JWTExpiration int `envconfig:"JWT_EXPIRATION" default:"3600"`
}

HTTP struct {
Expand Down
22 changes: 15 additions & 7 deletions service-app/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.23.2

require (
github.com/aws/aws-sdk-go v1.55.5
github.com/aws/aws-sdk-go-v2 v1.32.6
github.com/aws/aws-sdk-go-v2 v1.32.7
github.com/kelseyhightower/envconfig v1.4.0
github.com/stretchr/testify v1.10.0
)
Expand All @@ -13,8 +13,8 @@ require (
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.47 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.21 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.25 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.25 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.25 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect
Expand All @@ -33,8 +33,6 @@ require (
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/stretchr/objx v0.5.2 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/detectors/aws/ecs v1.33.0 // indirect
go.opentelemetry.io/contrib/propagators/aws v1.33.0 // indirect
go.opentelemetry.io/otel v1.33.0 // indirect
Expand All @@ -45,22 +43,32 @@ require (
go.opentelemetry.io/otel/trace v1.33.0 // indirect
go.opentelemetry.io/proto/otlp v1.4.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.21.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
google.golang.org/grpc v1.69.0 // indirect
google.golang.org/protobuf v1.35.2 // indirect
)

require (
github.com/stretchr/objx v0.5.2 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
)

require (
github.com/aws/aws-sdk-go-v2/config v1.28.6
github.com/aws/aws-sdk-go-v2/service/s3 v1.71.0
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.34.7
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ssm v1.56.2
github.com/golang-jwt/jwt/v5 v5.2.1
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/lestrrat-go/libxml2 v0.0.0-20240905100032-c934e3fcb9d3
github.com/ministryofjustice/opg-go-common v1.45.0
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/crypto v0.32.0
gopkg.in/yaml.v3 v3.0.1 // indirect
)
20 changes: 12 additions & 8 deletions service-app/go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU=
github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
github.com/aws/aws-sdk-go-v2 v1.32.6 h1:7BokKRgRPuGmKkFMhEg/jSul+tB9VvXhcViILtfG8b4=
github.com/aws/aws-sdk-go-v2 v1.32.6/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U=
github.com/aws/aws-sdk-go-v2 v1.32.7 h1:ky5o35oENWi0JYWUZkB7WYvVPP+bcRF5/Iq7JWSb5Rw=
github.com/aws/aws-sdk-go-v2 v1.32.7/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 h1:lL7IfaFzngfx0ZwUGOZdsFFnQ5uLvR0hWqqhyE7Q9M8=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7/go.mod h1:QraP0UcVlQJsmHfioCrveWOC1nbiWUl3ej08h4mXWoc=
github.com/aws/aws-sdk-go-v2/config v1.28.6 h1:D89IKtGrs/I3QXOLNTH93NJYtDhm8SYa9Q5CsPShmyo=
Expand All @@ -10,10 +10,10 @@ github.com/aws/aws-sdk-go-v2/credentials v1.17.47 h1:48bA+3/fCdi2yAwVt+3COvmatZ6
github.com/aws/aws-sdk-go-v2/credentials v1.17.47/go.mod h1:+KdckOejLW3Ks3b0E3b5rHsr2f9yuORBum0WPnE5o5w=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.21 h1:AmoU1pziydclFT/xRV+xXE/Vb8fttJCLRPv8oAkprc0=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.21/go.mod h1:AjUdLYe4Tgs6kpH4Bv7uMZo7pottoyHMn4eTcIcneaY=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.25 h1:s/fF4+yDQDoElYhfIVvSNyeCydfbuTKzhxSXDXCPasU=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.25/go.mod h1:IgPfDv5jqFIzQSNbUEMoitNooSMXjRSDkhXv8jiROvU=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.25 h1:ZntTCl5EsYnhN/IygQEUugpdwbhdkom9uHcbCftiGgA=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.25/go.mod h1:DBdPrgeocww+CSl1C8cEV8PN1mHMBhuCDLpXezyvWkE=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 h1:I/5wmGMffY4happ8NOCuIUEWGUvvFp5NSeQcXl9RHcI=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26/go.mod h1:FR8f4turZtNy6baO0KJ5FJUmXH/cSkI9fOngs0yl6mA=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 h1:zXFLuEuMMUOvEARXFUVJdfqZ4bvvSgdGRq/ATcrQxzM=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26/go.mod h1:3o2Wpy0bogG1kyOPrgkXA8pgIfEEv0+m19O9D5+W8y8=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.25 h1:r67ps7oHCYnflpgDy2LZU0MAQtQbYIOqNNnqGO6xQkE=
Expand All @@ -30,6 +30,8 @@ github.com/aws/aws-sdk-go-v2/service/s3 v1.71.0 h1:nyuzXooUNJexRT0Oy0UQY6AhOzxPx
github.com/aws/aws-sdk-go-v2/service/s3 v1.71.0/go.mod h1:sT/iQz8JK3u/5gZkT+Hmr7GzVZehUMkRZpOaAwYXeGY=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.34.7 h1:Nyfbgei75bohfmZNxgN27i528dGYVzqWJGlAO6lzXy8=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.34.7/go.mod h1:FG4p/DciRxPgjA+BEOlwRHN0iA8hX2h9g5buSy3cTDA=
github.com/aws/aws-sdk-go-v2/service/ssm v1.56.2 h1:MOxvXH2kRP5exvqJxAZ0/H9Ar51VmADJh95SgZE8u60=
github.com/aws/aws-sdk-go-v2/service/ssm v1.56.2/go.mod h1:RKWoqC9FlgMCkrfVOtgfqfwdaUIaq8H93UAt4xNaR0A=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.7 h1:rLnYAfXQ3YAccocshIH5mzNNwZBkBo+bP6EhIxak6Hw=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.7/go.mod h1:ZHtuQJ6t9A/+YDuxOLnbryAmITtr8UysSny3qcyvJTc=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.6 h1:JnhTZR3PiYDNKlXy50/pNeix9aGMo6lLpXwJ1mw8MD4=
Expand Down Expand Up @@ -112,10 +114,12 @@ go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q=
Expand Down
81 changes: 59 additions & 22 deletions service-app/internal/api/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/ministryofjustice/opg-go-common/telemetry"
"github.com/ministryofjustice/opg-scanning/config"
"github.com/ministryofjustice/opg-scanning/internal/auth"
"github.com/ministryofjustice/opg-scanning/internal/aws"
"github.com/ministryofjustice/opg-scanning/internal/httpclient"
"github.com/ministryofjustice/opg-scanning/internal/ingestion"
Expand All @@ -20,31 +21,75 @@ import (
)

type IndexController struct {
config *config.Config
logger *logger.Logger
validator *ingestion.Validator
Queue *ingestion.JobQueue
AwsClient *aws.AwsClient
config *config.Config
logger *logger.Logger
validator *ingestion.Validator
httpMiddleware *httpclient.Middleware
authMiddleware *auth.Middleware
Queue *ingestion.JobQueue
AwsClient *aws.AwsClient
}

func NewIndexController(awsClient *aws.AwsClient, appConfig *config.Config) *IndexController {
logger := logger.NewLogger(appConfig)

// Create dependencies
httpClient := httpclient.NewHttpClient(*appConfig, *logger)
tokenGenerator := auth.NewJWTTokenGenerator(awsClient, appConfig, logger)
cookieHelper := auth.MembraneCookieHelper{
CookieName: "membrane",
Secure: appConfig.App.Environment != "local",
}
authenticator := auth.NewBasicAuthAuthenticator(awsClient, cookieHelper, tokenGenerator)

// Create authentication middleware
authMiddleware := auth.NewMiddleware(authenticator, tokenGenerator, cookieHelper, logger)
// Create HTTP middleware
httpMiddleware, _ := httpclient.NewMiddleware(httpClient, tokenGenerator)

return &IndexController{
config: appConfig,
logger: logger.NewLogger(appConfig),
validator: ingestion.NewValidator(),
Queue: ingestion.NewJobQueue(appConfig),
AwsClient: awsClient,
config: appConfig,
logger: logger,
validator: ingestion.NewValidator(),
httpMiddleware: httpMiddleware,
authMiddleware: authMiddleware,
Queue: ingestion.NewJobQueue(appConfig),
AwsClient: awsClient,
}
}

func (c *IndexController) HandleRequests() {
http.Handle("/ingest", telemetry.Middleware(c.logger.SlogLogger)(http.HandlerFunc(c.IngestHandler)))
// Create the route to handle user authentication and issue JWT token
http.Handle("/auth/sessions", http.HandlerFunc(c.AuthHandler))

// Protect the route with JWT validation (using the authMiddleware)
http.Handle("/api/ddc", telemetry.Middleware(c.logger.SlogLogger)(
c.authMiddleware.CheckAuthMiddleware(http.HandlerFunc(c.IngestHandler)),
))

c.logger.Info("Starting server on :"+c.config.HTTP.Port, nil)
http.ListenAndServe(":"+c.config.HTTP.Port, nil)
}

func (c *IndexController) AuthHandler(w http.ResponseWriter, r *http.Request) {
// Authenticate user credentials and issue JWT token
_, err := c.authMiddleware.Authenticator.Authenticate(w, r)
if err != nil {
c.respondWithError(w, http.StatusUnauthorized, "Authentication failed", err)
return
}

w.Write([]byte("Authentication successful"))
}

func (c *IndexController) IngestHandler(w http.ResponseWriter, r *http.Request) {
// Extract claims from context
// _, ok := r.Context().Value("claims").(jwt.MapClaims)
// if !ok {
// c.respondWithError(w, http.StatusUnauthorized, "Unauthorized: Unable to extract claims", nil)
// return
// }

if r.Method != http.MethodPost {
c.respondWithError(w, http.StatusMethodNotAllowed, "Invalid HTTP method", nil)
return
Expand All @@ -54,7 +99,7 @@ func (c *IndexController) IngestHandler(w http.ResponseWriter, r *http.Request)

bodyStr, err := c.readRequestBody(r)
if err != nil {
c.respondWithError(w, http.StatusBadRequest, "Failed to read request body", err)
c.respondWithError(w, http.StatusBadRequest, "Invalid request body", err)
return
}

Expand All @@ -76,17 +121,8 @@ func (c *IndexController) IngestHandler(w http.ResponseWriter, r *http.Request)
return
}

// Sirius API integration
// Create a case stub in Sirius if we have a case to create
httpClient := httpclient.NewHttpClient(*c.config, *c.logger)
middleware, err := httpclient.NewMiddleware(httpClient, c.AwsClient)
if err != nil {
c.respondWithError(w, http.StatusInternalServerError, "Failed to create middleware", err)
return
}

// Create a new client and prepare to attach documents
client := NewClient(middleware)
client := NewClient(c.httpMiddleware)
service := NewService(client, parsedBaseXml)
scannedCaseResponse, err := service.CreateCaseStub(r.Context())
if err != nil {
Expand All @@ -103,6 +139,7 @@ func (c *IndexController) IngestHandler(w http.ResponseWriter, r *http.Request)
}
// Queue each document for further processing
c.logger.Info("Queueing documents for processing", nil)

for i := range parsedBaseXml.Body.Documents {
doc := &parsedBaseXml.Body.Documents[i]
c.Queue.AddToQueue(doc, "xml", func(processedDoc interface{}, originalDoc *types.BaseDocument) {
Expand Down
4 changes: 4 additions & 0 deletions service-app/internal/api/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ func (s *Service) CreateCaseStub(ctx context.Context) (*types.ScannedCaseRespons
}, nil
}

if s.Client.Middleware == nil {
return nil, fmt.Errorf("middleware is nil")
}

url := fmt.Sprintf("%s/%s", s.Client.Middleware.Config.App.SiriusBaseURL, s.Client.Middleware.Config.App.SiriusCaseStubURL)

resp, err := s.Client.ClientRequest(ctx, scannedCaseRequest, url)
Expand Down
Loading

0 comments on commit c0cde3c

Please sign in to comment.