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

add us-west-2 check to API and improve auth repr #424

Draft
wants to merge 17 commits into
base: main
Choose a base branch
from
Draft
1 change: 1 addition & 0 deletions binder/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: earthaccess
channels:
- conda-forge
dependencies:
- boto3
- python=3.9
- xarray>=0.19
- dask>=2022.1
Expand Down
12 changes: 9 additions & 3 deletions earthaccess/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
get_requests_https_session,
get_s3_credentials,
get_s3fs_session,
granule_query,
in_us_west_2,
login,
open,
search_data,
Expand All @@ -24,22 +24,28 @@
logger = logging.getLogger(__name__)

__all__ = [
# api.py
"login",
"search_datasets",
"search_data",
"get_requests_https_session",
"get_fsspec_https_session",
"get_s3fs_session",
"get_s3_credentials",
"granule_query",
"get_edl_token" "granule_query",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning: these strings will concatenate :)

"collection_query",
"open",
"download",
"auth_environ",
"in_us_west_2",
# search.py
"DataGranules",
"DataCollections",
# auth.py
"Auth",
# store.py
"Store",
"auth_environ",
# kerchunk
"consolidate_metadata",
]

Expand Down
16 changes: 16 additions & 0 deletions earthaccess/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,3 +353,19 @@ def auth_environ() -> Dict[str, str]:
"`auth_environ()` requires you to first authenticate with `earthaccess.login()`"
)
return {"EARTHDATA_USERNAME": auth.username, "EARTHDATA_PASSWORD": auth.password}


def in_us_west_2() -> str:
"""Returns a message indicating if the user is in AWS region us-west-2

Returns:
str: string indicating if the user is in AWS region us-west-2
"""
if earthaccess.__store__._running_in_us_west_2() is True:
return "You are running in AWS region 'us-west-2'"
else:
raise ValueError(
"Your instance is not running inside the"
" AWS us-west-2 region."
" You will not be able to directly access NASA Earthdata S3 buckets."
)
23 changes: 23 additions & 0 deletions earthaccess/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,28 @@ def __init__(self) -> None:
self.EDL_GENERATE_TOKENS_URL = "https://urs.earthdata.nasa.gov/api/users/token"
self.EDL_REVOKE_TOKEN = "https://urs.earthdata.nasa.gov/api/users/revoke_token"

def __repr__(self) -> str:
print_str = "Authentication Info\n" + "-------------------\n"
for k, v in self.auth_info.items():
print_str += str("{}: {}\n".format(k, v))

return print_str
Comment on lines +79 to +84
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I strongly discourage this implementation of __repr__ for at least 2 reasons:

  1. (minor) this is arguably an "abuse" of __repr__, which should generally be: "If at all possible, this should look like a valid Python expression that could be used to recreate an object with the same value (given an appropriate environment)." (see https://docs.python.org/3/reference/datamodel.html#object.__repr__)
  2. (very important) this can lead to inadvertent leaking of the user's token(s) during logging since auth_info includes those tokens


@property
def auth_info(self) -> Dict:
"""Get information about the authentication session

Returns:
Dict: information about the auth object
"""
summary_dict: Dict[str, Any]
summary_dict = {
"authenticated?": self.authenticated,
"tokens": self.tokens,
}

return summary_dict

def login(self, strategy: str = "netrc", persist: bool = False) -> Any:
"""Authenticate with Earthdata login.

Expand Down Expand Up @@ -168,6 +190,7 @@ def get_s3_credentials(
provider: A valid cloud provider. Each DAAC has a provider code for their cloud distributions.
endpoint: Getting the credentials directly from the S3Credentials URL.


Returns:
A Python dictionary with the temporary AWS S3 credentials.
"""
Expand Down
23 changes: 4 additions & 19 deletions earthaccess/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from typing import Any, Dict, List, Mapping, Optional, Tuple, Union
from uuid import uuid4

import botocore.session
import fsspec
import requests
import s3fs
Expand Down Expand Up @@ -137,26 +138,10 @@ def _own_s3_credentials(self, links: List[Dict[str, Any]]) -> Union[str, None]:
return None

def _running_in_us_west_2(self) -> bool:
session = self.auth.get_session()
try:
# https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html
token_ = session.put(
"http://169.254.169.254/latest/api/token",
headers={"X-aws-ec2-metadata-token-ttl-seconds": "21600"},
timeout=1,
)
resp = session.get(
"http://169.254.169.254/latest/meta-data/placement/region",
timeout=1,
headers={"X-aws-ec2-metadata-token": token_.text},
)
except Exception:
return False

if resp.status_code == 200 and b"us-west-2" == resp.content:
# On AWS, in region us-west-2
if botocore.session.get_session().get_config_variable("region") == "us-west-2":
return True
return False
else:
return False

def set_requests_session(
self, url: str, method: str = "get", bearer_token: bool = False
Expand Down
Loading