sigstore._internal.oidc.oauth
OAuth2 flow functionality for sigstore-python
.
1# Copyright 2022 The Sigstore Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15""" 16OAuth2 flow functionality for `sigstore-python`. 17""" 18 19from __future__ import annotations 20 21import base64 22import hashlib 23import http.server 24import logging 25import os 26import threading 27import urllib.parse 28import uuid 29from typing import Any, Dict, List, Optional, cast 30 31from id import IdentityError 32 33from sigstore._utils import B64Str 34from sigstore.oidc import Issuer 35 36_logger = logging.getLogger(__name__) 37 38 39# This HTML is copied from the Go Sigstore library and was originally authored by Julien Vermette: 40# https://github.com/sigstore/sigstore/blob/main/pkg/oauth/interactive.go 41AUTH_SUCCESS_HTML = """ 42<html> 43 <head> 44 <title>Sigstore Authentication</title> 45 <link id="favicon" rel="icon" type="image/svg"/> 46 <style> 47 :root { font-family: "Trebuchet MS", sans-serif; height: 100%; color: #444444; overflow: hidden; } 48 body { display: flex; justify-content: center; height: 100%; margin: 0 10%; background: #FFEAD7; } 49 .container { display: flex; flex-direction: column; justify-content: space-between; } 50 .sigstore { color: #2F2E71; font-weight: bold; } 51 .header { position: absolute; top: 30px; left: 22px; } 52 .title { font-size: 3.5em; margin-bottom: 30px; animation: 750ms ease-in-out 0s 1 show; } 53 .content { font-size: 1.5em; animation: 250ms hide, 750ms ease-in-out 250ms 1 show; } 54 .anchor { position: relative; } 55 .links { display: flex; justify-content: space-between; font-size: 1.2em; padding: 60px 0; position: absolute; bottom: 0; left: 0; right: 0; animation: 500ms hide, 750ms ease-in-out 500ms 1 show; } 56 .link { color: #444444; text-decoration: none; user-select: none; } 57 .link:hover { color: #6349FF; } 58 .link:hover>.arrow { transform: scaleX(1.5) translateX(3px); } 59 .link:hover>.sigstore { color: inherit; } 60 .link, .arrow { transition: 200ms; } 61 .arrow { display: inline-block; margin-left: 6px; transform: scaleX(1.5); } 62 @keyframes hide { 0%, 100% { opacity: 0; } } 63 @keyframes show { 0% { opacity: 0; transform: translateY(40px); } 100% { opacity: 1; } } 64 </style> 65 </head> 66 <body> 67 <div class="container"> 68 <div> 69 <a class="header" href="https://sigstore.dev"> 70 <svg id="logo" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="28.14" height="30.3"> 71 <circle r="7" cx="14" cy="15" fill="#FFEAD7"></circle> 72 <path fill="#2F2E71" d="M27.8 10.9c-.3-1.2-.9-2.2-1.7-3.1-.6-.7-1.3-1.3-2-2-.7-.6-1.2-1.3-1.5-2.1-.2-.4-.4-.8-.7-1.2-.5-.7-1.3-1.2-2.1-1.6-1.3-.7-2.7-.9-4.2-.9-.8 0-1.6.1-2.4.3-1.2.2-2.3.7-3.4 1.3-.7.4-1.3.9-1.9 1.4-1 .8-2 1.6-2.8 2.6-.6.8-1.4 1.3-2.2 1.8-.8.4-1.4 1-2 1.6-.6.6-.9 1.3-.9 2.1 0 .6.1 1.2.2 1.7.2.9.6 1.7.9 2.6.2.5.3 1 .3 1.5s0 1-.1 1.5c-.1 1.1 0 2.3.2 3.4.2 1 .8 1.8 1.8 2.2.1.1.3.1.4.1.2.1.2.2.1.3l-.1.1c-.4.5-.7 1.1-.6 1.8.1 1.1 1.3 1.8 2.3 1.3.6-.2 1.2 0 1.4.4.1.1.1.2.2.3.2.5.4.9.7 1.3.4.5.9.7 1.6.6.4-.1.8-.2 1.2-.4.7-.4 1.3-.9 2-1.5.2-.2.4-.2.7-.2.4 0 .8.2 1.2.5.6.4 1.2.7 1.9.9 1.3.4 2.5.5 3.8.2 1.3-.3 2.4-.9 3.4-1.6.7-.5 1.2-1 1.6-1.7.4-.7.6-1.4.8-2.2.3-1.1.4-2.2.4-3.4.1-1 .2-1.9.5-2.8.2-.7.5-1.4.8-2.1.2-.6.4-1.2.5-1.9.1-1.1 0-2.1-.3-3.1zM14.9.8c.3-.1.7-.1 1-.1h.3c1.1 0 2.1.2 3.1.5.6.2 1.2.6 1.7 1s.7.9.9 1.4v.1c0 .1 0 .2-.1.2s-.1 0-.2-.1c-.4-.4-.7-.8-1.1-1.1-.6-.5-1.2-.9-2-1.1-1.1-.3-2.1-.5-3.2-.7h-.6c.1 0 .1 0 .2-.1-.1 0 0 0 0 0zm-4.5 12.4c.6 0 1.1.5 1.2 1.2 0 .6-.5 1.2-1.2 1.2-.6 0-1.2-.5-1.1-1.2 0-.7.5-1.2 1.1-1.2zm3.8 1.3v-3.4c0-2.3 2-3.1 3.6-2.5.3.1.6.3.9.5.2.2.2.5.1.8-.2.2-.4.3-.7.1-.2-.1-.5-.2-.7-.3-.6-.2-1.3 0-1.6.4-.1.2-.2.4-.2.7-.1.5 0 .9 0 1.4v5.9c0 1.2-.6 2.1-1.8 2.4-1 .3-1.9.2-2.7-.6-.2-.2-.3-.5-.1-.7.1-.2.4-.3.7-.2.3.1.6.3.9.4 1 .1 1.7-.3 1.7-1.4-.1-1.2-.1-2.3-.1-3.5zm-8.8 7.6h-.1c-.1-.1-.2-.1-.3-.2-.2-.2-.4-.3-.6-.5-.3-.3-.5-.6-.7-1-.4-.8-.8-1.7-1-2.7-.1-.5-.2-1-.2-1.5s-.1-1-.2-1.4c-.1-.7-.2-1.5-.2-2.2 0-.9.1-1.7.4-2.5.3-.9.7-1.7 1.4-2.4.6-.6 1.1-1.2 1.7-1.8.1-.1.3-.2.4-.2 0 .1-.1.3-.2.4-.3.4-.6.7-.9 1.1-.5.6-.9 1.2-1.2 1.8-.4.7-.7 1.4-.9 2.2-.1.4-.2.8-.2 1.2 0 .4-.1.8 0 1.3 0 .6.1 1.1.2 1.6.1.6.2 1.1.2 1.7 0 .7.2 1.4.4 2.1 0 .2.2.3.2.5.3.6.6 1.1 1.1 1.5.2.2.4.5.6.7 0 0 0 .1.1.1v.2zM8 24.6c-.4 0-.7.1-1.1.2-.4.1-.6-.1-.7-.5 0-.1-.1-.3 0-.4.1-.3.3-.3.5-.1.2.2.5.4.7.5.1.1.2.1.4.1.1 0 .2.1.4.2H8zm7.6 2.1c-.3.2-.7.3-1.1.3-.3 0-.6-.1-.9-.1h-.2c-.4.1-.7.1-1.1.2-.1 0-.3 0-.4.1H11c-.4 0-.7-.2-1-.5-.1-.1-.2-.3-.3-.5-.1-.1-.1-.2-.1-.4 0-.1.1-.1.2-.1h.1c.5.3 1.1.4 1.6.5.7.1 1.4.2 2.1.2.4 0 .7.1 1.1.1h.8c.2.1.1.1.1.2zm3.7-2.5c-.7.4-1.5.7-2.3.9-.2 0-.5.1-.7.1-.2 0-.5 0-.7.1-.4.1-.8 0-1.2 0-.3 0-.6-.1-.9 0h-.2c-.4-.1-.9-.2-1.3-.3-.5-.1-1-.3-1.4-.5-.4-.1-.8-.3-1.1-.5-.2-.1-.4-.3-.6-.4-.6-.6-1.2-1.1-1.7-1.6-.4-.5-.8-.9-1.2-1.4-.4-.6-.7-1.2-1-1.9l-.3-.9c-.1-.3-.2-.5-.2-.8v-.8c.3.8.5 1.7.9 2.5.7 1.6 1.7 3 3 4.1 1.4 1.1 2.9 1.8 4.6 2.1.9.2 1.8.2 2.7.2 1.1-.1 2.2-.3 3.2-.8.2-.1.3-.2.5-.2 0 .1 0 .1-.1.1zm.1-8.7c-.6 0-1.1-.5-1.1-1.2 0-.6.5-1.2 1.2-1.2.6 0 1.1.5 1.1 1.2s-.5 1.3-1.2 1.2zm6.2 5.7c0 .4-.1.8-.2 1.2-.1.4-.1.9-.3 1.3-.1.4-.2.7-.4 1.1-.1.3-.3.6-.6.8-.3.2-.5.4-.9.5-.4.2-.7.3-1.2.3h-.9c-.2-.1-.2-.1-.1-.3.1-.2.3-.3.5-.4.3-.2.6-.5.8-.7.7-.7 1.3-1.6 1.9-2.4.4-.4.6-1 .9-1.5.1-.1.1-.2.2-.3.3.2.3.3.3.4zm-15-16.8c1.7-.8 3.5-1.1 5.3-.9.4 0 .8.1 1.1.3l1.8.6c.6.2 1.2.5 1.7.8.7.4 1.3.9 1.9 1.5.8.8 1.5 1.6 2 2.6.3.6.5 1.2.7 1.8.2.7.4 1.5.4 2.2v.9c0 .4-.1.8-.1 1.2v-1c0-1.2-.3-2.3-.6-3.4l-.6-1.5c-.2-.6-.5-1.1-.9-1.6-.1-.1-.3-.1-.4-.2-.1 0-.1 0-.2-.1-.5-.5-1.1-1-1.7-1.5-.8-.6-1.7-1.1-2.6-1.4-.4-.2-.8-.3-1.2-.4-.9-.2-1.8-.4-2.7-.3h-.9c-.3 0-.6.1-1 .2-.6.1-1.2.3-1.7.5h-.1s-.1 0 0-.1c0 0 0-.1-.1-.2m16.2 11.1c-.1-.8 0-1.7 0-2.5-.1-.8-.2-1.6-.4-2.4.5.7.6 1.6.7 2.4 0 .8 0 1.7-.3 2.5zm.6.5c0-.3.1-.7.2-1.1.1-.4.1-.9.1-1.3v-.4c0-.8-.2-1.6-.4-2.4-.4-.9-.8-1.6-1.4-2.4-.5-.6-.9-1.2-1.4-1.8l-.2-.2c.1 0 .1 0 .1.1 1 .8 1.8 1.6 2.4 2.7.5 1 .9 2 1 3.1.3 1.3.1 2.5-.4 3.7z"/> 73 </svg><svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="120" height="30.3" viewBox="28.14 0 120 30.3"> 74 <path fill="#2F2E71" d="M57.7 18c.9 0 1.9-.1 2.9.3.9.3 1.5.9 1.7 2 .1 1-.2 1.9-1.1 2.5-1.1.8-2.3.9-3.6 1-1.4 0-2.9 0-4.3-.6-1.6-.7-1.8-2.6-.4-3.6.3-.2.2-.3.1-.5-.7-.8-.7-2.2.3-2.8.3-.2.2-.3 0-.6-1.4-1.6-.7-4.1 1.3-4.8 1.6-.6 3.2-.6 4.8-.1.2.1.3.1.5-.1.3-.3.6-.5.9-.7.5-.3 1.1-.3 1.4 0 .3.4.3.9-.2 1.3-.7.5-.8 1-.6 1.9.4 1.5-.6 2.9-2.1 3.4-1.3.5-2.7.5-4 .2-.3-.1-.5-.1-.6.2-.1.3-.1.6.2.8.2.1.5.2.8.2h2zm-.6-2.7c.3 0 .5 0 .7-.1.8-.2 1.3-.7 1.4-1.4.1-.7-.3-1.3-.9-1.6-.8-.3-1.6-.3-2.4 0-1 .4-1.2 1.7-.6 2.4.5.6 1.2.7 1.8.7zm-.2 4.6h-1.8c-.4 0-.6.2-.7.5-.3.7.1 1.2.9 1.4 1.2.2 2.5.2 3.7-.1l.6-.3c.5-.3.4-1.1-.1-1.3-.2-.1-.5-.2-.7-.2h-1.9zm58.6-3.3h-3.2c-.3 0-.3.1-.3.4.2 1.2 1.3 2.1 2.8 2.3 1.1.1 2.1-.1 2.9-.9.2-.2.4-.3.6-.4.4-.2.8-.2 1.1.1.4.3.4.7.3 1.1-.3.9-.9 1.4-1.7 1.8-2.3 1-4.5.9-6.5-.6-1-.7-1.5-1.8-1.7-3-.3-1.7-.2-3.3.8-4.7 1.3-1.8 3.1-2.4 5.2-2.1 2 .3 3.4 1.3 4 3.2.2.6.3 1.2.2 1.8-.1.8-.4 1.1-1.2 1.1-1.1-.1-2.2-.1-3.3-.1zm-.7-1.9h2.4c.4 0 .4-.1.4-.5-.3-1.1-1.2-1.9-2.5-2-1.5-.1-2.6.6-3.1 1.9-.2.5-.1.6.4.6h2.4zm-23 6.7c-3.3 0-5.5-2.2-5.6-5.5 0-3.2 2.2-5.6 5.4-5.6 3.4 0 5.7 2.2 5.8 5.5 0 3.4-2.2 5.6-5.6 5.6zm0-2.1c1.9 0 3.2-1.3 3.3-3.3.1-2-1.3-3.4-3.2-3.4-1.8 0-3.2 1.4-3.2 3.3-.1 1.9 1.2 3.4 3.1 3.4zm-22.6 2.1c-1.1 0-2.4-.3-3.5-1.4-.3-.4-.6-.8-.7-1.3 0-.4.1-.7.4-.9.3-.2.7-.2 1 0 .3.2.6.4.8.6.9.9 2 1.1 3.2.9.6-.1 1-.5 1-1 .1-.5-.2-1-.8-1.2-.7-.3-1.4-.3-2.1-.5-.8-.2-1.6-.4-2.2-.9-1.5-1.2-1.4-3.5.2-4.6 1.2-.8 2.6-.9 4-.7 1 .1 1.9.5 2.6 1.2.3.3.4.6.5.9.1.4 0 .7-.3 1-.3.3-.7.3-1 .1-.4-.2-.7-.5-1.1-.8-.8-.6-1.7-.8-2.7-.5-.6.1-.9.5-.9 1s.3.9.8 1.1c.9.3 1.9.4 2.9.7.6.2 1.1.4 1.5.8 1.5 1.4 1.1 4.1-.9 5.1-.7.3-1.5.4-2.7.4zm-30.3 0c-1.5 0-3-.3-4.1-1.5-.3-.3-.4-.6-.5-1-.1-.4-.1-.8.3-1.1.4-.2.9-.2 1.3.1.3.2.6.5.8.7.9.8 1.9.9 3 .7.6-.1.9-.5.9-1.1 0-.5-.3-1-.8-1.2l-2.7-.6c-1.1-.3-2-.8-2.4-2-.6-1.7.4-3.4 2.2-3.9 1.7-.5 3.3-.3 4.8.5.6.3 1 .8 1.2 1.4.1.4.1.9-.3 1.1-.4.3-.8.2-1.2-.1-.4-.3-.7-.7-1.2-.9-.8-.4-1.5-.5-2.4-.3-.5.1-.8.4-.8.9s.2.8.7 1c.7.3 1.4.3 2.1.5.8.2 1.5.3 2.2.8 1.2.8 1.5 2.5.9 3.8-.7 1.4-1.9 1.8-3.3 2-.3.2-.5.2-.7.2zM78 15.8v-2.6c0-.3-.1-.4-.4-.4h-1.3c-.6-.1-.9-.5-.9-1s.4-1 .9-1h1.3c.3 0 .4-.1.4-.4V8.9c0-.7.5-1.1 1.1-1.2.6 0 1.1.4 1.2 1v.6c0 .4-.2 1 .1 1.3.3.3.9.1 1.3.1h1.6c.4 0 .7.3.8.8.1.4-.1.8-.4 1.1-.3.2-.6.2-.9.2h-2.1c-.3 0-.4 0-.4.4v4.7c0 1.1.9 1.6 1.9 1.1.3-.1.5-.3.7-.5.4-.3.8-.3 1.2 0 .4.3.4.8.2 1.2-.3.7-.9 1.1-1.5 1.3-1.3.5-2.6.5-3.8-.4-.7-.6-1-1.4-1.1-2.4.1-.7.1-1.6.1-2.4zm24.7-4.1c.8-1 1.8-1.4 3-1.3.7.1 1.4.3 1.9.9.3.4.5.9.4 1.5-.1.4-.3.7-.7.9-.5.2-.9 0-1.3-.3-.7-.7-1.3-.9-2.1-.5-.5.3-.8.7-1 1.3-.2.5-.3 1.1-.3 1.6v4.5c0 .5-.2.9-.6 1.1-.4.2-.8.2-1.2-.1-.4-.3-.5-.7-.5-1.1v-8.4c0-.7.4-1.2 1-1.3.7-.1 1.1.3 1.3 1.1.1-.1.1 0 .1.1zm-54 4.2v4.3c0 .8-.6 1.3-1.4 1.2-.5-.1-.9-.5-.9-1.1v-8.7c0-.7.5-1.1 1.2-1.1s1.1.4 1.2 1.2c-.1 1.3-.1 2.8-.1 4.2zm.3-8.2c0 .8-.6 1.4-1.4 1.4-.8 0-1.5-.6-1.5-1.4 0-.8.7-1.4 1.5-1.4s1.4.6 1.4 1.4z"/> 75 </svg> 76 </a> 77 </div> 78 <div> 79 <div class="title"> 80 <span class="sigstore">sigstore </span> 81 <span>authentication successful!</span> 82 </div> 83 <div class="content"> 84 <span>You may now close this page.</span> 85 </div> 86 </div> 87 <div class="anchor"> 88 <div class="links"> 89 <a href="https://sigstore.dev/" class="link login"><span class="sigstore">sigstore</span> home <span class="arrow">→</span></a> 90 <a href="https://docs.sigstore.dev/" class="link login"><span class="sigstore">sigstore</span> documentation <span class="arrow">→</span></a> 91 <a href="https://blog.sigstore.dev/" class="link"><span class="sigstore">sigstore</span> blog <span class="arrow">→</span></a> 92 </div> 93 </div> 94 </div> 95 <script> 96 document.getElementById("favicon").setAttribute("href", "data:image/svg+xml," + encodeURIComponent(document.getElementById("logo").outerHTML)); 97 </script> 98 </body> 99</html> 100""" # noqa: E501 101 102 103class _OAuthFlow: 104 def __init__(self, client_id: str, client_secret: str, issuer: Issuer): 105 self._client_id = client_id 106 self._client_secret = client_secret 107 self._issuer = issuer 108 self._server = _OAuthRedirectServer( 109 self._client_id, self._client_secret, self._issuer 110 ) 111 self._server_thread = threading.Thread( 112 target=lambda server: server.serve_forever(), 113 args=(self._server,), 114 ) 115 116 def __enter__(self) -> _OAuthRedirectServer: 117 self._server_thread.start() 118 119 return self._server 120 121 def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None: 122 self._server.shutdown() 123 self._server_thread.join() 124 125 126class _OAuthRedirectHandler(http.server.BaseHTTPRequestHandler): 127 def log_message(self, _format: str, *_args: Any) -> None: 128 pass 129 130 def do_GET(self) -> None: 131 _logger.debug(f"GET: {self.path} with {dict(self.headers)}") 132 server = cast(_OAuthRedirectServer, self.server) 133 134 # If the auth response has already been populated, the main thread will be stopping this 135 # thread and accessing the auth response shortly so we should stop servicing any requests. 136 if server.auth_response is not None: 137 _logger.debug(f"{self.path} unavailable (teardown)") 138 self.send_response(404) 139 return None 140 141 r = urllib.parse.urlsplit(self.path) 142 143 # We only understand two kinds of requests: 144 # 1. The response from a successful OAuth redirect 145 # 2. The initial request to /, which kicks off (1) 146 if r.path == server.redirect_path: 147 self.send_response(200) 148 self.send_header("Content-Type", "text/html; charset=utf-8") 149 body = AUTH_SUCCESS_HTML.encode("utf-8") 150 self.send_header("Content-Length", str(len(body))) 151 self.end_headers() 152 self.wfile.write(body) 153 server.auth_response = urllib.parse.parse_qs(r.query) 154 elif r.path == server.auth_request_path: 155 self.send_response(302) 156 self.send_header("Location", server.auth_endpoint) 157 self.end_headers() 158 else: 159 # Anything else sends a "Not Found" response. 160 self.send_response(404) 161 162 163OOB_REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob" 164 165 166class _OAuthSession: 167 def __init__(self, client_id: str, client_secret: str, issuer: Issuer): 168 self.__poison = False 169 170 self._client_id = client_id 171 self._client_secret = client_secret 172 self._issuer = issuer 173 self._state = str(uuid.uuid4()) 174 self._nonce = str(uuid.uuid4()) 175 176 self.code_verifier = B64Str( 177 base64.urlsafe_b64encode(os.urandom(32)).rstrip(b"=").decode() 178 ) 179 180 @property 181 def code_challenge(self) -> str: 182 return B64Str( 183 base64.urlsafe_b64encode( 184 hashlib.sha256(self.code_verifier.encode()).digest() 185 ) 186 .rstrip(b"=") 187 .decode() 188 ) 189 190 def auth_endpoint(self, redirect_uri: str) -> str: 191 # Defensive programming: we don't have a nice way to limit the 192 # lifetime of the OAuth session here, so we use the internal 193 # "poison" flag to check if we're attempting to reuse it in a way 194 # that would compromise the flow's security (i.e. nonce reuse). 195 if self.__poison: 196 raise IdentityError("internal error: OAuth endpoint misuse") 197 else: 198 self.__poison = True 199 200 params = self._auth_params(redirect_uri) 201 return f"{self._issuer.oidc_config.authorization_endpoint}?{urllib.parse.urlencode(params)}" 202 203 def _auth_params(self, redirect_uri: str) -> Dict[str, Any]: 204 return { 205 "response_type": "code", 206 "client_id": self._client_id, 207 "client_secret": self._client_secret, 208 "scope": "openid email", 209 "redirect_uri": redirect_uri, 210 "code_challenge": self.code_challenge, 211 "code_challenge_method": "S256", 212 "state": self._state, 213 "nonce": self._nonce, 214 } 215 216 217class _OAuthRedirectServer(http.server.HTTPServer): 218 def __init__(self, client_id: str, client_secret: str, issuer: Issuer) -> None: 219 super().__init__(("localhost", 0), _OAuthRedirectHandler) 220 self.oauth_session = _OAuthSession(client_id, client_secret, issuer) 221 self.auth_response: Optional[Dict[str, List[str]]] = None 222 self._is_out_of_band = False 223 224 @property 225 def base_uri(self) -> str: 226 # NOTE: We'd ideally use `self.server_name` here, but it uses 227 # the FQDN internally (which in turn confuses Sigstore). 228 return f"http://localhost:{self.server_port}" 229 230 @property 231 def auth_request_path(self) -> str: 232 # TODO: Maybe this should be /auth, for clarity? 233 return "/" 234 235 @property 236 def redirect_path(self) -> str: 237 return "/auth/callback" 238 239 @property 240 def redirect_uri(self) -> str: 241 return ( 242 (self.base_uri + self.redirect_path) 243 if not self._is_out_of_band 244 else OOB_REDIRECT_URI 245 ) 246 247 @property 248 def auth_endpoint(self) -> str: 249 return self.oauth_session.auth_endpoint(self.redirect_uri) 250 251 def enable_oob(self) -> None: 252 _logger.debug("enabling out-of-band OAuth flow") 253 self._is_out_of_band = True 254 255 def is_oob(self) -> bool: 256 return self._is_out_of_band
AUTH_SUCCESS_HTML =
'\n<html>\n <head>\n <title>Sigstore Authentication</title>\n <link id="favicon" rel="icon" type="image/svg"/>\n <style>\n :root { font-family: "Trebuchet MS", sans-serif; height: 100%; color: #444444; overflow: hidden; }\n body { display: flex; justify-content: center; height: 100%; margin: 0 10%; background: #FFEAD7; }\n .container { display: flex; flex-direction: column; justify-content: space-between; }\n .sigstore { color: #2F2E71; font-weight: bold; }\n .header { position: absolute; top: 30px; left: 22px; }\n .title { font-size: 3.5em; margin-bottom: 30px; animation: 750ms ease-in-out 0s 1 show; }\n .content { font-size: 1.5em; animation: 250ms hide, 750ms ease-in-out 250ms 1 show; }\n .anchor { position: relative; }\n .links { display: flex; justify-content: space-between; font-size: 1.2em; padding: 60px 0; position: absolute; bottom: 0; left: 0; right: 0; animation: 500ms hide, 750ms ease-in-out 500ms 1 show; }\n .link { color: #444444; text-decoration: none; user-select: none; }\n .link:hover { color: #6349FF; }\n .link:hover>.arrow { transform: scaleX(1.5) translateX(3px); }\n .link:hover>.sigstore { color: inherit; }\n .link, .arrow { transition: 200ms; }\n .arrow { display: inline-block; margin-left: 6px; transform: scaleX(1.5); }\n @keyframes hide { 0%, 100% { opacity: 0; } }\n @keyframes show { 0% { opacity: 0; transform: translateY(40px); } 100% { opacity: 1; } }\n </style>\n </head>\n <body>\n <div class="container">\n <div>\n <a class="header" href="https://sigstore.dev">\n <svg id="logo" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="28.14" height="30.3">\n <circle r="7" cx="14" cy="15" fill="#FFEAD7"></circle>\n <path fill="#2F2E71" d="M27.8 10.9c-.3-1.2-.9-2.2-1.7-3.1-.6-.7-1.3-1.3-2-2-.7-.6-1.2-1.3-1.5-2.1-.2-.4-.4-.8-.7-1.2-.5-.7-1.3-1.2-2.1-1.6-1.3-.7-2.7-.9-4.2-.9-.8 0-1.6.1-2.4.3-1.2.2-2.3.7-3.4 1.3-.7.4-1.3.9-1.9 1.4-1 .8-2 1.6-2.8 2.6-.6.8-1.4 1.3-2.2 1.8-.8.4-1.4 1-2 1.6-.6.6-.9 1.3-.9 2.1 0 .6.1 1.2.2 1.7.2.9.6 1.7.9 2.6.2.5.3 1 .3 1.5s0 1-.1 1.5c-.1 1.1 0 2.3.2 3.4.2 1 .8 1.8 1.8 2.2.1.1.3.1.4.1.2.1.2.2.1.3l-.1.1c-.4.5-.7 1.1-.6 1.8.1 1.1 1.3 1.8 2.3 1.3.6-.2 1.2 0 1.4.4.1.1.1.2.2.3.2.5.4.9.7 1.3.4.5.9.7 1.6.6.4-.1.8-.2 1.2-.4.7-.4 1.3-.9 2-1.5.2-.2.4-.2.7-.2.4 0 .8.2 1.2.5.6.4 1.2.7 1.9.9 1.3.4 2.5.5 3.8.2 1.3-.3 2.4-.9 3.4-1.6.7-.5 1.2-1 1.6-1.7.4-.7.6-1.4.8-2.2.3-1.1.4-2.2.4-3.4.1-1 .2-1.9.5-2.8.2-.7.5-1.4.8-2.1.2-.6.4-1.2.5-1.9.1-1.1 0-2.1-.3-3.1zM14.9.8c.3-.1.7-.1 1-.1h.3c1.1 0 2.1.2 3.1.5.6.2 1.2.6 1.7 1s.7.9.9 1.4v.1c0 .1 0 .2-.1.2s-.1 0-.2-.1c-.4-.4-.7-.8-1.1-1.1-.6-.5-1.2-.9-2-1.1-1.1-.3-2.1-.5-3.2-.7h-.6c.1 0 .1 0 .2-.1-.1 0 0 0 0 0zm-4.5 12.4c.6 0 1.1.5 1.2 1.2 0 .6-.5 1.2-1.2 1.2-.6 0-1.2-.5-1.1-1.2 0-.7.5-1.2 1.1-1.2zm3.8 1.3v-3.4c0-2.3 2-3.1 3.6-2.5.3.1.6.3.9.5.2.2.2.5.1.8-.2.2-.4.3-.7.1-.2-.1-.5-.2-.7-.3-.6-.2-1.3 0-1.6.4-.1.2-.2.4-.2.7-.1.5 0 .9 0 1.4v5.9c0 1.2-.6 2.1-1.8 2.4-1 .3-1.9.2-2.7-.6-.2-.2-.3-.5-.1-.7.1-.2.4-.3.7-.2.3.1.6.3.9.4 1 .1 1.7-.3 1.7-1.4-.1-1.2-.1-2.3-.1-3.5zm-8.8 7.6h-.1c-.1-.1-.2-.1-.3-.2-.2-.2-.4-.3-.6-.5-.3-.3-.5-.6-.7-1-.4-.8-.8-1.7-1-2.7-.1-.5-.2-1-.2-1.5s-.1-1-.2-1.4c-.1-.7-.2-1.5-.2-2.2 0-.9.1-1.7.4-2.5.3-.9.7-1.7 1.4-2.4.6-.6 1.1-1.2 1.7-1.8.1-.1.3-.2.4-.2 0 .1-.1.3-.2.4-.3.4-.6.7-.9 1.1-.5.6-.9 1.2-1.2 1.8-.4.7-.7 1.4-.9 2.2-.1.4-.2.8-.2 1.2 0 .4-.1.8 0 1.3 0 .6.1 1.1.2 1.6.1.6.2 1.1.2 1.7 0 .7.2 1.4.4 2.1 0 .2.2.3.2.5.3.6.6 1.1 1.1 1.5.2.2.4.5.6.7 0 0 0 .1.1.1v.2zM8 24.6c-.4 0-.7.1-1.1.2-.4.1-.6-.1-.7-.5 0-.1-.1-.3 0-.4.1-.3.3-.3.5-.1.2.2.5.4.7.5.1.1.2.1.4.1.1 0 .2.1.4.2H8zm7.6 2.1c-.3.2-.7.3-1.1.3-.3 0-.6-.1-.9-.1h-.2c-.4.1-.7.1-1.1.2-.1 0-.3 0-.4.1H11c-.4 0-.7-.2-1-.5-.1-.1-.2-.3-.3-.5-.1-.1-.1-.2-.1-.4 0-.1.1-.1.2-.1h.1c.5.3 1.1.4 1.6.5.7.1 1.4.2 2.1.2.4 0 .7.1 1.1.1h.8c.2.1.1.1.1.2zm3.7-2.5c-.7.4-1.5.7-2.3.9-.2 0-.5.1-.7.1-.2 0-.5 0-.7.1-.4.1-.8 0-1.2 0-.3 0-.6-.1-.9 0h-.2c-.4-.1-.9-.2-1.3-.3-.5-.1-1-.3-1.4-.5-.4-.1-.8-.3-1.1-.5-.2-.1-.4-.3-.6-.4-.6-.6-1.2-1.1-1.7-1.6-.4-.5-.8-.9-1.2-1.4-.4-.6-.7-1.2-1-1.9l-.3-.9c-.1-.3-.2-.5-.2-.8v-.8c.3.8.5 1.7.9 2.5.7 1.6 1.7 3 3 4.1 1.4 1.1 2.9 1.8 4.6 2.1.9.2 1.8.2 2.7.2 1.1-.1 2.2-.3 3.2-.8.2-.1.3-.2.5-.2 0 .1 0 .1-.1.1zm.1-8.7c-.6 0-1.1-.5-1.1-1.2 0-.6.5-1.2 1.2-1.2.6 0 1.1.5 1.1 1.2s-.5 1.3-1.2 1.2zm6.2 5.7c0 .4-.1.8-.2 1.2-.1.4-.1.9-.3 1.3-.1.4-.2.7-.4 1.1-.1.3-.3.6-.6.8-.3.2-.5.4-.9.5-.4.2-.7.3-1.2.3h-.9c-.2-.1-.2-.1-.1-.3.1-.2.3-.3.5-.4.3-.2.6-.5.8-.7.7-.7 1.3-1.6 1.9-2.4.4-.4.6-1 .9-1.5.1-.1.1-.2.2-.3.3.2.3.3.3.4zm-15-16.8c1.7-.8 3.5-1.1 5.3-.9.4 0 .8.1 1.1.3l1.8.6c.6.2 1.2.5 1.7.8.7.4 1.3.9 1.9 1.5.8.8 1.5 1.6 2 2.6.3.6.5 1.2.7 1.8.2.7.4 1.5.4 2.2v.9c0 .4-.1.8-.1 1.2v-1c0-1.2-.3-2.3-.6-3.4l-.6-1.5c-.2-.6-.5-1.1-.9-1.6-.1-.1-.3-.1-.4-.2-.1 0-.1 0-.2-.1-.5-.5-1.1-1-1.7-1.5-.8-.6-1.7-1.1-2.6-1.4-.4-.2-.8-.3-1.2-.4-.9-.2-1.8-.4-2.7-.3h-.9c-.3 0-.6.1-1 .2-.6.1-1.2.3-1.7.5h-.1s-.1 0 0-.1c0 0 0-.1-.1-.2m16.2 11.1c-.1-.8 0-1.7 0-2.5-.1-.8-.2-1.6-.4-2.4.5.7.6 1.6.7 2.4 0 .8 0 1.7-.3 2.5zm.6.5c0-.3.1-.7.2-1.1.1-.4.1-.9.1-1.3v-.4c0-.8-.2-1.6-.4-2.4-.4-.9-.8-1.6-1.4-2.4-.5-.6-.9-1.2-1.4-1.8l-.2-.2c.1 0 .1 0 .1.1 1 .8 1.8 1.6 2.4 2.7.5 1 .9 2 1 3.1.3 1.3.1 2.5-.4 3.7z"/>\n </svg><svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="120" height="30.3" viewBox="28.14 0 120 30.3">\n <path fill="#2F2E71" d="M57.7 18c.9 0 1.9-.1 2.9.3.9.3 1.5.9 1.7 2 .1 1-.2 1.9-1.1 2.5-1.1.8-2.3.9-3.6 1-1.4 0-2.9 0-4.3-.6-1.6-.7-1.8-2.6-.4-3.6.3-.2.2-.3.1-.5-.7-.8-.7-2.2.3-2.8.3-.2.2-.3 0-.6-1.4-1.6-.7-4.1 1.3-4.8 1.6-.6 3.2-.6 4.8-.1.2.1.3.1.5-.1.3-.3.6-.5.9-.7.5-.3 1.1-.3 1.4 0 .3.4.3.9-.2 1.3-.7.5-.8 1-.6 1.9.4 1.5-.6 2.9-2.1 3.4-1.3.5-2.7.5-4 .2-.3-.1-.5-.1-.6.2-.1.3-.1.6.2.8.2.1.5.2.8.2h2zm-.6-2.7c.3 0 .5 0 .7-.1.8-.2 1.3-.7 1.4-1.4.1-.7-.3-1.3-.9-1.6-.8-.3-1.6-.3-2.4 0-1 .4-1.2 1.7-.6 2.4.5.6 1.2.7 1.8.7zm-.2 4.6h-1.8c-.4 0-.6.2-.7.5-.3.7.1 1.2.9 1.4 1.2.2 2.5.2 3.7-.1l.6-.3c.5-.3.4-1.1-.1-1.3-.2-.1-.5-.2-.7-.2h-1.9zm58.6-3.3h-3.2c-.3 0-.3.1-.3.4.2 1.2 1.3 2.1 2.8 2.3 1.1.1 2.1-.1 2.9-.9.2-.2.4-.3.6-.4.4-.2.8-.2 1.1.1.4.3.4.7.3 1.1-.3.9-.9 1.4-1.7 1.8-2.3 1-4.5.9-6.5-.6-1-.7-1.5-1.8-1.7-3-.3-1.7-.2-3.3.8-4.7 1.3-1.8 3.1-2.4 5.2-2.1 2 .3 3.4 1.3 4 3.2.2.6.3 1.2.2 1.8-.1.8-.4 1.1-1.2 1.1-1.1-.1-2.2-.1-3.3-.1zm-.7-1.9h2.4c.4 0 .4-.1.4-.5-.3-1.1-1.2-1.9-2.5-2-1.5-.1-2.6.6-3.1 1.9-.2.5-.1.6.4.6h2.4zm-23 6.7c-3.3 0-5.5-2.2-5.6-5.5 0-3.2 2.2-5.6 5.4-5.6 3.4 0 5.7 2.2 5.8 5.5 0 3.4-2.2 5.6-5.6 5.6zm0-2.1c1.9 0 3.2-1.3 3.3-3.3.1-2-1.3-3.4-3.2-3.4-1.8 0-3.2 1.4-3.2 3.3-.1 1.9 1.2 3.4 3.1 3.4zm-22.6 2.1c-1.1 0-2.4-.3-3.5-1.4-.3-.4-.6-.8-.7-1.3 0-.4.1-.7.4-.9.3-.2.7-.2 1 0 .3.2.6.4.8.6.9.9 2 1.1 3.2.9.6-.1 1-.5 1-1 .1-.5-.2-1-.8-1.2-.7-.3-1.4-.3-2.1-.5-.8-.2-1.6-.4-2.2-.9-1.5-1.2-1.4-3.5.2-4.6 1.2-.8 2.6-.9 4-.7 1 .1 1.9.5 2.6 1.2.3.3.4.6.5.9.1.4 0 .7-.3 1-.3.3-.7.3-1 .1-.4-.2-.7-.5-1.1-.8-.8-.6-1.7-.8-2.7-.5-.6.1-.9.5-.9 1s.3.9.8 1.1c.9.3 1.9.4 2.9.7.6.2 1.1.4 1.5.8 1.5 1.4 1.1 4.1-.9 5.1-.7.3-1.5.4-2.7.4zm-30.3 0c-1.5 0-3-.3-4.1-1.5-.3-.3-.4-.6-.5-1-.1-.4-.1-.8.3-1.1.4-.2.9-.2 1.3.1.3.2.6.5.8.7.9.8 1.9.9 3 .7.6-.1.9-.5.9-1.1 0-.5-.3-1-.8-1.2l-2.7-.6c-1.1-.3-2-.8-2.4-2-.6-1.7.4-3.4 2.2-3.9 1.7-.5 3.3-.3 4.8.5.6.3 1 .8 1.2 1.4.1.4.1.9-.3 1.1-.4.3-.8.2-1.2-.1-.4-.3-.7-.7-1.2-.9-.8-.4-1.5-.5-2.4-.3-.5.1-.8.4-.8.9s.2.8.7 1c.7.3 1.4.3 2.1.5.8.2 1.5.3 2.2.8 1.2.8 1.5 2.5.9 3.8-.7 1.4-1.9 1.8-3.3 2-.3.2-.5.2-.7.2zM78 15.8v-2.6c0-.3-.1-.4-.4-.4h-1.3c-.6-.1-.9-.5-.9-1s.4-1 .9-1h1.3c.3 0 .4-.1.4-.4V8.9c0-.7.5-1.1 1.1-1.2.6 0 1.1.4 1.2 1v.6c0 .4-.2 1 .1 1.3.3.3.9.1 1.3.1h1.6c.4 0 .7.3.8.8.1.4-.1.8-.4 1.1-.3.2-.6.2-.9.2h-2.1c-.3 0-.4 0-.4.4v4.7c0 1.1.9 1.6 1.9 1.1.3-.1.5-.3.7-.5.4-.3.8-.3 1.2 0 .4.3.4.8.2 1.2-.3.7-.9 1.1-1.5 1.3-1.3.5-2.6.5-3.8-.4-.7-.6-1-1.4-1.1-2.4.1-.7.1-1.6.1-2.4zm24.7-4.1c.8-1 1.8-1.4 3-1.3.7.1 1.4.3 1.9.9.3.4.5.9.4 1.5-.1.4-.3.7-.7.9-.5.2-.9 0-1.3-.3-.7-.7-1.3-.9-2.1-.5-.5.3-.8.7-1 1.3-.2.5-.3 1.1-.3 1.6v4.5c0 .5-.2.9-.6 1.1-.4.2-.8.2-1.2-.1-.4-.3-.5-.7-.5-1.1v-8.4c0-.7.4-1.2 1-1.3.7-.1 1.1.3 1.3 1.1.1-.1.1 0 .1.1zm-54 4.2v4.3c0 .8-.6 1.3-1.4 1.2-.5-.1-.9-.5-.9-1.1v-8.7c0-.7.5-1.1 1.2-1.1s1.1.4 1.2 1.2c-.1 1.3-.1 2.8-.1 4.2zm.3-8.2c0 .8-.6 1.4-1.4 1.4-.8 0-1.5-.6-1.5-1.4 0-.8.7-1.4 1.5-1.4s1.4.6 1.4 1.4z"/>\n </svg>\n </a>\n </div>\n <div>\n <div class="title">\n <span class="sigstore">sigstore </span>\n <span>authentication successful!</span>\n </div>\n <div class="content">\n <span>You may now close this page.</span>\n </div>\n </div>\n <div class="anchor">\n <div class="links">\n <a href="https://sigstore.dev/" class="link login"><span class="sigstore">sigstore</span> home <span class="arrow">→</span></a>\n <a href="https://docs.sigstore.dev/" class="link login"><span class="sigstore">sigstore</span> documentation <span class="arrow">→</span></a>\n <a href="https://blog.sigstore.dev/" class="link"><span class="sigstore">sigstore</span> blog <span class="arrow">→</span></a>\n </div>\n </div>\n </div>\n <script>\n document.getElementById("favicon").setAttribute("href", "data:image/svg+xml," + encodeURIComponent(document.getElementById("logo").outerHTML));\n </script>\n </body>\n</html>\n'
OOB_REDIRECT_URI =
'urn:ietf:wg:oauth:2.0:oob'