-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #14 from esgf2-us/globus_setup
Register the West STAC Transaction API resource server client
- Loading branch information
Showing
1 changed file
with
142 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
import os | ||
import sys | ||
import argparse | ||
import json | ||
from globus_sdk import NativeAppAuthClient, RefreshTokenAuthorizer, AuthClient | ||
from globus_sdk.scopes import AuthScopes | ||
from globus_sdk import AuthAPIError | ||
from globus_sdk.tokenstorage import SimpleJSONFileAdapter | ||
|
||
|
||
globus_client_id = "ab9883f5-37d4-4066-b69f-ff3313e16dd8" | ||
view_my_groups_and_memberships_scope_uuid = "73320ffe-4cb4-4b25-a0a3-83d53d59ce4f" | ||
|
||
|
||
class WestDeployment: | ||
def __init__(self): | ||
self.native_client = NativeAppAuthClient(client_id=globus_client_id, app_name="West Deployment Client") | ||
self.scopes = [AuthScopes.manage_projects, "openid", "profile", "email"] | ||
filename = os.path.expanduser("~/.deployment_tokens.json") | ||
self.token_storage = SimpleJSONFileAdapter(filename) | ||
|
||
def do_login_flow(self): | ||
self.native_client.oauth2_start_flow(requested_scopes=self.scopes, refresh_tokens=True) | ||
authorize_url = self.native_client.oauth2_get_authorize_url(prompt="login") | ||
print("Please go to this URL and login: {0}".format(authorize_url)) | ||
auth_code = input("Please enter the code here: ").strip() | ||
return self.native_client.oauth2_exchange_code_for_tokens(auth_code) | ||
|
||
def get_tokens(self, resource_server, prompt=None): | ||
if not self.token_storage.file_exists() or prompt: | ||
response = self.do_login_flow() | ||
self.token_storage.store(response) | ||
tokens = response.by_resource_server[resource_server] | ||
else: | ||
tokens = self.token_storage.get_token_data(resource_server) | ||
return tokens | ||
|
||
def get_auth_client(self, prompt=None): | ||
tokens = self.get_tokens(AuthClient.resource_server, prompt) | ||
auth_authorizer = RefreshTokenAuthorizer( | ||
tokens["refresh_token"], | ||
self.native_client, | ||
access_token=tokens["access_token"], | ||
expires_at=tokens["expires_at_seconds"], | ||
on_refresh=self.token_storage, | ||
) | ||
auth_client = AuthClient(authorizer=auth_authorizer) | ||
return auth_client | ||
|
||
def get_user_info(self): | ||
r = self.auth_client.userinfo() | ||
self.sub = r.data.get("sub") | ||
self.email = r.data.get("email") | ||
print(f"sub: {self.sub}, email: {self.email}") | ||
|
||
def get_project(self): | ||
r = self.auth_client.get_projects() | ||
# print(json.dumps(r.data, indent=4)) | ||
project_id = None | ||
for project in r.data.get("projects", []): | ||
project_name = project.get("project_name", "") | ||
display_name = project.get("display_name", "") | ||
if project_name != "ESGF2 Data Challenges" or display_name != "ESGF2 Data Challenges": | ||
continue | ||
admin_identities = project.get("admins", []).get("identities", []) | ||
for identity in admin_identities: | ||
if identity.get("id") == self.sub: | ||
project_id = project.get("id") | ||
break | ||
if project_id: | ||
break | ||
|
||
if not project_id: | ||
r = self.auth_client.create_project("ESGF2 Data Challenges", self.email, admin_ids=[self.sub]) | ||
project_id = r.data.get("project", {}).get("id") | ||
self.project_id = project_id | ||
print(f"project_id: {self.project_id}") | ||
|
||
def get_client(self, new_client_name): | ||
r = self.auth_client.get_clients() | ||
for client in r.data.get("clients", []): | ||
project_id = client.get("project", "") | ||
if project_id != self.project_id: | ||
continue | ||
name = client.get("name", "") | ||
if name != new_client_name: | ||
continue | ||
print(json.dumps(client, indent=4)) | ||
print(f"Error: client '{new_client_name}' already exists") | ||
sys.exit(1) | ||
|
||
def create_client(self, new_client_name): | ||
r = self.auth_client.create_client(new_client_name, self.project_id, client_type="resource_server") | ||
|
||
self.service_client_id = r.data.get("client").get("id") | ||
r = self.auth_client.create_client_credential(self.service_client_id, "STAC Transaction API service client") | ||
print(json.dumps(r.data, indent=4)) | ||
self.service_client_secret = r.data.get("credential").get("secret") | ||
|
||
def get_dependent_scope(self): | ||
r = self.auth_client.create_scope( | ||
self.service_client_id, | ||
"ESGF West STAC Transaction API", | ||
"Verify membership in ESGF Publisher groups", | ||
"esgf", | ||
dependent_scopes=[ | ||
{ | ||
"scope": view_my_groups_and_memberships_scope_uuid, | ||
"optional": False, | ||
"requires_refresh_token": True, | ||
} | ||
], | ||
advertised=True, | ||
) | ||
print(json.dumps(r.data, indent=4)) | ||
|
||
def setup_service_client(self, name_suffix): | ||
self.auth_client = self.get_auth_client() | ||
self.get_user_info() | ||
self.get_project() | ||
new_client_name = f"ESGF2 Data Challenge Transaction API service client - {name_suffix}" | ||
self.get_client(new_client_name) | ||
try: | ||
self.create_client(new_client_name) | ||
except AuthAPIError: | ||
self.auth_client = self.get_auth_client(prompt="login") | ||
self.create_client(new_client_name) | ||
|
||
self.get_dependent_scope() | ||
|
||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument( | ||
"--client-name-suffix", | ||
required=True, | ||
help="suffix that will be added to the client name 'ESGF2 Data Challenge Transaction API service client - '", | ||
) | ||
args = parser.parse_args() | ||
|
||
wd = WestDeployment() | ||
wd.setup_service_client(args.client_name_suffix) |