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/4.1.0 #138

Merged
merged 28 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
0b182fc
/version 4.1.0a0
frankinspace Jun 26, 2024
106cf32
Merge remote-tracking branch 'origin/main' into develop
frankinspace Jul 2, 2024
158ec54
/version 4.1.0a1
frankinspace Jul 2, 2024
7c794eb
added query params to job list endpoint (#131)
marjo-luc Aug 6, 2024
94daabb
/version 4.1.0a2
marjo-luc Aug 6, 2024
1cda9b2
Update members.py (#120)
bsatoriu Aug 14, 2024
096229a
/version 4.1.0a3
bsatoriu Aug 14, 2024
b2c8836
Remove {username} param from DPS job list endpoint (#132)
bsatoriu Aug 14, 2024
ce6a216
/version 4.1.0a4
bsatoriu Aug 14, 2024
1d0e59c
User secret management (#135)
bsatoriu Aug 19, 2024
601b897
/version 4.1.0a5
bsatoriu Aug 19, 2024
f6eca44
Organizations & job queues management (#137)
bsatoriu Sep 9, 2024
781e7a6
/version 4.1.0a6
bsatoriu Sep 9, 2024
ef8ee42
Update CHANGELOG.md
bsatoriu Sep 10, 2024
f510858
/version 4.1.0a7
bsatoriu Sep 10, 2024
cfaa377
/version 4.2.0a0
bsatoriu Sep 10, 2024
df85c6b
Add support for DPS sandbox queue (#136)
sujen1412 Sep 12, 2024
3d39bee
/version 4.1.0rc1
bsatoriu Sep 12, 2024
bb88050
Mount maap-dps env file to read api host and dps token from the host …
sujen1412 Sep 17, 2024
5a7f72c
/version 4.1.0rc2
bsatoriu Sep 17, 2024
0497164
Set job time limit based on the queue time limits if specified (#140)
sujen1412 Sep 17, 2024
0ff9029
/version 4.1.0rc3
sujen1412 Sep 17, 2024
5d0087e
Convert time from minutes to seconds (#141)
sujen1412 Sep 17, 2024
46efb28
/version 4.1.0rc4
bsatoriu Sep 17, 2024
bee6eed
Add orgs to user profile
Sep 19, 2024
e9fcd7c
/version 4.1.0rc5
bsatoriu Sep 19, 2024
c1ad0e1
Update SQLALCHEMY_ENGINE_OPTIONS settings
Sep 25, 2024
b0cbcac
/version 4.1.0rc6
bsatoriu Sep 25, 2024
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
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [v4.1.0] - 2024-09-10
- [pull/131](https://github.com/MAAP-Project/maap-api-nasa/pull/131) - Added query params to job list endpoint
- [pull/135](https://github.com/MAAP-Project/maap-api-nasa/pull/135) - User secret management
- [pull/137](https://github.com/MAAP-Project/maap-api-nasa/pull/137) - Organizations & job queues management
- [pull/136](https://github.com/MAAP-Project/maap-api-nasa/pull/136) - Add support for DPS sandbox queue
- [pull/132](https://github.com/MAAP-Project/maap-api-nasa/pull/132) - Remove {username} param from DPS job list endpoint

## [v4.0.0] - 2024-06-26
- [issues/111](https://github.com/MAAP-Project/maap-api-nasa/issues/111) - Implement github actions CICD and convert to poetry based build
- [pull/110](https://github.com/MAAP-Project/maap-api-nasa/pull/110) - Remove postgres from docker-compose
Expand All @@ -16,4 +23,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0


[unreleased]: https://github.com/MAAP-Project/maap-api-nasa/v4.0.0...HEAD
[v4.0.0]: https://github.com/MAAP-Project/maap-api-nasa/compare/v3.1.5...v4.0.0
[v4.1.0]: https://github.com/MAAP-Project/maap-api-nasa/compare/v4.0.0...v4.1.0
[v4.0.0]: https://github.com/MAAP-Project/maap-api-nasa/compare/v3.1.5...v4.0.0
File renamed without changes.
94 changes: 1 addition & 93 deletions api/cas/cas_auth.py → api/auth/cas_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@

import flask
import requests
from flask import abort, request, Response, json
from flask import request, json
from flask_api import status
from xmltodict import parse
from flask import current_app
from .cas_urls import create_cas_proxy_url, create_cas_validate_url, create_cas_proxy_validate_url
from api.maap_database import db
from api.models.member import Member
from api.models.member_session import MemberSession
from api.models.member_job import MemberJob
from api import settings
from functools import wraps
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from Crypto import Random
Expand All @@ -21,7 +19,6 @@
from api.utils.url_util import proxied_url
import ast


try:
from urllib import urlopen
except ImportError:
Expand All @@ -31,7 +28,6 @@

PROXY_TICKET_PREFIX = "PGT-"


def validate(service, ticket):
"""
Will attempt to validate the ticket. If validation fails False
Expand Down Expand Up @@ -132,15 +128,6 @@ def validate_bearer(token):
return None


def validate_cas_request(token):
"""
Will attempt to validate a CAS machine token. Return True if validation succeeds.
"""

current_app.logger.debug("validating cas request token {0}".format(token))
return token == settings.CAS_SECRET_KEY


def validate_cas_request(cas_url):

xml_from_dict = {}
Expand Down Expand Up @@ -214,82 +201,3 @@ def decrypt_proxy_ticket(ticket):
return ''


def get_authorized_user():
if 'proxy-ticket' in request.headers:
member_session = validate_proxy(request.headers['proxy-ticket'])

if member_session is not None:
return member_session.member

if 'Authorization' in request.headers:
bearer = request.headers.get('Authorization')
token = bearer.split()[1]
authorized = validate_bearer(token)

if authorized is not None:
return authorized

return None


def login_required(wrapped_function):
@wraps(wrapped_function)
def wrap(*args, **kwargs):

if 'proxy-ticket' in request.headers:
authorized = validate_proxy(request.headers['proxy-ticket'])

if authorized is not None:
return wrapped_function(*args, **kwargs)

if 'cpticket' in request.headers:
authorized = validate_proxy(request.headers['cpticket'])

if authorized is not None:
return wrapped_function(*args, **kwargs)

if 'Authorization' in request.headers:
bearer = request.headers.get('Authorization')
token = bearer.split()[1]
authorized = validate_bearer(token)

if authorized is not None:
return wrapped_function(*args, **kwargs)

if 'cas-authorization' in request.headers:
authorized = validate_cas_request(request.headers['cas-authorization'])

if authorized:
return wrapped_function(*args, **kwargs)

if 'dps-token' in request.headers and valid_dps_request():
return wrapped_function(*args, **kwargs)

abort(status.HTTP_403_FORBIDDEN, description="Not authorized.")

return wrap


def valid_dps_request():
if 'dps-token' in request.headers:
return settings.DPS_MACHINE_TOKEN == request.headers['dps-token']
return False


def edl_federated_request(url, stream_response=False):
s = requests.Session()
response = s.get(url, stream=stream_response)

if response.status_code == status.HTTP_401_UNAUTHORIZED:
maap_user = get_authorized_user()

if maap_user is not None:
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=stream_response)

return response


File renamed without changes.
105 changes: 105 additions & 0 deletions api/auth/security.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
from functools import wraps
import requests
from flask import request, abort
from flask_api import status
from api import settings
from api.auth.cas_auth import validate_proxy, validate_bearer, validate_cas_request
from api.maap_database import db
from api.models.member import Member
from api.models.role import Role

HEADER_PROXY_TICKET = "proxy-ticket"
HEADER_CP_TICKET = "cpticket"
HEADER_AUTHORIZATION = "Authorization"
HEADER_CAS_AUTHORIZATION = "cas-authorization"
HEADER_DPS_TOKEN = "dps-token"
MEMBER_STATUS_ACTIVE = "active"
MEMBER_STATUS_SUSPENDED = "suspended"


def get_authorized_user():
auth = get_auth_header()

if auth == HEADER_PROXY_TICKET or auth == HEADER_CP_TICKET:
member_session = validate_proxy(request.headers[auth])

if member_session is not None:
return member_session.member

if auth == HEADER_AUTHORIZATION:
bearer = request.headers.get(auth)
token = bearer.split()[1]
authorized = validate_bearer(token)

if authorized is not None:
return authorized

return None


def login_required(role=Role.ROLE_GUEST):
def login_required_outer(wrapped_function):
@wraps(wrapped_function)
def wrap(*args, **kwargs):
auth = get_auth_header()

if auth == HEADER_PROXY_TICKET or auth == HEADER_CP_TICKET:
member_session = validate_proxy(request.headers[auth])

if member_session is not None and member_session.member.role_id >= role:
return wrapped_function(*args, **kwargs)

if auth == HEADER_AUTHORIZATION:
bearer = request.headers.get(auth)
token = bearer.split()[1]
authorized = validate_bearer(token)

if authorized is not None:
return wrapped_function(*args, **kwargs)

if auth == HEADER_CAS_AUTHORIZATION and validate_cas_request(request.headers[auth]) is not None:
return wrapped_function(*args, **kwargs)

if auth == HEADER_DPS_TOKEN and valid_dps_request():
return wrapped_function(*args, **kwargs)

abort(status.HTTP_403_FORBIDDEN, description="Not authorized.")

return wrap
return login_required_outer

def valid_dps_request():
if HEADER_DPS_TOKEN in request.headers:
return settings.DPS_MACHINE_TOKEN == request.headers[HEADER_DPS_TOKEN]
return False


def get_auth_header():
if HEADER_PROXY_TICKET in request.headers:
return HEADER_PROXY_TICKET
if HEADER_CP_TICKET in request.headers:
return HEADER_CP_TICKET
if HEADER_AUTHORIZATION in request.headers:
return HEADER_AUTHORIZATION
if HEADER_CAS_AUTHORIZATION in request.headers:
return HEADER_CAS_AUTHORIZATION
if HEADER_DPS_TOKEN in request.headers:
return HEADER_DPS_TOKEN
return None


def edl_federated_request(url, stream_response=False):
s = requests.Session()
response = s.get(url, stream=stream_response)

if response.status_code == status.HTTP_401_UNAUTHORIZED:
maap_user = get_authorized_user()

if maap_user is not None:
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=stream_response)

return response
Loading