Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

release v3.1.3 #94

Merged
merged 11 commits into from
Jan 19, 2024
30 changes: 21 additions & 9 deletions api/endpoints/cmr.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,16 +130,28 @@ class CmrGranuleData(Resource):
"""

def get(self, file_uri):
response = edl_federated_request(parse.unquote(file_uri), stream=True)
s = requests.Session()
response = s.get(parse.unquote(file_uri), stream=True)

if response.status_code == status.HTTP_200_OK:
return Response(
response=stream_with_context(response.iter_content(chunk_size=1024 * 10)),
content_type=response.headers.get('Content-Type'),
direct_passthrough=True)
else:
# Propagate the error
return response
if response.status_code == 401:
maap_user = get_authorized_user()

if maap_user is None:
return Response(response.text, status=401)
else:
urs_token = db.session.query(Member).filter_by(id=maap_user.id).first().urs_token
s.headers.update({'Authorization': f'Bearer {urs_token},Basic {settings.MAAP_EDL_CREDS}',
'Connection': 'close'})

response = s.get(url=response.url, stream=True)

if response.status_code >= 400:
return Response(response.text, status=response.status_code)

return Response(
response=stream_with_context(response.iter_content(chunk_size=1024 * 10)),
content_type=response.headers.get('Content-Type'),
direct_passthrough=True)


def get_search_headers():
Expand Down
91 changes: 53 additions & 38 deletions api/endpoints/members.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
from urllib import parse
from api.utils.url_util import proxied_url


log = logging.getLogger(__name__)
ns = api.namespace('members', description='Operations for MAAP members')
s3_client = boto3.client('s3', region_name=settings.AWS_REGION)
Expand Down Expand Up @@ -76,13 +75,14 @@ def get(self, key):
Member_db.last_name,
Member_db.email,
Member_db.status,
Member_db.public_ssh_key,
Member_db.creation_date
]

member = db.session\
.query(Member_db)\
.with_entities(*cols)\
.filter_by(username=key)\
member = db.session \
.query(Member_db) \
.with_entities(*cols) \
.filter_by(username=key) \
.first()

if member is None:
Expand All @@ -92,11 +92,11 @@ def get(self, key):
result = json.loads(member_schema.dumps(member))

if valid_dps_request():
pgt_ticket = db.session\
.query(MemberSession_db)\
.with_entities(MemberSession_db.session_key)\
.filter_by(member_id=member.id)\
.order_by(MemberSession_db.id.desc())\
pgt_ticket = db.session \
.query(MemberSession_db) \
.with_entities(MemberSession_db.session_key) \
.filter_by(member_id=member.id) \
.order_by(MemberSession_db.id.desc()) \
.first()

member_session_schema = MemberSessionSchema()
Expand Down Expand Up @@ -341,6 +341,7 @@ def get(self):
Member_db.last_name,
Member_db.email,
Member_db.status,
Member_db.public_ssh_key,
Member_db.creation_date
]

Expand Down Expand Up @@ -413,7 +414,6 @@ def delete(self):

@ns.route('/self/presignedUrlS3/<string:bucket>/<path:key>')
class PresignedUrlS3(Resource):

expiration_param = reqparse.RequestParser()
expiration_param.add_argument('exp', type=int, required=False, default=60 * 60 * 12)
expiration_param.add_argument('ws', type=str, required=False, default="")
Expand Down Expand Up @@ -456,15 +456,13 @@ def mount_key_to_bucket(self, key, ws):

@ns.route('/self/awsAccess/requesterPaysBucket')
class AwsAccessRequesterPaysBucket(Resource):

expiration_param = reqparse.RequestParser()
expiration_param.add_argument('exp', type=int, required=False, default=60 * 60 * 12)

@api.doc(security='ApiKeyAuth')
@login_required
@api.expect(expiration_param)
def get(self):

member = get_authorized_user()

expiration = request.args['exp']
Expand Down Expand Up @@ -497,26 +495,42 @@ class AwsAccessEdcCredentials(Resource):
Example:
https://api.maap-project.org/api/self/edcCredentials/https%3A%2F%2Fdata.lpdaac.earthdatacloud.nasa.gov%2Fs3credentials
"""

