Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support automatic authentication #300

Merged
merged 7 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions earthaccess/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import threading
from importlib.metadata import version
from typing import Any

Expand Down Expand Up @@ -36,7 +37,30 @@
"Store",
]

__auth__ = Auth()
__store__: Any = None

__version__ = version("earthaccess")

_auth = Auth()
_store = None
_lock = threading.Lock()


def __getattr__(name): # type: ignore
MattF-NSIDC marked this conversation as resolved.
Show resolved Hide resolved
global _auth, _store

if name == "__auth__" or name == "__store__":
with _lock:
if not _auth.authenticated:
for strategy in ["environment", "netrc"]:
try:
_auth.login(strategy=strategy)
except Exception:
continue
else:
if not _auth.authenticated:
continue
MattF-NSIDC marked this conversation as resolved.
Show resolved Hide resolved
else:
_store = Store(_auth)
break
return _auth if name == "__auth__" else _store
else:
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
3 changes: 1 addition & 2 deletions earthaccess/api.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from typing import Any, Dict, List, Optional, Type, Union

import earthaccess
import requests
import s3fs
from fsspec import AbstractFileSystem

import earthaccess

from .auth import Auth
from .search import CollectionQuery, DataCollections, DataGranules, GranuleQuery
from .store import Store
Expand Down
33 changes: 18 additions & 15 deletions earthaccess/auth.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import getpass
import logging
import os
from netrc import NetrcParseError
from pathlib import Path
Expand All @@ -10,6 +11,8 @@

from .daac import DAACS

logger = logging.getLogger(__name__)


class SessionWithHeaderRedirection(requests.Session):
"""
Expand Down Expand Up @@ -76,7 +79,7 @@ def login(self, strategy: str = "netrc", persist: bool = False) -> Any:
an instance of Auth.
"""
if self.authenticated:
print("We are already authenticated with NASA EDL")
logger.debug("We are already authenticated with NASA EDL")
return self
if strategy == "interactive":
self._interactive(persist)
Expand All @@ -98,7 +101,7 @@ def refresh_tokens(self) -> bool:
if resp_tokens.ok:
self.token = resp_tokens.json()
self.tokens = [self.token]
print(
logger.debug(
f"earthaccess generated a token for CMR with expiration on: {self.token['expiration_date']}"
)
return True
Expand All @@ -111,7 +114,7 @@ def refresh_tokens(self) -> bool:
if resp_tokens.ok:
self.token = resp_tokens.json()
self.tokens.extend(self.token)
print(
logger.debug(
f"earthaccess generated a token for CMR with expiration on: {self.token['expiration_date']}"
)
return True
Expand All @@ -127,7 +130,7 @@ def refresh_tokens(self) -> bool:
if resp_tokens.ok:
self.token = resp_tokens.json()
self.tokens[0] = self.token
print(
logger.debug(
f"earthaccess generated a token for CMR with expiration on: {self.token['expiration_date']}"
)
return True
Expand Down Expand Up @@ -221,7 +224,7 @@ def _interactive(self, presist_credentials: bool = False) -> bool:
password = getpass.getpass(prompt="Enter your Earthdata password: ")
authenticated = self._get_credentials(username, password)
if authenticated:
print("Using user provided credentials for EDL")
logger.debug("Using user provided credentials for EDL")
if presist_credentials:
print("Persisting credentials to .netrc")
self._persist_user_credentials(username, password)
Expand All @@ -231,29 +234,29 @@ def _netrc(self) -> bool:
try:
my_netrc = Netrc()
except FileNotFoundError as err:
print(f"No .netrc found in {os.path.expanduser('~')}")
raise err
raise FileNotFoundError(
f"No .netrc found in {os.path.expanduser('~')}"
) from err
except NetrcParseError as err:
print("Unable to parse .netrc")
raise err
raise NetrcParseError("Unable to parse .netrc") from err
MattF-NSIDC marked this conversation as resolved.
Show resolved Hide resolved
if my_netrc["urs.earthdata.nasa.gov"] is not None:
username = my_netrc["urs.earthdata.nasa.gov"]["login"]
password = my_netrc["urs.earthdata.nasa.gov"]["password"]
else:
return False
authenticated = self._get_credentials(username, password)
if authenticated:
print("Using .netrc file for EDL")
logger.debug("Using .netrc file for EDL")
return authenticated

def _environment(self) -> bool:
username = os.getenv("EARTHDATA_USERNAME")
password = os.getenv("EARTHDATA_PASSWORD")
authenticated = self._get_credentials(username, password)
if authenticated:
print("Using environment variables for EDL")
logger.debug("Using environment variables for EDL")
else:
print(
logger.debug(
"EARTHDATA_USERNAME and EARTHDATA_PASSWORD are not set in the current environment, try "
"setting them or use a different strategy (netrc, interactive)"
)
Expand All @@ -270,7 +273,7 @@ def _get_credentials(
f"Authentication with Earthdata Login failed with:\n{token_resp.text}"
)
return False
print("You're now authenticated with NASA Earthdata Login")
logger.debug("You're now authenticated with NASA Earthdata Login")
self.username = username
self.password = password

Expand All @@ -279,13 +282,13 @@ def _get_credentials(

if len(self.tokens) == 0:
self.refresh_tokens()
print(
logger.debug(
f"earthaccess generated a token for CMR with expiration on: {self.token['expiration_date']}"
)
self.token = self.tokens[0]
elif len(self.tokens) > 0:
self.token = self.tokens[0]
print(
logger.debug(
f"Using token with expiration date: {self.token['expiration_date']}"
)
profile = self.get_user_profile()
Expand Down
7 changes: 3 additions & 4 deletions earthaccess/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,20 @@
from functools import lru_cache
from itertools import chain
from pathlib import Path
from typing import Any, Callable, Dict, List, Optional, Union
from typing import Any, Dict, List, Optional, Union
from uuid import uuid4

import earthaccess
import fsspec
import requests
import s3fs
from multimethod import multimethod as singledispatchmethod
from pqdm.threads import pqdm

import earthaccess

from .auth import Auth
from .daac import DAAC_TEST_URLS, find_provider
from .results import DataGranule
from .search import DataCollections
from .auth import Auth


class EarthAccessFile(fsspec.spec.AbstractBufferedFile):
Expand Down
Loading