From 5c5faca0752030a5de5ca8aa97e15c6d579487cb Mon Sep 17 00:00:00 2001 From: Noah Date: Sun, 19 Oct 2025 11:35:26 -0400 Subject: [PATCH 1/7] add redirect uri env support --- config.env.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config.env.py b/config.env.py index dab496a..5edea95 100644 --- a/config.env.py +++ b/config.env.py @@ -11,6 +11,8 @@ # OpenID Connect SSO config OIDC_ISSUER = os.environ.get('OIDC_ISSUER', 'https://sso.csh.rit.edu/auth/realms/csh') + +OIDC_REDIRECT_URI = os.environ.get('OIDC_REDIRECT_URI', 'https://eac.csh.rit.edu/redirect_uri') OIDC_CLIENT_CONFIG = { 'client_id': os.environ.get('OIDC_CLIENT_ID', ''), 'client_secret': os.environ.get('OIDC_CLIENT_SECRET', ''), From 1a029e47d65bc0259e56907df43508a4606f1234 Mon Sep 17 00:00:00 2001 From: Noah Date: Mon, 20 Oct 2025 12:45:40 -0400 Subject: [PATCH 2/7] github app auth as well as automatically adding people to org --- config.env.py | 4 ++-- eac/__init__.py | 29 +++++++++++++++++++++-------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/config.env.py b/config.env.py index 1bb5f82..bebbb31 100644 --- a/config.env.py +++ b/config.env.py @@ -30,9 +30,9 @@ SLACK_SECRET = os.environ.get('SLACK_SECRET', '') # GitHub secrets -GITHUB_OAUTH_CLIENT_ID = os.environ.get('GITHUB_OAUTH_CLIENT_ID', '') -GITHUB_OAUTH_CLIENT_SECRET = os.environ.get('GITHUB_OAUTH_CLIENT_SECRET', '') +GITHUB_REDIRECT_URI = os.environ.get('GITHUB_REDIRECT_URI', 'https://eac.csh.rit.edu/github/return') GITHUB_APP_CLIENT_ID = os.environ.get('GITHUB_APP_CLIENT_ID', '') +GITHUB_APP_CLIENT_SECRET = os.environ.get('GITHUB_APP_CLIENT_ID', '') GITHUB_APP_PRIVATE_KEY = os.environ.get('GITHUB_APP_PRIVATE_KEY', '') # Twitch secrets diff --git a/eac/__init__.py b/eac/__init__.py index 3188059..77ab14d 100644 --- a/eac/__init__.py +++ b/eac/__init__.py @@ -55,7 +55,9 @@ _GITHUB_AUTH_URI = 'https://github.com/login/oauth/authorize' \ + '?client_id=%s' \ - + '&state=%s' + + '&state=%s' \ + + '&redirect_uri=%s' + _GITHUB_TOKEN_URI = 'https://github.com/login/oauth/access_token' \ + '?client_id=%s' \ + '&client_secret=%s' \ @@ -151,7 +153,7 @@ def _auth_github() -> werkzeug.Response: # Redirect to github for authorisation return redirect( _GITHUB_AUTH_URI % - (APP.config['GITHUB_OAUTH_CLIENT_ID'], APP.config['STATE'])) + (APP.config['GITHUB_APP_CLIENT_ID'], APP.config['STATE'], urllib.parse.quote(APP.config['GITHUB_REDIRECT_URI'], safe=''))) @APP.route('/github/return', methods=['GET']) @@ -165,8 +167,8 @@ def _github_landing() -> tuple[str, int]: # Get token from github resp = requests.post( _GITHUB_TOKEN_URI % - (APP.config['GITHUB_OAUTH_CLIENT_ID'], - APP.config['GITHUB_OAUTH_CLIENT_SECRET'], request.args.get('code')), + (APP.config['GITHUB_APP_CLIENT_ID'], APP.config['GITHUB_APP_CLIENT_SECRET'], + request.args.get('code')), headers={'Accept': 'application/json'}, timeout=APP.config['REQUEST_TIMEOUT']) try: @@ -176,9 +178,9 @@ def _github_landing() -> tuple[str, int]: raise e resp_json = resp.json() - token = resp_json['access_token'] + user_token = resp_json['access_token'] header = { - 'Authorization': 'token ' + token, + 'Authorization': 'Bearer ' + user_token, 'Accept': 'application/vnd.github.v3+json' } @@ -200,7 +202,7 @@ def _github_landing() -> tuple[str, int]: uid = str(session['userinfo'].get('preferred_username', '')) member = _LDAP.get_member(uid, uid=True) - _link_github(github_username, github_id, member) + _link_github(github_username, github_id, member, user_token) return render_template('callback.html'), 200 @@ -255,7 +257,7 @@ def _auth_github_org() -> str: return org_token -def _link_github(github_username: str, github_id: str, member: Any) -> None: +def _link_github(github_username: str, github_id: str, member: Any, user_token: str) -> None: """ Puts a member's github into LDAP and adds them to the org. :param github_username: the user's github username @@ -286,6 +288,17 @@ def _link_github(github_username: str, github_id: str, member: Any) -> None: print('response:', resp.json()) raise e + github_user_headers = { + 'Accept': 'application/vnd.github.v3+json', + 'Authorization': f'Token {user_token}', + } + + requests.patch( + 'https://api.github.com/user/memberships/orgs/ComputerScienceHouse', + headers=github_user_headers, + json={'state': 'active'} + ) + member.github = github_username From ddede408316b19559406e7e73795c072014500a0 Mon Sep 17 00:00:00 2001 From: Noah Date: Mon, 20 Oct 2025 13:37:17 -0400 Subject: [PATCH 3/7] logging for key error to debug --- eac/__init__.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/eac/__init__.py b/eac/__init__.py index 77ab14d..f1ec145 100644 --- a/eac/__init__.py +++ b/eac/__init__.py @@ -178,7 +178,12 @@ def _github_landing() -> tuple[str, int]: raise e resp_json = resp.json() - user_token = resp_json['access_token'] + try: + user_token = resp_json['access_token'] + except KeyError as e: + print('error: ', e, resp_json) + raise e + header = { 'Authorization': 'Bearer ' + user_token, 'Accept': 'application/vnd.github.v3+json' From 67377eefb15edc58c8225711fd9e529aeeb2ff72 Mon Sep 17 00:00:00 2001 From: Noah Date: Mon, 20 Oct 2025 13:38:34 -0400 Subject: [PATCH 4/7] remove github from ldap before deleting to fix desync error --- eac/__init__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/eac/__init__.py b/eac/__init__.py index f1ec145..cf730ad 100644 --- a/eac/__init__.py +++ b/eac/__init__.py @@ -314,6 +314,9 @@ def _revoke_github() -> werkzeug.Response: uid = str(session['userinfo'].get('preferred_username', '')) member = _LDAP.get_member(uid, uid=True) + github_id = member.github + member.github = None + org_token = _auth_github_org() headers = { @@ -322,8 +325,7 @@ def _revoke_github() -> werkzeug.Response: } resp = requests.delete( - 'https://api.github.com/orgs/ComputerScienceHouse/members/' + - member.github, + 'https://api.github.com/orgs/ComputerScienceHouse/members/' + github_id, headers=headers, timeout=APP.config['REQUEST_TIMEOUT'], ) @@ -334,7 +336,6 @@ def _revoke_github() -> werkzeug.Response: print('response:', resp.json()) raise e - member.github = None return jsonify(success=True) From f9fafbdc68afcef48b38237486a5a71ad8196650 Mon Sep 17 00:00:00 2001 From: Noah Date: Mon, 20 Oct 2025 13:55:50 -0400 Subject: [PATCH 5/7] fixed env var name --- config.env.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.env.py b/config.env.py index bebbb31..a741a34 100644 --- a/config.env.py +++ b/config.env.py @@ -32,7 +32,7 @@ # GitHub secrets GITHUB_REDIRECT_URI = os.environ.get('GITHUB_REDIRECT_URI', 'https://eac.csh.rit.edu/github/return') GITHUB_APP_CLIENT_ID = os.environ.get('GITHUB_APP_CLIENT_ID', '') -GITHUB_APP_CLIENT_SECRET = os.environ.get('GITHUB_APP_CLIENT_ID', '') +GITHUB_APP_CLIENT_SECRET = os.environ.get('GITHUB_APP_CLIENT_SECRET', '') GITHUB_APP_PRIVATE_KEY = os.environ.get('GITHUB_APP_PRIVATE_KEY', '') # Twitch secrets From 89901c492627ea11d65bac949c7c7926c892ab8d Mon Sep 17 00:00:00 2001 From: Noah Date: Mon, 20 Oct 2025 14:13:08 -0400 Subject: [PATCH 6/7] linting --- config.env.py | 6 ++++-- eac/__init__.py | 17 ++++++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/config.env.py b/config.env.py index a741a34..cd8cd52 100644 --- a/config.env.py +++ b/config.env.py @@ -12,7 +12,8 @@ OIDC_ISSUER = os.environ.get('OIDC_ISSUER', 'https://sso.csh.rit.edu/auth/realms/csh') -OIDC_REDIRECT_URI = os.environ.get('OIDC_REDIRECT_URI', 'https://eac.csh.rit.edu/redirect_uri') +OIDC_REDIRECT_URI = os.environ.get('OIDC_REDIRECT_URI', + 'https://eac.csh.rit.edu/redirect_uri') OIDC_CLIENT_CONFIG = { 'client_id': os.environ.get('OIDC_CLIENT_ID', ''), 'client_secret': os.environ.get('OIDC_CLIENT_SECRET', ''), @@ -30,7 +31,8 @@ SLACK_SECRET = os.environ.get('SLACK_SECRET', '') # GitHub secrets -GITHUB_REDIRECT_URI = os.environ.get('GITHUB_REDIRECT_URI', 'https://eac.csh.rit.edu/github/return') +GITHUB_REDIRECT_URI = os.environ.get('GITHUB_REDIRECT_URI', + 'https://eac.csh.rit.edu/github/return') GITHUB_APP_CLIENT_ID = os.environ.get('GITHUB_APP_CLIENT_ID', '') GITHUB_APP_CLIENT_SECRET = os.environ.get('GITHUB_APP_CLIENT_SECRET', '') GITHUB_APP_PRIVATE_KEY = os.environ.get('GITHUB_APP_PRIVATE_KEY', '') diff --git a/eac/__init__.py b/eac/__init__.py index cf730ad..409adc4 100644 --- a/eac/__init__.py +++ b/eac/__init__.py @@ -153,7 +153,8 @@ def _auth_github() -> werkzeug.Response: # Redirect to github for authorisation return redirect( _GITHUB_AUTH_URI % - (APP.config['GITHUB_APP_CLIENT_ID'], APP.config['STATE'], urllib.parse.quote(APP.config['GITHUB_REDIRECT_URI'], safe=''))) + (APP.config['GITHUB_APP_CLIENT_ID'], APP.config['STATE'], + urllib.parse.quote(APP.config['GITHUB_REDIRECT_URI'], safe=''))) @APP.route('/github/return', methods=['GET']) @@ -167,8 +168,8 @@ def _github_landing() -> tuple[str, int]: # Get token from github resp = requests.post( _GITHUB_TOKEN_URI % - (APP.config['GITHUB_APP_CLIENT_ID'], APP.config['GITHUB_APP_CLIENT_SECRET'], - request.args.get('code')), + (APP.config['GITHUB_APP_CLIENT_ID'], + APP.config['GITHUB_APP_CLIENT_SECRET'], request.args.get('code')), headers={'Accept': 'application/json'}, timeout=APP.config['REQUEST_TIMEOUT']) try: @@ -262,7 +263,8 @@ def _auth_github_org() -> str: return org_token -def _link_github(github_username: str, github_id: str, member: Any, user_token: str) -> None: +def _link_github(github_username: str, github_id: str, member: Any, + user_token: str) -> None: """ Puts a member's github into LDAP and adds them to the org. :param github_username: the user's github username @@ -301,8 +303,8 @@ def _link_github(github_username: str, github_id: str, member: Any, user_token: requests.patch( 'https://api.github.com/user/memberships/orgs/ComputerScienceHouse', headers=github_user_headers, - json={'state': 'active'} - ) + json={'state': 'active'}, + timeout=APP.config['REQUEST_TIMEOUT']) member.github = github_username @@ -325,7 +327,8 @@ def _revoke_github() -> werkzeug.Response: } resp = requests.delete( - 'https://api.github.com/orgs/ComputerScienceHouse/members/' + github_id, + 'https://api.github.com/orgs/ComputerScienceHouse/members/' + + github_id, headers=headers, timeout=APP.config['REQUEST_TIMEOUT'], ) From aadfabab7c104c9345e3122b20fbb24a89140521 Mon Sep 17 00:00:00 2001 From: Noah Date: Mon, 20 Oct 2025 20:30:38 -0400 Subject: [PATCH 7/7] moved when ldap github user role is removed --- eac/__init__.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/eac/__init__.py b/eac/__init__.py index 409adc4..dd22928 100644 --- a/eac/__init__.py +++ b/eac/__init__.py @@ -316,9 +316,6 @@ def _revoke_github() -> werkzeug.Response: uid = str(session['userinfo'].get('preferred_username', '')) member = _LDAP.get_member(uid, uid=True) - github_id = member.github - member.github = None - org_token = _auth_github_org() headers = { @@ -328,7 +325,7 @@ def _revoke_github() -> werkzeug.Response: resp = requests.delete( 'https://api.github.com/orgs/ComputerScienceHouse/members/' + - github_id, + member.github, headers=headers, timeout=APP.config['REQUEST_TIMEOUT'], ) @@ -339,6 +336,7 @@ def _revoke_github() -> werkzeug.Response: print('response:', resp.json()) raise e + member.github = None return jsonify(success=True)