@api.doc(security='ApiKeyAuth')
@login_required
def get(self, endpoint_uri):
s = requests.Session()
maap_user = get_authorized_user()

if not maap_user:
if maap_user is None:
return Response('Unauthorized', status=401)
else:
urs_token = db.session.query(Member_db).filter_by(id=maap_user.id).first().urs_token
s.headers.update({'Authorization': f'Bearer {urs_token},Basic {settings.MAAP_EDL_CREDS}',
'Connection': 'close'})

creds = get_edc_credentials(endpoint_uri, maap_user)
endpoint = parse.unquote(endpoint_uri)
login_resp = s.get(
endpoint, allow_redirects=False
)

response = jsonify(
accessKeyId=creds['accessKeyId'],
secretAccessKey=creds['secretAccessKey'],
sessionToken=creds['sessionToken'],
expiration=creds['expiration']
)
if login_resp.status_code == 307:
edl_response = s.get(url=login_resp.headers['location'])
else:
edl_response = edl_federated_request(url=endpoint)

response.headers.add('Access-Control-Allow-Origin', '*')
json_response = json.loads(edl_response.content)

return response
response = jsonify(
accessKeyId=json_response['accessKeyId'],
secretAccessKey=json_response['secretAccessKey'],
sessionToken=json_response['sessionToken'],
expiration=json_response['expiration']
)

response.headers.add('Access-Control-Allow-Origin', '*')

return response


@ns.route('/self/awsAccess/workspaceBucket')
Expand All @@ -529,6 +543,7 @@ class AwsAccessUserBucketCredentials(Resource):
Example:
https://api.maap-project.org/api/self/awsAccess/workspaceBucket
"""

@api.doc(security='ApiKeyAuth')
@login_required
def get(self):
Expand Down Expand Up @@ -629,23 +644,24 @@ def get_edc_credentials(endpoint_uri, user):
"""
urs_token = db.session.query(Member_db).filter_by(id=user.id).first().urs_token

with requests.Session() as s:
s.headers.update(
{
'Authorization': f'Bearer {urs_token},Basic {settings.MAAP_EDL_CREDS}',
'Connection': 'close'
}
)
s = requests.Session()

endpoint = parse.unquote(endpoint_uri)
login_resp = s.get(endpoint, allow_redirects=False)
s.headers.update(
{
'Authorization': f'Bearer {urs_token},Basic {settings.MAAP_EDL_CREDS}',
'Connection': 'close'
}
)

if login_resp.status_code == status.HTTP_307_TEMPORARY_REDIRECT:
edl_response = s.get(url=login_resp.headers['location'])
else:
edl_response = edl_federated_request(url=endpoint)
endpoint = parse.unquote(endpoint_uri)
login_resp = s.get(endpoint, allow_redirects=False)

return json.loads(edl_response.content)
if login_resp.status_code == status.HTTP_307_TEMPORARY_REDIRECT:
edl_response = s.get(url=login_resp.headers['location'])
else:
edl_response = edl_federated_request(url=endpoint)

return json.loads(edl_response.content)


@ns.route('/pre-approved')
Expand Down Expand Up @@ -714,7 +730,6 @@ class PreApprovedEmails(Resource):
@api.doc(security='ApiKeyAuth')
@login_required
def delete(self, email):

"""
Delete pre-approved email
"""
Expand Down
7 changes: 6 additions & 1 deletion docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,15 @@ services:
volumes:
- ./logs:/maap-api-nasa/logs/
command: >
sh -c "flask run --host=0.0.0.0"
sh -c "gunicorn --bind 0.0.0.0:5000 api.maapapp:app -w 4"
environment:
FLASK_APP: /maap-api-nasa/api/maapapp.py
restart: always
logging:
driver: "json-file"
options:
max-size: 250m
max-file: 10

db:
image: postgres:14.5
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
cachetools
gunicorn
flask
flask-cors
flask-restx
Expand Down