Skip to content
This repository was archived by the owner on Sep 25, 2025. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ jobs:
domain: grfn.asf.alaska.edu
auth_url: "https://urs.earthdata.nasa.gov/oauth/authorize?response_type=code&client_id=BO_n7nTIlMljdvU6kRRB3g&redirect_uri=https://auth.asf.alaska.edu/login"
jwt_cookie_name: asf-urs
log_bucket: grfn-logs
private_bucket: grfn-content-prod
deploy_ref: refs/heads/prod

Expand All @@ -26,7 +25,6 @@ jobs:
domain: grfn-test.asf.alaska.edu
auth_url: "https://uat.urs.earthdata.nasa.gov/oauth/authorize?client_id=Qkd0Z9KbhG86qedkRC7nSA&response_type=code&redirect_uri=https://auth-test-jenk.asf.alaska.edu/login"
jwt_cookie_name: asf-urs
log_bucket: grfn-logs
private_bucket: grfn-content-test
deploy_ref: refs/heads/test

Expand Down Expand Up @@ -70,11 +68,8 @@ jobs:
--capabilities CAPABILITY_NAMED_IAM \
--parameter-overrides \
CertificateArn='${{ secrets.CETRIFICATE_ARN }}' \
CloudFrontKeyPairId='${{ secrets.CLOUDFRONT_KEY_PAIR_ID }}' \
DomainName='${{ matrix.domain }}' \
LogBucket='${{ matrix.log_bucket }}' \
PrivateBucket='${{ matrix.private_bucket }}' \
PrivateKeySecretName='${{ secrets.PRIVATE_KEY_SECRET_NAME }}' \
AuthUrl='${{ matrix.auth_url }}' \
JwtCookieName='${{ matrix.jwt_cookie_name }}' \
JwtPublicKey='${{ secrets.JWT_PUBLIC_KEY }}'
21 changes: 0 additions & 21 deletions cloudformation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,12 @@ Parameters:
Description: Name of S3 bucket in which zipped output products will be archived
Type: String

LogBucket:
Type: String

CertificateArn:
Type: String

DomainName:
Type: String

CloudFrontKeyPairId:
Type: String

PrivateKeySecretName:
Type: String

AuthUrl:
Type: String

Expand All @@ -37,22 +28,10 @@ Resources:
Properties:
Parameters:
Name: !Sub "${AWS::StackName}-door"
CloudFrontDomainName: !GetAtt CloudFrontStack.Outputs.DomainName
CloudFrontKeyPairId: !Ref CloudFrontKeyPairId
PrivateKeySecretName: !Ref PrivateKeySecretName
PrivateBucket: !Ref PrivateBucket
CertificateArn: !Ref CertificateArn
DomainName: !Ref DomainName
AuthUrl: !Ref AuthUrl
JwtCookieName: !Ref JwtCookieName
JwtPublicKey: !Ref JwtPublicKey
TemplateURL: door/cloudformation.yaml

CloudFrontStack:
Type: AWS::CloudFormation::Stack
Properties:
Parameters:
Name: !Ref AWS::StackName
Bucket: !Ref PrivateBucket
LogBucket: !Ref LogBucket
TemplateURL: cloudfront/cloudformation.yaml
83 changes: 0 additions & 83 deletions cloudfront/cloudformation.yaml

This file was deleted.

15 changes: 0 additions & 15 deletions door/cloudformation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,6 @@ Parameters:
Name:
Type: String

CloudFrontDomainName:
Type: String

CloudFrontKeyPairId:
Type: String

PrivateKeySecretName:
Type: String

PrivateBucket:
Type: String

Expand Down Expand Up @@ -116,9 +107,6 @@ Resources:
- logs:CreateLogStream
- logs:PutLogEvents
Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*"
- Effect: Allow
Action: secretsmanager:GetSecretValue
Resource: !Sub "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${PrivateKeySecretName}*"
- Effect: Allow
Action: s3:ListBucket
Resource: !Sub "arn:aws:s3:::${PrivateBucket}"
Expand All @@ -131,9 +119,6 @@ Resources:
Properties:
Environment:
Variables:
CLOUDFRONT_DOMAIN_NAME: !Ref CloudFrontDomainName
CLOUDFRONT_KEY_PAIR_ID: !Ref CloudFrontKeyPairId
PRIVATE_KEY_SECRET_NAME: !Ref PrivateKeySecretName
EXPIRE_TIME_IN_SECONDS: 15
BUCKET: !Ref PrivateBucket
AUTH_URL: !Ref AuthUrl
Expand Down
3 changes: 1 addition & 2 deletions door/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
Flask
Flask-Cors
rsa
serverless_wsgi
PyJWT
cryptography
cryptography
35 changes: 8 additions & 27 deletions door/src/door/routes.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import json
import os
from datetime import datetime, timedelta, timezone
from urllib.parse import quote_plus

import boto3
import jwt
import rsa
from botocore.exceptions import ClientError
from botocore.signers import CloudFrontSigner
from flask import abort, g, redirect, request
from flask_cors import CORS

Expand All @@ -25,12 +21,6 @@ def decode_token(token):
return None


@app.before_first_request
def init_app():
private_key = get_secret(os.environ['PRIVATE_KEY_SECRET_NAME'])['private_key']
os.environ['CLOUDFRONT_PRIVATE_KEY'] = str(private_key)


@app.before_request
def authenticate_user():
cookie = request.cookies.get(os.environ['JWT_COOKIE_NAME'])
Expand All @@ -57,24 +47,15 @@ def download_redirect(object_key):
abort(404)
raise

signed_url = get_signed_url(object_key, g.user_id, os.environ['CLOUDFRONT_PRIVATE_KEY'])
signed_url = get_signed_url(object_key, g.user_id)
return redirect(signed_url)


def get_signed_url(object_key, user_id, private_key):
def rsa_signer(message):
key = rsa.PrivateKey.load_pkcs1(private_key.encode(), 'PEM')
return rsa.sign(message, key, 'SHA-1')

base_url = f'https://{os.environ["CLOUDFRONT_DOMAIN_NAME"]}/{object_key}?userid={user_id}'
expiration_datetime = datetime.now(tz=timezone.utc) + timedelta(seconds=int(os.environ['EXPIRE_TIME_IN_SECONDS']))
cf_signer = CloudFrontSigner(os.environ['CLOUDFRONT_KEY_PAIR_ID'], rsa_signer)
signed_url = cf_signer.generate_presigned_url(base_url, date_less_than=expiration_datetime)
def get_signed_url(object_key, user_id):
signed_url = s3.generate_presigned_url(
ClientMethod='get_object',
Params={'Bucket': os.environ['BUCKET'], 'Key': object_key},
ExpiresIn=int(os.environ['EXPIRE_TIME_IN_SECONDS']),
)
signed_url += f'&user_id={user_id}'
return signed_url


def get_secret(secret_name):
sm = boto3.client('secretsmanager', os.environ['AWS_REGION'])
response = sm.get_secret_value(SecretId=secret_name)
secret = json.loads(response['SecretString'])
return secret