Skip to content

Commit

Permalink
feat: Add --oauth-force-oob CLI option (#667)
Browse files Browse the repository at this point in the history
  • Loading branch information
laurentsimon authored Jun 9, 2023
1 parent d610255 commit 814af38
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 14 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ All versions prior to 0.9.0 are untracked.

## [Unreleased]

### Added

* CLI: `sigstore sign` and `sigstore get-identity-token` now support the
`--oauth-force-oob` option; which has the same behavior as the
preexisting `SIGSTORE_OAUTH_FORCE_OOB` environment variable
([#667](https://github.com/sigstore/sigstore-python/pull/667))

### Changed

* `sigstore verify` now performs additional verification of Rekor's inclusion
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ Sigstore instance options:
usage: sigstore sign [-h] [--identity-token TOKEN] [--oidc-client-id ID]
[--oidc-client-secret SECRET]
[--oidc-disable-ambient-providers] [--oidc-issuer URL]
[--no-default-files] [--signature FILE]
[--certificate FILE] [--bundle FILE]
[--oauth-force-oob] [--no-default-files]
[--signature FILE] [--certificate FILE] [--bundle FILE]
[--output-directory DIR] [--overwrite] [--staging]
[--rekor-url URL] [--rekor-root-pubkey FILE]
[--fulcio-url URL] [--ctfe FILE]
Expand All @@ -160,6 +160,9 @@ OpenID Connect options:
(e.g. on GitHub Actions) (default: False)
--oidc-issuer URL The OpenID Connect issuer to use (conflicts with
--staging) (default: https://oauth2.sigstore.dev/auth)
--oauth-force-oob Force an out-of-band OAuth flow and do not
automatically start the default web browser (default:
False)

Output options:
--no-default-files Don't emit the default output files ({input}.sigstore)
Expand Down
10 changes: 9 additions & 1 deletion sigstore/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,12 @@ def _add_shared_oidc_options(
default=os.getenv("SIGSTORE_OIDC_ISSUER", DEFAULT_OAUTH_ISSUER_URL),
help="The OpenID Connect issuer to use (conflicts with --staging)",
)
group.add_argument(
"--oauth-force-oob",
action="store_true",
default=_boolify_env("SIGSTORE_OAUTH_FORCE_OOB"),
help="Force an out-of-band OAuth flow and do not automatically start the default web browser",
)


def _parser() -> argparse.ArgumentParser:
Expand Down Expand Up @@ -977,7 +983,9 @@ def _get_identity(args: argparse.Namespace) -> Optional[IdentityToken]:
args.oidc_client_secret = "" # nosec: B105

token = issuer.identity_token(
client_id=args.oidc_client_id, client_secret=args.oidc_client_secret
client_id=args.oidc_client_id,
client_secret=args.oidc_client_secret,
force_oob=args.oauth_force_oob,
)

return token
19 changes: 12 additions & 7 deletions sigstore/oidc.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from __future__ import annotations

import logging
import os
import sys
import time
import urllib.parse
Expand Down Expand Up @@ -293,22 +292,26 @@ def staging(cls) -> Issuer:
return cls(STAGING_OAUTH_ISSUER_URL)

def identity_token( # nosec: B107
self, client_id: str = "sigstore", client_secret: str = ""
self,
client_id: str = "sigstore",
client_secret: str = "",
force_oob: bool = False,
) -> IdentityToken:
"""
Retrieves and returns an `IdentityToken` from the current `Issuer`, via OAuth.
This function blocks on user interaction, either via a web browser or an out-of-band
OAuth flow.
This function blocks on user interaction.
The `force_oob` flag controls the kind of flow performed. When `False` (the default),
this function attempts to open the user's web browser before falling back to
an out-of-band flow. When `True`, the out-of-band flow is always used.
"""

# This function and the components that it relies on are based off of:
# https://github.com/psteniusubi/python-sample

from sigstore._internal.oidc.oauth import _OAuthFlow

force_oob = os.getenv("SIGSTORE_OAUTH_FORCE_OOB") is not None

code: str
with _OAuthFlow(client_id, client_secret, self) as server:
# Launch web browser
Expand Down Expand Up @@ -361,7 +364,9 @@ def identity_token( # nosec: B107
try:
resp.raise_for_status()
except requests.HTTPError as http_error:
raise IdentityError from http_error
raise IdentityError(
f"Token request failed with {resp.status_code}"
) from http_error

token_json = resp.json()
token_error = token_json.get("error")
Expand Down
7 changes: 3 additions & 4 deletions test/unit/internal/oidc/test_issuer.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ def test_init_url():


@pytest.mark.online
def test_get_identity_token_identity_error(monkeypatch):
monkeypatch.setenv("SIGSTORE_OAUTH_FORCE_OOB", "")
def test_get_identity_token_bad_code(monkeypatch):
monkeypatch.setattr("builtins.input", lambda _: "hunter2")

with pytest.raises(IdentityError):
Issuer.staging().identity_token()
with pytest.raises(IdentityError, match=r"^Token request failed with .+$"):
Issuer.staging().identity_token(force_oob=True)

0 comments on commit 814af38

Please sign in to comment.