Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ All versions prior to 0.9.0 are untracked.

* Added support for ed25519 keys.
[#1377](https://github.com/sigstore/sigstore-python/pull/1377)
* Added client_id as the audience (aud) claim when initializing IdentityToken
[#1402](https://github.com/sigstore/sigstore-python/pull/1402)


### Fixed

Expand Down
53 changes: 26 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,23 +69,22 @@ usage: sigstore [-h] [-v] [-V] [--staging | --trust-config FILE] COMMAND ...
a tool for signing and verifying Python package distributions

positional arguments:
COMMAND the operation to perform
attest sign one or more inputs using DSSE
sign sign one or more inputs
verify verify one or more inputs
get-identity-token
retrieve and return a Sigstore-compatible OpenID
Connect token
plumbing developer-only plumbing operations

optional arguments:
-h, --help show this help message and exit
-v, --verbose run with additional debug logging; supply multiple
times to increase verbosity (default: 0)
-V, --version show program's version number and exit
--staging Use sigstore's staging instances, instead of the
default production instances (default: False)
--trust-config FILE The client trust configuration to use (default: None)
COMMAND the operation to perform
attest sign one or more inputs using DSSE
sign sign one or more inputs
verify verify one or more inputs
get-identity-token retrieve and return a Sigstore-compatible OpenID
Connect token
plumbing developer-only plumbing operations

options:
-h, --help show this help message and exit
-v, --verbose run with additional debug logging; supply multiple
times to increase verbosity (default: 0)
-V, --version show program's version number and exit
--staging Use sigstore's staging instances, instead of the
default production instances (default: False)
--trust-config FILE The client trust configuration to use (default: None)
```
<!-- @end-sigstore-help@ -->

Expand All @@ -105,7 +104,7 @@ usage: sigstore sign [-h] [-v] [--identity-token TOKEN] [--oidc-client-id ID]
positional arguments:
FILE The file to sign

optional arguments:
options:
-h, --help show this help message and exit
-v, --verbose run with additional debug logging; supply multiple
times to increase verbosity (default: 0)
Expand All @@ -129,10 +128,10 @@ OpenID Connect options:
Output options:
--no-default-files Don't emit the default output files
({input}.sigstore.json) (default: False)
--signature FILE, --output-signature FILE
--signature, --output-signature FILE
Write a single signature to the given file; does not
work with multiple input files (default: None)
--certificate FILE, --output-certificate FILE
--certificate, --output-certificate FILE
Write a single certificate to the given file; does not
work with multiple input files (default: None)
--bundle FILE Write a single Sigstore bundle to the given file; does
Expand Down Expand Up @@ -161,7 +160,7 @@ usage: sigstore attest [-h] [-v] --predicate FILE --predicate-type TYPE
positional arguments:
FILE The file to sign

optional arguments:
options:
-h, --help show this help message and exit
-v, --verbose run with additional debug logging; supply multiple
times to increase verbosity (default: 0)
Expand Down Expand Up @@ -205,17 +204,17 @@ Output options:
```
usage: sigstore verify identity [-h] [-v] [--certificate FILE]
[--signature FILE] [--bundle FILE] [--offline]
--cert-identity IDENTITY --cert-oidc-issuer
URL
--cert-identity IDENTITY
--cert-oidc-issuer URL
FILE_OR_DIGEST [FILE_OR_DIGEST ...]

optional arguments:
options:
-h, --help show this help message and exit
-v, --verbose run with additional debug logging; supply multiple
times to increase verbosity (default: 0)

Verification inputs:
--certificate FILE, --cert FILE
--certificate, --cert FILE
The PEM-encoded certificate to verify against; not
used with multiple inputs (default: None)
--signature FILE The signature to verify against; not used with
Expand Down Expand Up @@ -248,13 +247,13 @@ usage: sigstore verify github [-h] [-v] [--certificate FILE]
[--ref REF]
FILE_OR_DIGEST [FILE_OR_DIGEST ...]

optional arguments:
options:
-h, --help show this help message and exit
-v, --verbose run with additional debug logging; supply multiple
times to increase verbosity (default: 0)

Verification inputs:
--certificate FILE, --cert FILE
--certificate, --cert FILE
The PEM-encoded certificate to verify against; not
used with multiple inputs (default: None)
--signature FILE The signature to verify against; not used with
Expand Down
2 changes: 1 addition & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,4 @@ extra:
- icon: fontawesome/brands/slack
link: https://sigstore.slack.com
- icon: fontawesome/brands/x-twitter
link: https://twitter.com/projectsigstore
link: https://twitter.com/projectsigstore
4 changes: 2 additions & 2 deletions sigstore/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ def _sign_common(
# 3) Interactive OAuth flow
identity: IdentityToken | None
if args.identity_token:
identity = IdentityToken(args.identity_token)
identity = IdentityToken(args.identity_token, args.client_id)
else:
identity = _get_identity(args, trust_config)

Expand Down Expand Up @@ -1185,7 +1185,7 @@ def _get_identity(

# Happy path: we've detected an ambient credential, so we can return early.
if token:
return IdentityToken(token)
return IdentityToken(token, args.client_id)

if args.oidc_issuer is not None:
issuer = Issuer(args.oidc_issuer)
Expand Down
21 changes: 14 additions & 7 deletions sigstore/oidc.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
"https://oauth2.sigstage.dev/auth": "email",
"https://token.actions.githubusercontent.com": "sub",
}
_DEFAULT_AUDIENCE = "sigstore"

_DEFAULT_CLIENT_ID = "sigstore"


class _OpenIDConfiguration(BaseModel):
Expand All @@ -66,7 +67,7 @@ class IdentityToken:
a sensible subject, issuer, and audience for Sigstore purposes.
"""

def __init__(self, raw_token: str) -> None:
def __init__(self, raw_token: str, client_id: Optional[str]) -> None:
"""
Create a new `IdentityToken` from the given OIDC token.
"""
Expand All @@ -90,7 +91,7 @@ def __init__(self, raw_token: str) -> None:
# See: https://openid.net/specs/openid-connect-basic-1_0.html#IDToken
"require": ["aud", "sub", "iat", "exp", "iss"],
},
audience=_DEFAULT_AUDIENCE,
audience=client_id,
# NOTE: This leeway shouldn't be strictly necessary, but is
# included to preempt any (small) skew between the host
# and the originating IdP.
Expand Down Expand Up @@ -270,7 +271,7 @@ def __init__(self, base_url: str) -> None:

def identity_token( # nosec: B107
self,
client_id: str = "sigstore",
client_id: Optional[str] = None,
client_secret: str = "",
force_oob: bool = False,
) -> IdentityToken:
Expand All @@ -284,6 +285,8 @@ def identity_token( # nosec: B107
an out-of-band flow. When `True`, the out-of-band flow is always used.
"""

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

Expand Down Expand Up @@ -350,7 +353,7 @@ def identity_token( # nosec: B107
if token_error is not None:
raise IdentityError(f"Error response from token endpoint: {token_error}")

return IdentityToken(token_json["access_token"])
return IdentityToken(token_json["access_token"], client_id)


class IdentityError(Error):
Expand Down Expand Up @@ -402,9 +405,13 @@ def diagnostics(self) -> str:
"""


def detect_credential() -> Optional[str]:
def detect_credential(client_id: Optional[str] = None) -> Optional[str]:
"""Calls `id.detect_credential`, but wraps exceptions with our own exception type."""

if client_id is None:
client_id = _DEFAULT_CLIENT_ID

try:
return cast(Optional[str], id.detect_credential(_DEFAULT_AUDIENCE))
return cast(Optional[str], id.detect_credential(client_id))
except id.IdentityError as exc:
IdentityError.raise_from_id(exc)
4 changes: 1 addition & 3 deletions test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
detect_credential,
)

from sigstore.oidc import _DEFAULT_AUDIENCE

_ASSETS = (Path(__file__).parent / "assets").resolve()
assert _ASSETS.is_dir()

Expand All @@ -44,7 +42,7 @@ def _has_oidc_id():
return True

try:
token = detect_credential(_DEFAULT_AUDIENCE)
token = detect_credential()
if token is None:
return False
except GitHubOidcPermissionCredentialError:
Expand Down
6 changes: 3 additions & 3 deletions test/unit/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
from sigstore._internal.trust import ClientTrustConfig
from sigstore._utils import sha256_digest
from sigstore.models import Bundle
from sigstore.oidc import _DEFAULT_AUDIENCE, IdentityToken
from sigstore.oidc import IdentityToken
from sigstore.sign import SigningContext
from sigstore.verify.verifier import Verifier

Expand Down Expand Up @@ -209,7 +209,7 @@ def ctx_cls():
token = os.getenv(f"SIGSTORE_IDENTITY_TOKEN_{env}")
if not token:
# If the variable is not defined, try getting an ambient token.
token = detect_credential(_DEFAULT_AUDIENCE)
token = detect_credential()

return ctx_cls, IdentityToken(token)

Expand All @@ -230,7 +230,7 @@ def signer():
token = os.getenv("SIGSTORE_IDENTITY_TOKEN_staging")
if not token:
# If the variable is not defined, try getting an ambient token.
token = detect_credential(_DEFAULT_AUDIENCE)
token = detect_credential()

return signer, verifier, IdentityToken(token)

Expand Down