Skip to content

Commit f4cfe8c

Browse files
authored
Merge pull request #358 from ASFHyP3/develop
Release v7.7.0
2 parents 6fd41e2 + e0b4879 commit f4cfe8c

File tree

10 files changed

+286
-17
lines changed

10 files changed

+286
-17
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [PEP 440](https://www.python.org/dev/peps/pep-0440/)
77
and uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
88

9+
## [7.7.0]
10+
11+
### Added
12+
* Added support for using an [Earthdata Login Bearer Token](https://urs.earthdata.nasa.gov/documentation/for_users/user_token) when authenticating the `HyP3` object.
13+
914
## [7.6.0]
1015
### Changed
1116
* `ARIA-S1-GUNW` jobs now uses `reference_date` and `secondary_date` as input instead of a list of granules

docs/hyp3_authentication.ipynb

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "c71ac86b03faa125",
6+
"metadata": {
7+
"collapsed": false
8+
},
9+
"source": [
10+
"# Authenticating a HyP3 Session with the SDK\n",
11+
"\n",
12+
"When initializing a HyP3 object with the HyP3 SDK, you have three options:\n",
13+
"1. Input your EDL username and password\n",
14+
"2. Input your EDL Bearer Token\n",
15+
"3. Store your credentials locally in a .netrc file in your home directory\n",
16+
"\n",
17+
"This tutorial will walk you through each of these authentication methods. If you have not created an Earthdata Login account yet, make sure to do so here: https://urs.earthdata.nasa.gov/users/new.\n",
18+
"\n",
19+
"Likewise, before starting, make sure you have `hyp3-sdk` installed locally and ensure the version is >=7.7.0."
20+
]
21+
},
22+
{
23+
"cell_type": "code",
24+
"execution_count": null,
25+
"id": "6b0bbf63de13b184",
26+
"metadata": {
27+
"collapsed": false
28+
},
29+
"outputs": [],
30+
"source": [
31+
"!pip install 'hyp3-sdk>=7.7.0'"
32+
]
33+
},
34+
{
35+
"cell_type": "code",
36+
"execution_count": null,
37+
"outputs": [],
38+
"source": [
39+
"import hyp3_sdk as sdk"
40+
],
41+
"metadata": {
42+
"collapsed": false
43+
},
44+
"id": "a38df62d8552468b"
45+
},
46+
{
47+
"cell_type": "markdown",
48+
"id": "6a29e00aa30bdf90",
49+
"metadata": {
50+
"collapsed": false
51+
},
52+
"source": [
53+
"## Using your username and password\n",
54+
"This option requires minimal amount of set up. All you need is to know your EDL username and password. You can either prompt for a username and password by passing `password` in as `prompt`:"
55+
]
56+
},
57+
{
58+
"cell_type": "code",
59+
"execution_count": null,
60+
"id": "3fa21cf01ff3ca32",
61+
"metadata": {
62+
"collapsed": false
63+
},
64+
"outputs": [],
65+
"source": [
66+
"HyP3 = sdk.HyP3(prompt='password')"
67+
]
68+
},
69+
{
70+
"cell_type": "markdown",
71+
"id": "1095f5668639490b",
72+
"metadata": {
73+
"collapsed": false
74+
},
75+
"source": [
76+
"Or pass them directly:"
77+
]
78+
},
79+
{
80+
"cell_type": "code",
81+
"execution_count": null,
82+
"id": "f2b96d74e0d60fc1",
83+
"metadata": {
84+
"collapsed": false
85+
},
86+
"outputs": [],
87+
"source": [
88+
"username = 'myusername'\n",
89+
"password = 'mypassword'\n",
90+
"\n",
91+
"HyP3 = sdk.HyP3(username=username, password=password)"
92+
]
93+
},
94+
{
95+
"cell_type": "markdown",
96+
"id": "4d0b9fa22a7d6aa",
97+
"metadata": {
98+
"collapsed": false
99+
},
100+
"source": [
101+
"## Using your EDL Bearer Token\n",
102+
"Alternatively, you can authenticate your HyP3 object using your EDL token. Follow this documentation to create one: https://urs.earthdata.nasa.gov/documentation/for_users/user_token.\n",
103+
"\n",
104+
"Once that token is set up, prompt for an EDL token:"
105+
]
106+
},
107+
{
108+
"cell_type": "code",
109+
"execution_count": null,
110+
"outputs": [],
111+
"source": [
112+
"HyP3 = sdk.HyP3(prompt='token')"
113+
],
114+
"metadata": {
115+
"collapsed": false
116+
},
117+
"id": "7805f87763471220"
118+
},
119+
{
120+
"cell_type": "markdown",
121+
"source": [
122+
"Or pass it directly:"
123+
],
124+
"metadata": {
125+
"collapsed": false
126+
},
127+
"id": "19f255f3f2c1a7c4"
128+
},
129+
{
130+
"cell_type": "code",
131+
"execution_count": null,
132+
"id": "ae92262a7e05b711",
133+
"metadata": {
134+
"collapsed": false
135+
},
136+
"outputs": [],
137+
"source": [
138+
"token = 'mytoken'\n",
139+
"HyP3 = sdk.HyP3(token=token)"
140+
]
141+
},
142+
{
143+
"cell_type": "markdown",
144+
"id": "c9fd77b21a1122bb",
145+
"metadata": {
146+
"collapsed": false
147+
},
148+
"source": [
149+
"## Using a local .netrc file\n",
150+
"This option take a bit more effort to set up but saves time in the long run. You will create a .netrc file in your local home directory. \n",
151+
"\n",
152+
"You can do this by running the following commands, replacing `USER` and `PASSWORD` with your EDL username and password:"
153+
]
154+
},
155+
{
156+
"cell_type": "code",
157+
"execution_count": null,
158+
"id": "561b0abd53726fec",
159+
"metadata": {
160+
"collapsed": false
161+
},
162+
"outputs": [],
163+
"source": [
164+
"%%bash\n",
165+
"echo 'machine urs.earthdata.nasa.gov login USER password PASSWORD' > ~/.netrc\n",
166+
"chmod 0600 ~/.netrc"
167+
]
168+
},
169+
{
170+
"cell_type": "markdown",
171+
"id": "27ee6339a540cb39",
172+
"metadata": {
173+
"collapsed": false
174+
},
175+
"source": [
176+
"Now, when you initialize the HyP3 object, your credentials will be pulled from the .netrc file:"
177+
]
178+
},
179+
{
180+
"cell_type": "code",
181+
"execution_count": null,
182+
"id": "e7bb4b87181a5660",
183+
"metadata": {
184+
"collapsed": false
185+
},
186+
"outputs": [],
187+
"source": [
188+
"HyP3 = sdk.HyP3()"
189+
]
190+
}
191+
],
192+
"metadata": {
193+
"kernelspec": {
194+
"display_name": "Python 3",
195+
"language": "python",
196+
"name": "python3"
197+
},
198+
"language_info": {
199+
"codemirror_mode": {
200+
"name": "ipython",
201+
"version": 2
202+
},
203+
"file_extension": ".py",
204+
"mimetype": "text/x-python",
205+
"name": "python",
206+
"nbconvert_exporter": "python",
207+
"pygments_lexer": "ipython2",
208+
"version": "2.7.6"
209+
}
210+
},
211+
"nbformat": 4,
212+
"nbformat_minor": 5
213+
}

