Skip to content

Commit

Permalink
Add lambda to create certificate provider
Browse files Browse the repository at this point in the history
  • Loading branch information
hawx committed Jan 3, 2024
1 parent acd14fc commit 7ace6e8
Show file tree
Hide file tree
Showing 22 changed files with 751 additions and 350 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ down: ## Stop application
docker compose down

test: ## Unit tests
go test ./lambda/get/... ./lambda/create/... ./lambda/update/... ./internal/shared/... -race -covermode=atomic -coverprofile=coverage.out
go test ./... -race -covermode=atomic -coverprofile=coverage.out

test-api: URL ?= http://localhost:9000
test-api:
Expand Down
44 changes: 43 additions & 1 deletion docs/openapi/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,33 @@ paths:
httpMethod: "POST"
type: "aws_proxy"
contentHandling: "CONVERT_TO_TEXT"

/lpas/{uid}/certifcate-provider:
parameters:
- name: uid
in: path
required: true
description: The UID of the case
schema:
type: string
pattern: "M-([A-Z0-9]{4})-([A-Z0-9]{4})-([A-Z0-9]{4})"
example: M-789Q-P4DF-4UX3
put:
operationId: putCertificateProvider
summary: Store a certificate provider
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/CertificateProviderRequest"
responses:
"201":
description: Certificate provider created
"400":
description: Invalid request
content:
application/json:
schema:
$ref: "#/components/schemas/BadRequestError"
/health-check:
get:
operationId: healthCheck
Expand Down Expand Up @@ -202,6 +228,22 @@ components:
properties:
code:
enum: ["NOT_FOUND"]
CertificateProviderRequest:
type: object
required:
- contactLanguagePreference
- signedAt
properties:
address:
$ref: "#/components/schemas/Address"
contactLanguagePreference:
enum:
- cy
- en
signedAt:
type: string
format: date-time
additionalProperties: false
Lpa:
allOf:
- $ref: "#/components/schemas/InitialLpa"
Expand Down
69 changes: 69 additions & 0 deletions internal/ddb/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package ddb

import (
"context"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
"github.com/aws/aws-xray-sdk-go/xray"
"github.com/ministryofjustice/opg-data-lpa-store/internal/shared"
)

type Client struct {
ddb *dynamodb.DynamoDB
tableName string
}

func (c *Client) Put(ctx context.Context, data any) error {
item, err := dynamodbattribute.MarshalMap(data)
if err != nil {
return err
}

_, err = c.ddb.PutItemWithContext(ctx, &dynamodb.PutItemInput{
TableName: aws.String(c.tableName),
Item: item,
})

return err
}

func (c *Client) Get(ctx context.Context, uid string) (shared.Lpa, error) {
lpa := shared.Lpa{}

marshalledUid, err := dynamodbattribute.Marshal(uid)
if err != nil {
return lpa, err
}

getItemOutput, err := c.ddb.GetItemWithContext(ctx, &dynamodb.GetItemInput{
TableName: aws.String(c.tableName),
Key: map[string]*dynamodb.AttributeValue{
"uid": marshalledUid,
},
})

if err != nil {
return lpa, err
}

err = dynamodbattribute.UnmarshalMap(getItemOutput.Item, &lpa)

return lpa, err
}

func New(endpoint, tableName string) *Client {
sess := session.Must(session.NewSession())
sess.Config.Endpoint = &endpoint

c := &Client{
ddb: dynamodb.New(sess),
tableName: tableName,
}

xray.AWS(c.ddb.Client)

return c
}
10 changes: 0 additions & 10 deletions internal/shared/client.go

This file was deleted.

70 changes: 0 additions & 70 deletions internal/shared/ddb.go
Original file line number Diff line number Diff line change
@@ -1,71 +1 @@
package shared

import (
"context"
"os"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
"github.com/aws/aws-xray-sdk-go/xray"
)

type DynamoDBClient struct {
ddb *dynamodb.DynamoDB
tableName string
}

func (c DynamoDBClient) Put(ctx context.Context, data Lpa) error {
item, err := dynamodbattribute.MarshalMap(data)
if err != nil {
return err
}

_, err = c.ddb.PutItemWithContext(ctx, &dynamodb.PutItemInput{
TableName: aws.String(c.tableName),
Item: item,
})

return err
}

func (c DynamoDBClient) Get(ctx context.Context, uid string) (Lpa, error) {
lpa := Lpa{}

marshalledUid, err := dynamodbattribute.Marshal(uid)
if err != nil {
return lpa, err
}

getItemOutput, err := c.ddb.GetItemWithContext(ctx, &dynamodb.GetItemInput{
TableName: aws.String(c.tableName),
Key: map[string]*dynamodb.AttributeValue{
"uid": marshalledUid,
},
})

if err != nil {
return lpa, err
}

err = dynamodbattribute.UnmarshalMap(getItemOutput.Item, &lpa)

return lpa, err
}

