Skip to content

Commit 436b09d

Browse files
committed
feat:(oidc) derive audience claim from client_id in IdentityToken
Signed-off-by: SequeI <[email protected]>
1 parent 6ae464b commit 436b09d

File tree

5 files changed

+21
-14
lines changed

5 files changed

+21
-14
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ All versions prior to 0.9.0 are untracked.
1212

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

1619
### Fixed
1720

sigstore/_cli.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ def _add_shared_oidc_options(
208208
"--oidc-client-id",
209209
metavar="ID",
210210
type=str,
211-
default=os.getenv("SIGSTORE_OIDC_CLIENT_ID", "sigstore"),
211+
default=os.getenv("SIGSTORE_OIDC_CLIENT_ID"),
212212
help="The custom OpenID Connect client ID to use during OAuth2",
213213
)
214214
group.add_argument(
@@ -238,7 +238,6 @@ def _add_shared_oidc_options(
238238
help="Force an out-of-band OAuth flow and do not automatically start the default web browser",
239239
)
240240

241-
242241
def _parser() -> argparse.ArgumentParser:
243242
# Arguments in parent_parser can be used for both commands and subcommands
244243
parent_parser = argparse.ArgumentParser(add_help=False)

sigstore/oidc.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@
4141
"https://oauth2.sigstage.dev/auth": "email",
4242
"https://token.actions.githubusercontent.com": "sub",
4343
}
44-
_DEFAULT_AUDIENCE = "sigstore"
4544

45+
_DEFAULT_CLIENT_ID = "sigstore"
4646

4747
class _OpenIDConfiguration(BaseModel):
4848
"""
@@ -66,7 +66,7 @@ class IdentityToken:
6666
a sensible subject, issuer, and audience for Sigstore purposes.
6767
"""
6868

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

271271
def identity_token( # nosec: B107
272272
self,
273-
client_id: str = "sigstore",
273+
client_id: str = None,
274274
client_secret: str = "",
275275
force_oob: bool = False,
276276
) -> IdentityToken:
@@ -284,6 +284,8 @@ def identity_token( # nosec: B107
284284
an out-of-band flow. When `True`, the out-of-band flow is always used.
285285
"""
286286

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

@@ -350,7 +352,7 @@ def identity_token( # nosec: B107
350352
if token_error is not None:
351353
raise IdentityError(f"Error response from token endpoint: {token_error}")
352354

353-
return IdentityToken(token_json["access_token"])
355+
return IdentityToken(token_json["access_token"], client_id)
354356

355357

356358
class IdentityError(Error):
@@ -402,9 +404,13 @@ def diagnostics(self) -> str:
402404
"""
403405

404406

405-
def detect_credential() -> Optional[str]:
407+
def detect_credential(client_id: Optional[str] = None) -> Optional[str]:
406408
"""Calls `id.detect_credential`, but wraps exceptions with our own exception type."""
409+
410+
if client_id is None:
411+
client_id = _DEFAULT_CLIENT_ID
412+
407413
try:
408-
return cast(Optional[str], id.detect_credential(_DEFAULT_AUDIENCE))
414+
return cast(Optional[str], id.detect_credential(client_id))
409415
except id.IdentityError as exc:
410416
IdentityError.raise_from_id(exc)

test/conftest.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
detect_credential,
2323
)
2424

25-
from sigstore.oidc import _DEFAULT_AUDIENCE
2625

2726
_ASSETS = (Path(__file__).parent / "assets").resolve()
2827
assert _ASSETS.is_dir()
@@ -44,7 +43,7 @@ def _has_oidc_id():
4443
return True
4544

4645
try:
47-
token = detect_credential(_DEFAULT_AUDIENCE)
46+
token = detect_credential()
4847
if token is None:
4948
return False
5049
except GitHubOidcPermissionCredentialError:

test/unit/conftest.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
from sigstore._internal.rekor.client import RekorClient
4040
from sigstore._utils import sha256_digest
4141
from sigstore.models import Bundle
42-
from sigstore.oidc import _DEFAULT_AUDIENCE, IdentityToken
42+
from sigstore.oidc import IdentityToken
4343
from sigstore.sign import SigningContext
4444
from sigstore.verify.verifier import Verifier
4545

@@ -198,7 +198,7 @@ def sign_ctx_and_ident_for_env(
198198
token = os.getenv(f"SIGSTORE_IDENTITY_TOKEN_{env}")
199199
if not token:
200200
# If the variable is not defined, try getting an ambient token.
201-
token = detect_credential(_DEFAULT_AUDIENCE)
201+
token = detect_credential()
202202

203203
return ctx_cls, IdentityToken(token)
204204

@@ -212,7 +212,7 @@ def staging() -> tuple[type[SigningContext], type[Verifier], IdentityToken]:
212212
token = os.getenv("SIGSTORE_IDENTITY_TOKEN_staging")
213213
if not token:
214214
# If the variable is not defined, try getting an ambient token.
215-
token = detect_credential(_DEFAULT_AUDIENCE)
215+
token = detect_credential()
216216

217217
return signer, verifier, IdentityToken(token)
218218

0 commit comments

Comments
 (0)