docs/hyp3_job_name_change.ipynb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
},
2222
"outputs": [],
2323
"source": [
24-
"!pip install 'hyp3-sdk>=7.3.0' \n",
24+
"!pip install 'hyp3-sdk>=7.7.0' \n",
2525
"\n",
2626
"import hyp3_sdk as sdk"
2727
]
@@ -45,7 +45,7 @@
4545
},
4646
"outputs": [],
4747
"source": [
48-
"hyp3 = sdk.HyP3(prompt=True)\n",
48+
"hyp3 = sdk.HyP3(prompt='token')\n",
4949
"\n",
5050
"project_name = 'renameDemo'\n",
5151
"reference = 'S1_136231_IW2_20200604T022312_VV_7C85-BURST'\n",

docs/sdk_example.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
"outputs": [],
8787
"source": [
8888
"# or enter your credentials\n",
89-
"hyp3 = sdk.HyP3(prompt=True)"
89+
"hyp3 = sdk.HyP3(prompt='token')"
9090
]
9191
},
9292
{

docs/search_other_user_jobs.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"from hyp3_sdk import HyP3\n",
1515
"\n",
1616
"\n",
17-
"hyp3 = HyP3()\n",
17+
"hyp3 = HyP3(prompt='token')\n",
1818
"my_rtc_jobs = hyp3.find_jobs(name='rtc-example')"
1919
]
2020
},

src/hyp3_sdk/hyp3.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ def __init__(
3030
api_url: str = PROD_API,
3131
username: str | None = None,
3232
password: str | None = None,
33-
prompt: bool = False,
33+
token: str | None = None,
34+
prompt: Literal['password', 'token'] | bool | None = None,
3435
):
3536
"""If username and password are not provided, attempts to use credentials from a `.netrc` file.
3637
@@ -40,17 +41,31 @@ def __init__(
4041
Both username and password must be provided if either is provided.
4142
password: Password for authenticating to `urs.earthdata.nasa.gov`.
4243
Both username and password must be provided if either is provided.
43-
prompt: Prompt for username and/or password interactively when they
44-
are not provided as keyword parameters
44+
token: Earthdata Login Bearer Token for authenticating to `urs.earthdata.nasa.gov`
45+
prompt: Either 'password' or 'token' to prompt for EDL username and password or EDL bearer token, respectively.
4546
"""
4647
self.url = api_url
4748

