Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
26 changes: 19 additions & 7 deletions sigstore/_internal/oidc/oauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@
</div>
<div class="anchor">
<div class="links">
<a href="https://sigstore.dev/" class="link login"><span class="sigstore">sigstore</span> home <span class="arrow"></span></a>
<a href="https://docs.sigstore.dev/" class="link login"><span class="sigstore">sigstore</span> documentation <span class="arrow"></span></a>
<a href="https://blog.sigstore.dev/" class="link"><span class="sigstore">sigstore</span> blog <span class="arrow"></span></a>
<a href="https://sigstore.dev/" class="link login"><span class="sigstore">sigstore</span> home <span class="arrow">&rarr;</span></a>
<a href="https://docs.sigstore.dev/" class="link login"><span class="sigstore">sigstore</span> documentation <span class="arrow">&rarr;</span></a>
<a href="https://blog.sigstore.dev/" class="link"><span class="sigstore">sigstore</span> blog <span class="arrow">&rarr;</span></a>
</div>
</div>
</div>
Expand All @@ -102,12 +102,18 @@


class _OAuthFlow:
def __init__(self, client_id: str, client_secret: str, issuer: Issuer):
def __init__(
self,
client_id: str,
client_secret: str,
issuer: Issuer,
redirect_port: int = 0,
):
self._client_id = client_id
self._client_secret = client_secret
self._issuer = issuer
self._server = _OAuthRedirectServer(
self._client_id, self._client_secret, self._issuer
self._client_id, self._client_secret, self._issuer, port=redirect_port
)
self._server_thread = threading.Thread(
target=lambda server: server.serve_forever(),
Expand Down Expand Up @@ -223,8 +229,14 @@ def _auth_params(self, redirect_uri: str) -> dict[str, Any]:


class _OAuthRedirectServer(http.server.HTTPServer):
def __init__(self, client_id: str, client_secret: str, issuer: Issuer) -> None:
super().__init__(("localhost", 0), _OAuthRedirectHandler)
def __init__(
self,
client_id: str,
client_secret: str,
issuer: Issuer,
port: int = 0,
) -> None:
super().__init__(("localhost", port), _OAuthRedirectHandler)
self.oauth_session = _OAuthSession(client_id, client_secret, issuer)
self.auth_response: dict[str, list[str]] | None = None
self._is_out_of_band = False
Expand Down
10 changes: 9 additions & 1 deletion sigstore/oidc.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ def identity_token( # nosec: B107
client_id: str = _DEFAULT_CLIENT_ID,
client_secret: str = "",
force_oob: bool = False,
redirect_port: int = 0,
) -> IdentityToken:
"""
Retrieves and returns an `IdentityToken` from the current `Issuer`, via OAuth.
Expand All @@ -283,6 +284,11 @@ def identity_token( # nosec: B107
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.

The `redirect_port` parameter controls the port used for the local redirect server
during the OAuth flow. When `0` (the default), an ephemeral port is chosen by the OS.
Set this to a specific port number when your OIDC provider requires a pre-registered
redirect URI with a fixed port.
"""

# This function and the components that it relies on are based off of:
Expand All @@ -291,7 +297,9 @@ def identity_token( # nosec: B107
from sigstore._internal.oidc.oauth import _OAuthFlow

code: str
with _OAuthFlow(client_id, client_secret, self) as server:
with _OAuthFlow(
client_id, client_secret, self, redirect_port=redirect_port
) as server:
# Launch web browser
if not force_oob and webbrowser.open(server.base_uri):
print("Waiting for browser interaction...", file=sys.stderr)
Expand Down