|
1 | | -#!/usr/bin/env python |
2 | | - |
3 | 1 | import argparse |
4 | | -import os |
5 | 2 |
|
6 | 3 | import globus_sdk |
7 | | -from globus_sdk.token_storage import SimpleJSONFileAdapter |
8 | | - |
9 | | -MY_FILE_ADAPTER = SimpleJSONFileAdapter( |
10 | | - os.path.expanduser("~/.sdk-manage-projects.json") |
11 | | -) |
12 | | - |
13 | | -SCOPES = [globus_sdk.AuthClient.scopes.manage_projects, "openid", "email"] |
14 | | -RESOURCE_SERVER = globus_sdk.AuthClient.resource_server |
15 | 4 |
|
16 | 5 | # tutorial client ID |
17 | 6 | # we recommend replacing this with your own client for any production use-cases |
18 | 7 | CLIENT_ID = "61338d24-54d5-408f-a10d-66c06b59f6d2" |
19 | 8 |
|
20 | | -NATIVE_CLIENT = globus_sdk.NativeAppAuthClient(CLIENT_ID) |
21 | | - |
22 | | - |
23 | | -def do_login_flow(*, session_params: dict | None = None): |
24 | | - NATIVE_CLIENT.oauth2_start_flow(requested_scopes=SCOPES) |
25 | | - # special note! |
26 | | - # this works because oauth2_get_authorize_url supports session error data |
27 | | - # as parameters to build the authorization URL |
28 | | - # you could do this manually with the following supported parameters: |
29 | | - # - session_required_identities |
30 | | - # - session_required_single_domain |
31 | | - # - session_required_policies |
32 | | - authorize_url = NATIVE_CLIENT.oauth2_get_authorize_url(**session_params) |
33 | | - print(f"Please go to this URL and login:\n\n{authorize_url}\n") |
34 | | - auth_code = input("Please enter the code here: ").strip() |
35 | | - tokens = NATIVE_CLIENT.oauth2_exchange_code_for_tokens(auth_code) |
36 | | - return tokens |
37 | | - |
38 | 9 |
|
39 | | -def get_tokens(): |
40 | | - if not MY_FILE_ADAPTER.file_exists(): |
41 | | - # do a login flow, getting back initial tokens |
42 | | - response = do_login_flow() |
43 | | - # now store the tokens and pull out the correct token |
44 | | - MY_FILE_ADAPTER.store(response) |
45 | | - tokens = response.by_resource_server[RESOURCE_SERVER] |
46 | | - else: |
47 | | - # otherwise, we already did login; load the tokens from that file |
48 | | - tokens = MY_FILE_ADAPTER.get_token_data(RESOURCE_SERVER) |
49 | | - |
50 | | - return tokens |
51 | | - |
52 | | - |
53 | | -def get_auth_client(): |
54 | | - tokens = get_tokens() |
| 10 | +def get_auth_client(app: globus_sdk.GlobusApp) -> globus_sdk.AuthClient: |
55 | 11 | return globus_sdk.AuthClient( |
56 | | - authorizer=globus_sdk.AccessTokenAuthorizer(tokens["access_token"]) |
| 12 | + app_scopes=[ |
| 13 | + globus_sdk.AuthClient.scopes.manage_projects, |
| 14 | + globus_sdk.AuthClient.scopes.openid, |
| 15 | + globus_sdk.AuthClient.scopes.email, |
| 16 | + ], |
| 17 | + app=app, |
57 | 18 | ) |
58 | 19 |
|
59 | 20 |
|
60 | | -def create_project(args): |
61 | | - auth_client = get_auth_client() |
62 | | - userinfo = auth_client.userinfo() |
63 | | - print( |
64 | | - auth_client.create_project( |
65 | | - args.name, |
66 | | - contact_email=userinfo["email"], |
67 | | - admin_ids=userinfo["sub"], |
| 21 | +def create_project(app: globus_sdk.GlobusApp, name: str) -> None: |
| 22 | + with get_auth_client(app) as auth_client: |
| 23 | + userinfo = auth_client.userinfo() |
| 24 | + print( |
| 25 | + auth_client.create_project( |
| 26 | + name, contact_email=userinfo["email"], admin_ids=userinfo["sub"] |
| 27 | + ) |
68 | 28 | ) |
69 | | - ) |
70 | 29 |
|
71 | 30 |
|
72 | | -def delete_project(args): |
73 | | - auth_client = get_auth_client() |
74 | | - print(auth_client.delete_project(args.project_id)) |
| 31 | +def delete_project(app: globus_sdk.GlobusApp, project_id: str) -> None: |
| 32 | + with get_auth_client(app) as auth_client: |
| 33 | + print(auth_client.delete_project(project_id)) |
75 | 34 |
|
76 | 35 |
|
77 | | -def list_projects(): |
78 | | - auth_client = get_auth_client() |
79 | | - for project in auth_client.get_projects(): |
80 | | - print(f"name: {project['display_name']}") |
81 | | - print(f"id: {project['id']}") |
82 | | - print() |
| 36 | +def list_projects(app: globus_sdk.GlobusApp) -> None: |
| 37 | + with get_auth_client(app) as auth_client: |
| 38 | + for project in auth_client.get_projects(): |
| 39 | + print(f"name: {project['display_name']}") |
| 40 | + print(f"id: {project['id']}") |
| 41 | + print() |
83 | 42 |
|
84 | 43 |
|
85 | | -def main(): |
| 44 | +def main() -> None: |
86 | 45 | parser = argparse.ArgumentParser() |
87 | 46 | parser.add_argument("action", choices=["create", "delete", "list"]) |
88 | 47 | parser.add_argument("-p", "--project-id", help="Project ID for delete") |
89 | 48 | parser.add_argument("-n", "--name", help="Project name for create") |
90 | 49 | args = parser.parse_args() |
91 | 50 |
|
92 | | - try: |
93 | | - execute(parser, args) |
94 | | - except globus_sdk.GlobusAPIError as err: |
95 | | - if not err.info.authorization_parameters: |
96 | | - raise |
97 | | - |
98 | | - err_params = err.info.authorization_parameters |
99 | | - session_params = {} |
100 | | - if err_params.session_required_identities: |
101 | | - print("session required identities detected") |
102 | | - session_params["session_required_identities"] = ( |
103 | | - err_params.session_required_identities |
104 | | - ) |
105 | | - if err_params.session_required_single_domain: |
106 | | - print("session required single domain detected") |
107 | | - session_params["session_required_single_domain"] = ( |
108 | | - err_params.session_required_single_domain |
109 | | - ) |
110 | | - if err_params.session_required_policies: |
111 | | - print("session required policies detected") |
112 | | - session_params["session_required_policies"] = ( |
113 | | - err_params.session_required_policies |
114 | | - ) |
115 | | - print(session_params) |
116 | | - print(err_params) |
117 | | - response = do_login_flow(session_params=session_params) |
118 | | - # now store the tokens |
119 | | - MY_FILE_ADAPTER.store(response) |
120 | | - print( |
121 | | - "Reauthenticated successfully to satisfy " |
122 | | - "session requirements. Will now try again.\n" |
123 | | - ) |
124 | | - |
125 | | - # try the action again |
126 | | - execute(parser, args) |
127 | | - |
128 | | - |
129 | | -def execute(parser, args): |
130 | | - if args.action == "create": |
131 | | - if args.name is None: |
132 | | - parser.error("create requires --name") |
133 | | - create_project(args) |
134 | | - elif args.action == "delete": |
135 | | - if args.project_id is None: |
136 | | - parser.error("delete requires --project-id") |
137 | | - delete_project(args) |
138 | | - elif args.action == "list": |
139 | | - list_projects() |
140 | | - else: |
141 | | - raise NotImplementedError() |
| 51 | + with globus_sdk.UserApp( |
| 52 | + "manage-projects-example", |
| 53 | + client_id=CLIENT_ID, |
| 54 | + # we set 'auto_redrive_gares', so that any authentication policy errors will |
| 55 | + # trigger an automatic second login |
| 56 | + config=globus_sdk.GlobusAppConfig(auto_redrive_gares=True), |
| 57 | + ) as app: |
| 58 | + if args.action == "create": |
| 59 | + if args.name is None: |
| 60 | + parser.error("create requires --name") |
| 61 | + create_project(app, args.name) |
| 62 | + elif args.action == "delete": |
| 63 | + if args.project_id is None: |
| 64 | + parser.error("delete requires --project-id") |
| 65 | + delete_project(app, args.project_id) |
| 66 | + elif args.action == "list": |
| 67 | + list_projects(app) |
| 68 | + else: |
| 69 | + raise NotImplementedError() |
142 | 70 |
|
143 | 71 |
|
144 | 72 | if __name__ == "__main__": |
|
0 commit comments