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

Various and sundry #332

Merged
merged 8 commits into from
Jan 11, 2024
Merged

Various and sundry #332

merged 8 commits into from
Jan 11, 2024

Conversation

tsibley
Copy link
Member

@tsibley tsibley commented Nov 21, 2023

See commit messages. Done during work on the path towards OIDC/OAuth2-based login, but suitable for separate review and independent merge.

Checklist

  • Checks pass

@tsibley tsibley requested a review from a team November 21, 2023 18:59
@tsibley
Copy link
Member Author

tsibley commented Nov 21, 2023

I was going to write up change log entries, but all of these seem like internal improvements to me and not user-facing. The one or two that might be user-facing are only so when things are used in development contexts (e.g. with NEXTSTRAIN_DOT_ORG set).

…able

Reading the OAuth 2.0 spec again¹, I noted that:

    The authorization server MAY issue a new refresh token, in which
    case the client MUST discard the old refresh token and replace it
    with the new refresh token. The authorization server MAY revoke the
    old refresh token after issuing a new refresh token to the client.

I had assumed the refresh token itself was never renewed as I never
observed AWS Cognito doing so in practice.  I addressed this assumption
for nextstrain.org², which is using OAuth 2.0, but it also got me
thinking about Nextstrain CLI here, which isn't using OAuth 2.0 per se
but is using a Cognito API that's very similar.

Like the OAuth 2.0 spec, the documented Cognito response type
definitions include the possibility of an updated refresh token.³
Perhaps Cognito even does renew them, but only as necessary and we've
never happened to notice this issue!

Regardless, we're planning to move to generic OAuth 2.0 authentication
instead of using Cognito's API, or at least support the former in
addition to the latter.  This change of logic will help smooth that
switch.

¹ <https://datatracker.ietf.org/doc/html/rfc6749#section-6>
² <nextstrain/nextstrain.org#736>
³ <https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AuthenticationResultType.html>
…esources…

…like the other remote actions/commands do.  Being precise about what's
being acted upon is important and useful.

Note that at the moment this is only not identical to the previous
output when NEXTSTRAIN_DOT_ORG is set to something other than
<https://nextstrain.org>.
…dling

There was a narrow space for bugs here since it was reconstructing what
the user associated with the request was *expected* to be, but not what
it necessarily *actually* was, e.g. what was used to send the actual

    Authorization: Bearer …

header in the request.

From a given requests.Response object we can't access the auth provider
directly (by design), so we have to arrange a backchannel to pass along
to the error handler the actual user authn information used in the
request.  A simple custom attribute on the request object does the job
nicely.

One alternative would be a custom request header, e.g.

    Nextstrain-Username: trs

or some such, but I like the attribute because it's more targeted in
scope and doesn't send unnecessary information.  Another alternative
would be for the error handler to parse the token in the Authorization
header—it doesn't really even need to verify the JWT, just parse it—and
extract the username that way.  But that's a bit more involved and the
simplicity of a custom attribute is more compelling.
This avoids issues where nextstrain.cli.command.remote masks the
nextstrain.cli.remote module when attempting to use the former, e.g.

    import nextstrain.cli.remote

will get you nextstrain.cli.command.remote because it was imported as
"remote" into nextstrain.cli.

I thought maybe you could work around this, e.g. with

    import nextstrain.cli.remote as remote

but no dice.

This happens because importing x.y.z first imports x, then imports x.y,
and finally x.y.z and during this each nested module is made available
in its parent by design.

In any case, switching to nextstrain.cli.command.all_commands nicely
parallels the existing nextstrain.cli.runner.all_runners variable.
These are used in `nextstrain view --help` output, and setting them
during development (e.g. for `make -C doc livehtml`) would otherwise
influence the generated doc.
@tsibley tsibley force-pushed the trs/various-and-sundry branch from ac2feff to 1c6a658 Compare November 21, 2023 19:09
Based on `nextstrain view`'s interaction with the standard library's
webbrowser module.  Arranges to launch the browser in a separate thread,
as this will be good enough for many contexts.  `nextstrain view` itself
still arranges to launch the browser in a separate _process_, since
view's main thread/process exec's into a new program shortly after
launching the browser.
Copy link
Member

@victorlin victorlin left a comment

Choose a reason for hiding this comment

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

Local testing:

  • nextstrain view works with 3261aac
  • NOBROWSER=1 nextstrain view works with 32f06fe

Copy link
Contributor

@joverlee521 joverlee521 left a comment

Choose a reason for hiding this comment

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

I'm probably missing context from the ongoing CDC work, but changes LGTM from inspection.

I'm curious what prompted the NOBROWSER variable?

@tsibley
Copy link
Member Author

tsibley commented Jan 11, 2024

I'm curious what prompted the NOBROWSER variable?

When doing browser work for #333 and nextstrain login, I noticed that setting BROWSER= didn't work as I expected it to. It doesn't result in finding no browser and thus not automatically opening one, instead it's just an empty list of preferred browsers and so still falls back to the built-in defaults.

Since BROWSER is handled by the webbrowser module in the stdlib, I added NOBROWSER. This is an env var that's somewhat of a convention, akin to NO_COLOR (though not as widely supported).

@tsibley tsibley merged commit a2a88d4 into master Jan 11, 2024
@tsibley tsibley deleted the trs/various-and-sundry branch January 11, 2024 20:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants