Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,43 @@ In this example, the user would be prompted to enter a value for "password" and,
"password": "my_password"
}
```
Additional `external_auth` settings for providers that require non standard communication pattern
|Key|Type|Description|Default|
|:--|:---|:----------|-------|
|`data_as_headers`|`boolean`|Send post_vars as request headers instead of body|`False`|
|`token_cookie_mappings`|`list` of `dict`|Map tokens in response body to session cookies|`[]`|
|`secret_prompt_mappings`|`dict`|Prompt for `secret_post_vars` with more descriptive names|`{}`|

Example:

```json

{
"name": "my_host",
"graphql_url": "https://hostname/v1/graphql",
"gateway_url": "https://hostname/gateway",
"username": "my_username",
"external_auth": {
"auth_url": "https://auth_service/route",
"data_as_headers": true,
"static_post_vars": {
"username": "my_username"
},
"secret_post_vars": [
"x-password"
],
"token_cookie_mappings": [
{
"key": "token_name_key",
"value": "token_value_key"
}
],
"secret_prompt_mappings": {
"x-password": "Password"
}
}
}
```

#### Using a Hasura Admin Secret

Expand Down
32 changes: 31 additions & 1 deletion src/aerie_cli/aerie_host.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,18 @@ def authenticate(self, username: str, password: str = None):
if not self.check_auth():
raise RuntimeError(f"Failed to open session")

def validateSSO(self):
resp = self.session.get(self.gateway_url + "/auth/validateSSO")

if not resp.ok:
raise RuntimeError(f"failed to validate external credential")
resp_json = resp.json()

self.aerie_jwt = AerieJWT(resp_json["token"])
self.active_role = self.aerie_jwt.default_role

if not self.check_auth():
raise RuntimeError(f"Failed to open session")

@define
class ExternalAuthConfiguration:
Expand All @@ -293,13 +305,28 @@ class ExternalAuthConfiguration:
auth_url: str
static_post_vars: dict
secret_post_vars: list
data_as_headers: bool
token_cookie_mappings: list
secret_prompt_mappings: dict

@classmethod
def from_dict(cls, config: Dict) -> "ExternalAuthConfiguration":
try:
auth_url = config["auth_url"]
static_post_vars = config["static_post_vars"]
secret_post_vars = config["secret_post_vars"]
try:
data_as_headers = config["data_as_headers"]
except KeyError:
data_as_headers = False
try:
token_cookie_mappings = config["token_cookie_mappings"]
except KeyError:
token_cookie_mappings = []
try:
secret_prompt_mappings = config["secret_prompt_mappings"]
except KeyError:
secret_prompt_mappings = {}

except KeyError as e:
raise ValueError(
Expand All @@ -316,13 +343,16 @@ def from_dict(cls, config: Dict) -> "ExternalAuthConfiguration":
"Invalid value for 'secret_post_vars' in external auth configuration"
)

return cls(auth_url, static_post_vars, secret_post_vars)
return cls(auth_url, static_post_vars, secret_post_vars, data_as_headers, token_cookie_mappings, secret_prompt_mappings)

def to_dict(self) -> Dict:
return {
"auth_url": self.auth_url,
"static_post_vars": self.static_post_vars,
"secret_post_vars": self.secret_post_vars,
"data_as_headers": self.data_as_headers,
"token_cookie_mappings": self.token_cookie_mappings,
"secret_prompt_mappings": self.secret_prompt_mappings
}


Expand Down
37 changes: 26 additions & 11 deletions src/aerie_cli/utils/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,20 +99,32 @@ def authenticate_with_external(
secret_post_vars = {}

for secret_var_name in configuration.secret_post_vars:
try:
secret_prompt = configuration.secret_prompt_mappings[secret_var_name]
except KeyError:
secret_prompt = secret_var_name

if secret_var_name in secret_post_vars.keys():
post_vars[secret_var_name] = secret_post_vars[secret_var_name]
else:
post_vars[secret_var_name] = typer.prompt(f"External authentication - {secret_var_name}", hide_input=True)
post_vars[secret_var_name] = typer.prompt(f"External authentication - {secret_prompt}", hide_input=True)

resp = session.post(configuration.auth_url, json=post_vars)
if configuration.data_as_headers:
session.headers = post_vars
resp = session.post(configuration.auth_url)
else:
resp = session.post(configuration.auth_url, json=post_vars)

if not resp.ok:
raise RuntimeError(
f"Failed to authenticate with proxy: {configuration.auth_url}"
)

return session
resp_json = resp.json()
for token in configuration.token_cookie_mappings:
session.cookies.set(resp_json[token['key']], resp_json[token['value']])

return session

def start_session_from_configuration(
configuration: AerieHostConfiguration,
Expand Down Expand Up @@ -153,15 +165,18 @@ def start_session_from_configuration(
configuration.name,
)

if username is None:
if configuration.username is None:
username = typer.prompt("Aerie Username")
else:
username = configuration.username
if configuration.external_auth is None:
if username is None:
if configuration.username is None:
username = typer.prompt("Aerie Username")
else:
username = configuration.username

if password is None and hs.is_auth_enabled():
password = typer.prompt("Aerie Password", hide_input=True)
if password is None and hs.is_auth_enabled():
password = typer.prompt("Aerie Password", hide_input=True)

hs.authenticate(username, password)
hs.authenticate(username, password)
else:
hs.validateSSO()

return hs