48-
if username is None and prompt:
49-
username = input('NASA Earthdata Login username: ')
50-
if password is None and prompt:
51-
password = getpass('NASA Earthdata Login password: ')
49+
if prompt not in (True, False, 'password', 'token', None):
50+
raise ValueError(f'Unexpected value {prompt} for `prompt`')
5251

53-
self.session = hyp3_sdk.util.get_authenticated_session(username, password)
52+
if prompt is True:
53+
warnings.warn(
54+
'Passing `prompt=True` is deprecated. Please use either `prompt="password"` or `prompt="token"`',
55+
UserWarning,
56+
)
57+
prompt = 'password'
58+
59+
if prompt == 'password':
60+
if username is None:
61+
username = input('NASA Earthdata Login username: ')
62+
if password is None:
63+
password = getpass('NASA Earthdata Login password: ')
64+
65+
if prompt == 'token' and token is None:
66+
token = getpass('NASA Earthdata Login bearer token: ')
67+
68+
self.session = hyp3_sdk.util.get_authenticated_session(username, password, token)
5469
self.session.headers.update({'User-Agent': f'{hyp3_sdk.__name__}/{hyp3_sdk.__version__}'})
5570

5671
hostname = urlsplit(self.url).hostname

src/hyp3_sdk/util.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ def get_tqdm_progress_bar():
7171
return tqdm
7272

7373

74-
def get_authenticated_session(username: str | None, password: str | None) -> requests.Session:
74+
def get_authenticated_session(
75+
username: str | None = None, password: str | None = None, token: str | None = None
76+
) -> requests.Session:
7577
"""Log into HyP3 using credentials for `urs.earthdata.nasa.gov` from either the provided
7678
credentials or a `.netrc` file.
7779
@@ -80,10 +82,14 @@ def get_authenticated_session(username: str | None, password: str | None) -> req
8082
"""
8183
s = requests.Session()
8284

85+
if token is not None:
86+
s.headers.update({'Authorization': f'Bearer {token}'})
87+
return s
88+
8389
if username is not None and password is not None:
8490
response = s.get(AUTH_URL, auth=(username, password))
8591
auth_error_message = (
86-
'Was not able to authenticate with credentials provided\n'
92+
'Was not able to authenticate with username and password provided\n'
8793
'This could be due to invalid credentials or a connection error.'
8894
)
8995
else:

tests/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
@pytest.fixture(autouse=True)
1515
def get_mock_hyp3():
16-
def mock_get_authenticated_session(username, password):
16+
def mock_get_authenticated_session(username, password, token):
1717
session = requests.Session()
1818
session.cookies.set('asf-urs', 'test-cookie', domain='.asf.alaska.edu')
1919
return session

tests/test_hyp3.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import hyp3_sdk
1010
from hyp3_sdk import Batch, HyP3, Job
11-
from hyp3_sdk.exceptions import HyP3Error
11+
from hyp3_sdk.exceptions import AuthenticationError, HyP3Error
1212

1313

1414
@responses.activate
@@ -24,6 +24,25 @@ def test_session_headers(get_mock_hyp3):
2424
assert responses.calls[1].request.headers['User-Agent'] == f'hyp3_sdk/{hyp3_sdk.__version__}'
2525

2626

27+
def test_invalid_prompt():
28+
with pytest.raises(ValueError, match=r'^Unexpected value'):
29+
HyP3(prompt='prompt') # type: ignore[arg-type]
30+
31+
32+
@responses.activate
33+
def test_no_prompt():
34+
responses.add(responses.GET, hyp3_sdk.util.AUTH_URL, status=401)
35+
36+
with pytest.raises(AuthenticationError, match=r'^Was not able to authenticate with \.netrc file'):
37+
HyP3()
38+
39+
with pytest.raises(AuthenticationError, match=r'^Was not able to authenticate with \.netrc file'):
40+
HyP3(prompt=False)
41+
42+
with pytest.raises(AuthenticationError, match=r'^Was not able to authenticate with \.netrc file'):
43+
HyP3(prompt=None)
44+
45+
2746
@responses.activate
2847
def test_find_jobs(get_mock_hyp3, get_mock_job):
2948
api_response_mock = {

0 commit comments

Comments
 (0)