feat(spanner): auth login support for Spanner Omni endpoints - #18273
feat(spanner): auth login support for Spanner Omni endpoints#18273sagnghos wants to merge 7 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces Spanner Omni authentication and connection utilities, implementing the OPAQUE protocol for login authentication. It adds a new SpannerOmniCredentials class, a LoginClient for gRPC communication, and cryptographic helpers in opaque.py, while updating connection and client classes to support username and password parameters. The review feedback highlights several important improvements, including resolving a potential NameError in connection.py when credentials is referenced before definition, ensuring the close() method of _RequestIterator is idempotent, cancelling active gRPC calls on exceptions to free resources, validating masked_response length early to prevent DoS vectors, and correcting type annotations for mutated headers parameters using MutableMapping.
22e1f60 to
c4d6def
Compare
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces support for Spanner Omni authentication using the OPAQUE protocol, adding username and password parameters to the connection and client interfaces, along with the necessary cryptographic utilities and OPAQUE login client. A critical performance issue was identified in the async gRPC interceptors, where calling the synchronous refresh() method directly blocks the asyncio event loop; it is recommended to run this synchronous call in a thread pool executor using loop.run_in_executor to prevent blocking.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces support for Spanner Omni authentication using the OPAQUE protocol, adding username and password parameters to connection and client classes, implementing SpannerOmniCredentials, and adding the necessary cryptographic utilities and gRPC login client. The review feedback suggests improving thread safety in SpannerOmniCredentials by using a threading.Lock to synchronize token refreshes, implementing _perform_refresh_token instead of overriding refresh directly when subclassing CredentialsWithRegionalAccessBoundary, and optimizing the xor_bytes utility in opaque.py using fast integer bitwise operations.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces support for Spanner Omni authentication using the OPAQUE protocol, adding username and password parameters to the DB-API connection and client interfaces, implementing the OPAQUE login flow and cryptographic utilities, and updating transport helpers. The review feedback highlights critical security improvements in opaque.py to prevent creating immutable copies of sensitive data (plaintext passwords, blind scalars, and private keyshares) in memory, ensuring they can be zeroized in place. Additionally, the feedback suggests enhancing the robustness of the gRPC bidirectional streaming in LoginClient by safely handling premature stream closures to avoid unhandled StopIteration exceptions.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces support for Spanner Omni authentication using the OPAQUE protocol, adding the SpannerOmniCredentials, LoginClient, and UserAuthenticator classes along with corresponding protobuf definitions and tests. It updates the DB-API connect function and the Spanner Client (both synchronous and asynchronous) to accept username and password parameters when instance_type is set to 'omni'. Feedback on the changes suggests improving the gRPC channel initialization in SpannerOmniCredentials to support mTLS using system default root certificates when ca_certificate is omitted but client certificates are provided, thereby avoiding breaking changes and preserving backwards compatibility.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces support for Spanner Omni authentication using the OPAQUE protocol. It adds new connection parameters (username and password) to the DB-API and client constructors, implements the SpannerOmniCredentials class with synchronous and asynchronous gRPC interceptors, and provides the cryptographic implementation of the OPAQUE protocol. One issue was identified in the cryptographic utilities where random_oracle_sha256 could crash due to an unvalidated iter_count exceeding 255 when encoding it as a single byte.
| if iter_count * hash_output_length > 130048: | ||
| raise ValueError( | ||
| f"Domain bit length must not be greater than 130048: {output_bit_length}" | ||
| ) |
There was a problem hiding this comment.
In random_oracle_sha256, i is encoded as a single byte using bytes([i]) on line 303. This restricts iter_count to a maximum of 255, as bytes([i]) will raise a ValueError for any i >= 256. Therefore, the maximum supported bit length is 255 * 256 = 65280 bits, rather than 130048 bits. The check should be updated to enforce iter_count <= 255 to prevent runtime crashes for larger domain sizes.
| if iter_count * hash_output_length > 130048: | |
| raise ValueError( | |
| f"Domain bit length must not be greater than 130048: {output_bit_length}" | |
| ) | |
| if iter_count > 255: | |
| raise ValueError( | |
| f"Domain bit length must not be greater than 65280: {output_bit_length}" | |
| ) |
This PR introduces native username/password authentication support for Spanner Omni endpoints using the OPAQUE password-authenticated key exchange (PAKE) protocol, maintaining parity with the Go and Java client implementations.
Java implementation - googleapis/google-cloud-java#13470
Go implementation - googleapis/google-cloud-go#20085
Key Changes:
authentication_pb2*,login_pb2*,login_pb2_grpc*) and a gRPCLoginClientto handle the authentication handshake with Spanner Omni endpoints over theLoginService/Loginbi-directional stream.opaque.py): Implements the client-side OPAQUE protocol utilizing NIST P-256 elliptic curve arithmetic (cryptography), Argon2id stretching with defensive parameter validation, RFC 9380 hash-to-curve / random oracle mapping, and constant-time MAC verification.finallyblocks.credentials.py): ImplementsSpannerOmniCredentialssubclassinggoogle.auth.credentials.Credentialsto manage Bearer access token lifecycle, automatic expiry checks, and transparent token refreshes. Provides dedicated interceptors for both synchronousgrpcand asynchronousgrpc.aiochannels across all RPC patterns (unary-unary, unary-stream, stream-unary, stream-stream).spanner_v1.Clientandspanner_v1.AsyncClientto acceptusername,password, andinstance_type="omni", automatically wiring upSpannerOmniCredentials.google.cloud.spanner_dbapi.connect()to acceptusernameandpasswordfor DB-API connections.LoginClientstate machine, credentials lifecycle/interceptors, DB-API connect options, and system test configurations for both sync and async client workflows against live Spanner Omni instances.Running Integration Tests
To run integration tests against a live Spanner Omni instance with auth login, set the following environment variables: