diff --git a/src/planet_auth_utils/__init__.py b/src/planet_auth_utils/__init__.py index 002807b..8faa025 100644 --- a/src/planet_auth_utils/__init__.py +++ b/src/planet_auth_utils/__init__.py @@ -80,6 +80,8 @@ opt_extra, opt_human_readable, opt_issuer, + opt_key, + opt_key_file, opt_loglevel, opt_long, opt_open_browser, @@ -143,6 +145,8 @@ "opt_extra", "opt_human_readable", "opt_issuer", + "opt_key", + "opt_key_file", "opt_loglevel", "opt_long", "opt_open_browser", diff --git a/src/planet_auth_utils/commands/cli/jwt_cmd.py b/src/planet_auth_utils/commands/cli/jwt_cmd.py index 14bb9e3..8e41d61 100644 --- a/src/planet_auth_utils/commands/cli/jwt_cmd.py +++ b/src/planet_auth_utils/commands/cli/jwt_cmd.py @@ -14,6 +14,7 @@ import click import json +import jwt import pathlib import sys import textwrap @@ -30,6 +31,8 @@ from .options import ( opt_audience, opt_issuer, + opt_key, + opt_key_file, opt_token, opt_token_file, opt_human_readable, @@ -230,12 +233,45 @@ def cmd_jwt_validate_oauth(ctx, token, token_file, audience, issuer, human_reada @opt_human_readable() @opt_token() @opt_token_file() +@opt_key() +@opt_key_file() @recast_exceptions_to_click(AuthException, FileNotFoundError, NotImplementedError) -def cmd_jwt_validate_rs256(ctx, token, token_file, human_readable): +def cmd_jwt_validate_rs256(ctx, token, token_file, key, key_file, human_readable): """ Validate a JWT signed with a RS256 signature """ - # token_to_validate = _get_token_or_fail(token_opt=token, token_file_opt=token_file) + # The TokenValidator is geared for OAuth2 JWTs. + # This helper is lower level, and doesn't make the same assumptions. + # TODO: it might be nice to still have this more adjacent to the TokenValidator + # to keep practices aligned. + # validator = TokenValidator() + token_to_validate = _get_token_or_fail(token_opt=token, token_file_opt=token_file) + signing_key: jwt.PyJWK = None + # required_claims = [] + validated_complete = jwt.decode_complete( # Throws when invalid. + token_to_validate, + signing_key, + algorithms=["rs256", "RS256"], + # issuer=issuer, + # audience=audience, + options={ + # "require": required_claims, + # "verify_aud": True, + "verify_exp": True, + # "verify_iss": True, + "verify_signature": True, + }, + ) + # XXX check - validation throws on error + click.echo("TOKEN OK") + print_jwt_parts( + raw=token_to_validate, + header=validated_complete["header"], + body=validated_complete["payload"], + signature=validated_complete["signature"], + human_readable=human_readable, + ) + raise NotImplementedError("Command not implemented") diff --git a/src/planet_auth_utils/commands/cli/options.py b/src/planet_auth_utils/commands/cli/options.py index 9b15bb1..88ffa7c 100644 --- a/src/planet_auth_utils/commands/cli/options.py +++ b/src/planet_auth_utils/commands/cli/options.py @@ -193,6 +193,50 @@ def decorator(function) -> _click_option_decorator_type: return decorator +def opt_key( + default=None, hidden: bool = False, envvar: Optional[str] = EnvironmentVariables.AUTH_KEY +) -> _click_option_decorator_type: + """ + Click option for specifying a key literal. + """ + def decorator(function) -> _click_option_decorator_type: + function = click.option( + "--key", + help="Key string.", + type=str, + envvar=envvar, + default=default, + show_envvar=bool(envvar), + show_default=False, + hidden=hidden, + )(function) + return function + + return decorator + + +def opt_key_file( + default=None, hidden: bool = False, envvar: Optional[str] = EnvironmentVariables.AUTH_KEY_FILE +) -> _click_option_decorator_type: + """ + Click option for specifying a key file location for the + planet_auth package's click commands. + """ + def decorator(function) -> _click_option_decorator_type: + function = click.option( + "--key-file", + type=click.Path(exists=True, file_okay=True, readable=True, path_type=pathlib.Path), + envvar=envvar, + help="File containing a key.", + default=default, + show_envvar=bool(envvar), + show_default=True, + hidden=hidden, + )(function) + return function + + return decorator + def opt_loglevel( default="INFO", hidden: bool = False, envvar: Optional[str] = EnvironmentVariables.AUTH_LOGLEVEL ) -> _click_option_decorator_type: