(
self, request: Request, challenge: _DigestAuthChallenge
)
| 253 | raise ProtocolError(message, request=request) from exc |
| 254 | |
| 255 | def _build_auth_header( |
| 256 | self, request: Request, challenge: _DigestAuthChallenge |
| 257 | ) -> str: |
| 258 | hash_func = self._ALGORITHM_TO_HASH_FUNCTION[challenge.algorithm.upper()] |
| 259 | |
| 260 | def digest(data: bytes) -> bytes: |
| 261 | return hash_func(data).hexdigest().encode() |
| 262 | |
| 263 | A1 = b":".join((self._username, challenge.realm, self._password)) |
| 264 | |
| 265 | path = request.url.raw_path |
| 266 | A2 = b":".join((request.method.encode(), path)) |
| 267 | # TODO: implement auth-int |
| 268 | HA2 = digest(A2) |
| 269 | |
| 270 | nc_value = b"%08x" % self._nonce_count |
| 271 | cnonce = self._get_client_nonce(self._nonce_count, challenge.nonce) |
| 272 | self._nonce_count += 1 |
| 273 | |
| 274 | HA1 = digest(A1) |
| 275 | if challenge.algorithm.lower().endswith("-sess"): |
| 276 | HA1 = digest(b":".join((HA1, challenge.nonce, cnonce))) |
| 277 | |
| 278 | qop = self._resolve_qop(challenge.qop, request=request) |
| 279 | if qop is None: |
| 280 | # Following RFC 2069 |
| 281 | digest_data = [HA1, challenge.nonce, HA2] |
| 282 | else: |
| 283 | # Following RFC 2617/7616 |
| 284 | digest_data = [HA1, challenge.nonce, nc_value, cnonce, qop, HA2] |
| 285 | |
| 286 | format_args = { |
| 287 | "username": self._username, |
| 288 | "realm": challenge.realm, |
| 289 | "nonce": challenge.nonce, |
| 290 | "uri": path, |
| 291 | "response": digest(b":".join(digest_data)), |
| 292 | "algorithm": challenge.algorithm.encode(), |
| 293 | } |
| 294 | if challenge.opaque: |
| 295 | format_args["opaque"] = challenge.opaque |
| 296 | if qop: |
| 297 | format_args["qop"] = b"auth" |
| 298 | format_args["nc"] = nc_value |
| 299 | format_args["cnonce"] = cnonce |
| 300 | |
| 301 | return "Digest " + self._get_header_value(format_args) |
| 302 | |
| 303 | def _get_client_nonce(self, nonce_count: int, nonce: bytes) -> bytes: |
| 304 | s = str(nonce_count).encode() |
no test coverage detected