Skip to content

Commit 227c770

Browse files
authored
Update the auth management example scripts (#1417)
2 parents 3e5a748 + 7b08829 commit 227c770

4 files changed

Lines changed: 62 additions & 252 deletions

File tree

docs/examples/auth_manage_projects/index.rst

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,19 @@
11
Manage Globus Auth Projects
22
===========================
33

4-
.. note::
5-
6-
The following scripts, when run, may leave tokens in a JSON file in
7-
your home directory. Be sure to delete these tokens after use.
8-
94
List Projects via the Auth API
105
------------------------------
116

127
The following is a very small and simple script using the Globus Auth Developer
138
APIs.
149

1510
It uses the tutorial client ID from the :ref:`tutorials <tutorials>`.
16-
For simplicity, the script will prompt for login on each use.
1711

1812
.. literalinclude:: list_projects.py
1913
:caption: ``list_projects.py`` [:download:`download <list_projects.py>`]
2014
:language: python
2115

2216

23-
List and Create Projects via the Auth API
24-
-----------------------------------------
25-
26-
The next example builds upon the earlier example by offering a pair of
27-
features, List and Create.
28-
29-
Argument parsing allows for an action to be selected, which is then executed by
30-
calling the appropriate function.
31-
32-
.. literalinclude:: list_and_create_projects.py
33-
:caption: ``list_and_create_projects.py`` [:download:`download <list_and_create_projects.py>`]
34-
:language: python
35-
36-
3717
List, Create, and Delete Projects via the Auth API
3818
--------------------------------------------------
3919

@@ -44,16 +24,16 @@ List, Create, and Delete Projects via the Auth API
4424
Deleting projects may be harmful to your production applications.
4525
Only delete with care.
4626

47-
The following example expands upon the former by adding delete functionality.
27+
The following example builds upon the earlier example by offering multiple
28+
features: List, Create, and Delete.
4829

49-
Because Delete requires authentication under a session policy, the login code
50-
grows here to include a storage adapter (with data kept in
51-
``~/.sdk-manage-projects.json``). If a policy failure is encountered, the code
52-
will prompt the user to login again to satisfy the policy and then reexecute
53-
the desired activity.
30+
Argument parsing allows for an action to be selected, which is then executed by
31+
calling the appropriate function.
5432

55-
As a result, this example is significantly more complex, but it still follows
56-
the same basic pattern as above.
33+
Because Delete requires authentication under a session policy, we set
34+
the ``auto_redrive_gares`` configuration, which handles unsatisfied auth
35+
requirements. If a policy failure is encountered, the code will prompt the user
36+
to login again to satisfy the policy and then reexecute the desired activity.
5737

5838
.. literalinclude:: manage_projects.py
5939
:caption: ``manage_projects.py`` [:download:`download <manage_projects.py>`]

docs/examples/auth_manage_projects/list_and_create_projects.py

Lines changed: 0 additions & 80 deletions
This file was deleted.

docs/examples/auth_manage_projects/list_projects.py

Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,21 @@
1-
#!/usr/bin/env python
2-
31
import globus_sdk
42

5-
SCOPES = [globus_sdk.AuthClient.scopes.manage_projects, "openid", "email"]
6-
RESOURCE_SERVER = globus_sdk.AuthClient.resource_server
7-
83
# tutorial client ID
94
# we recommend replacing this with your own client for any production use-cases
105
CLIENT_ID = "61338d24-54d5-408f-a10d-66c06b59f6d2"
116

12-
NATIVE_CLIENT = globus_sdk.NativeAppAuthClient(CLIENT_ID)
13-
14-
15-
def do_login_flow():
16-
NATIVE_CLIENT.oauth2_start_flow(requested_scopes=SCOPES)
17-
authorize_url = NATIVE_CLIENT.oauth2_get_authorize_url()
18-
print(f"Please go to this URL and login:\n\n{authorize_url}\n")
19-
auth_code = input("Please enter the code here: ").strip()
20-
tokens = NATIVE_CLIENT.oauth2_exchange_code_for_tokens(auth_code)
21-
return tokens.by_resource_server[RESOURCE_SERVER]
22-
23-
24-
def get_auth_client():
25-
tokens = do_login_flow()
26-
return globus_sdk.AuthClient(
27-
authorizer=globus_sdk.AccessTokenAuthorizer(tokens["access_token"])
28-
)
29-
307

31-
def main():
32-
auth_client = get_auth_client()
33-
for project in auth_client.get_projects():
34-
print(f"name: {project['display_name']}")
35-
print(f"id: {project['id']}")
36-
print()
8+
def main() -> None:
9+
with (
10+
globus_sdk.UserApp("list-projects-example", client_id=CLIENT_ID) as app,
11+
globus_sdk.AuthClient(
12+
app_scopes=[globus_sdk.AuthClient.scopes.manage_projects], app=app
13+
) as auth_client,
14+
):
15+
for project in auth_client.get_projects():
16+
print(f"name: {project['display_name']}")
17+
print(f"id: {project['id']}")
18+
print()
3719

3820

3921
if __name__ == "__main__":

docs/examples/auth_manage_projects/manage_projects.py

Lines changed: 43 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,144 +1,72 @@
1-
#!/usr/bin/env python
2-
31
import argparse
4-
import os
52

63
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
154

165
# tutorial client ID
176
# we recommend replacing this with your own client for any production use-cases
187
CLIENT_ID = "61338d24-54d5-408f-a10d-66c06b59f6d2"
198

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-
389

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:
5511
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,
5718
)
5819

5920

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+
)
6828
)
69-
)
7029

7130

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))
7534

7635

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()
8342

8443

85-
def main():
44+
def main() -> None:
8645
parser = argparse.ArgumentParser()
8746
parser.add_argument("action", choices=["create", "delete", "list"])
8847
parser.add_argument("-p", "--project-id", help="Project ID for delete")
8948
parser.add_argument("-n", "--name", help="Project name for create")
9049
args = parser.parse_args()
9150

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()
14270

14371

14472
if __name__ == "__main__":

0 commit comments

Comments
 (0)