func NewDynamoDB(tableName string) DynamoDBClient {
sess := session.Must(session.NewSession())

endpoint := os.Getenv("AWS_DYNAMODB_ENDPOINT")
sess.Config.Endpoint = &endpoint

c := DynamoDBClient{
ddb: dynamodb.New(sess),
tableName: tableName,
}

xray.AWS(c.ddb.Client)

return c
}
40 changes: 20 additions & 20 deletions internal/shared/jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,25 +88,6 @@ func NewJWTVerifier() JWTVerifier {
}
}

// tokenStr is the JWT token, minus any "Bearer: " prefix
func (v JWTVerifier) VerifyToken(tokenStr string) error {
lsc := lpaStoreClaims{}

parsedToken, err := jwt.ParseWithClaims(tokenStr, &lsc, func(token *jwt.Token) (interface{}, error) {
return v.secretKey, nil
})

if err != nil {
return err
}

if !parsedToken.Valid {
return fmt.Errorf("Invalid JWT")
}

return nil
}

var bearerRegexp = regexp.MustCompile("^Bearer[ ]+")

// verify JWT from event header
Expand All @@ -119,9 +100,28 @@ func (v JWTVerifier) VerifyHeader(event events.APIGatewayProxyRequest) bool {
}

tokenStr := bearerRegexp.ReplaceAllString(jwtHeaders[0], "")
if v.VerifyToken(tokenStr) != nil {
if v.verifyToken(tokenStr) != nil {
return false
}

return true
}

// tokenStr is the JWT token, minus any "Bearer: " prefix
func (v JWTVerifier) verifyToken(tokenStr string) error {
lsc := lpaStoreClaims{}

parsedToken, err := jwt.ParseWithClaims(tokenStr, &lsc, func(token *jwt.Token) (interface{}, error) {
return v.secretKey, nil
})

if err != nil {
return err
}

if !parsedToken.Valid {
return fmt.Errorf("Invalid JWT")
}

return nil
}
16 changes: 8 additions & 8 deletions internal/shared/jwt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func createToken(claims jwt.MapClaims) string {
}

func TestVerifyEmptyJwt(t *testing.T) {
err := verifier.VerifyToken("")
err := verifier.verifyToken("")
assert.NotNil(t, err)
}

Expand All @@ -38,7 +38,7 @@ func TestVerifyExpInPast(t *testing.T) {
"sub": "M-3467-89QW-ERTY",
})

err := verifier.VerifyToken(token)
err := verifier.verifyToken(token)

assert.NotNil(t, err)
if err != nil {
Expand All @@ -54,7 +54,7 @@ func TestVerifyIatInFuture(t *testing.T) {
"sub": "[email protected]",
})

err := verifier.VerifyToken(token)
err := verifier.verifyToken(token)

assert.NotNil(t, err)
if err != nil {
Expand All @@ -70,7 +70,7 @@ func TestVerifyIssuer(t *testing.T) {
"sub": "[email protected]",
})

err := verifier.VerifyToken(token)
err := verifier.verifyToken(token)

assert.NotNil(t, err)
if err != nil {
Expand All @@ -86,7 +86,7 @@ func TestVerifyBadEmailForSiriusIssuer(t *testing.T) {
"sub": "",
})

err := verifier.VerifyToken(token)
err := verifier.verifyToken(token)

assert.NotNil(t, err)
if err != nil {
Expand All @@ -102,7 +102,7 @@ func TestVerifyBadUIDForMRLPAIssuer(t *testing.T) {
"sub": "",
})

err := verifier.VerifyToken(token)
err := verifier.verifyToken(token)

assert.NotNil(t, err)
if err != nil {
Expand All @@ -118,7 +118,7 @@ func TestVerifyGoodJwt(t *testing.T) {
"sub": "[email protected]",
})

err := verifier.VerifyToken(token)
err := verifier.verifyToken(token)
assert.Nil(t, err)
}

Expand All @@ -134,7 +134,7 @@ func TestNewJWTVerifier(t *testing.T) {
newVerifier := NewJWTVerifier()
os.Unsetenv("JWT_SECRET_KEY")

err := newVerifier.VerifyToken(token)
err := newVerifier.verifyToken(token)
assert.Nil(t, err)
}

Expand Down
12 changes: 12 additions & 0 deletions internal/shared/lang.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package shared

type Lang string

var (
LangCy = Lang("cy")
LangEn = Lang("en")
)

func (l Lang) IsValid() bool {
return l == LangCy || l == LangEn
}
Loading

0 comments on commit 7ace6e8

Please sign in to comment.