From ea4707385ba2f2cb20254c280d4d85f567d34e5a Mon Sep 17 00:00:00 2001 From: sagnghos Date: Thu, 7 May 2026 17:11:43 +0000 Subject: [PATCH 01/15] feat(spanner): login functionality Spanner Omni --- java-spanner/google-cloud-spanner/pom.xml | 17 +- .../google/cloud/spanner/SpannerOptions.java | 79 ++++ .../cloud/spanner/omni/LoginClient.java | 270 +++++++++++++ .../spanner/omni/SpannerOmniCredentials.java | 141 +++++++ .../cloud/spanner/omni/opaque/OpaqueUtil.java | 355 ++++++++++++++++++ .../testing/ExperimentalHostHelper.java | 7 + .../src/main/proto/login.proto | 180 +++++++++ 7 files changed, 1048 insertions(+), 1 deletion(-) create mode 100644 java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java create mode 100644 java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java create mode 100644 java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java create mode 100644 java-spanner/google-cloud-spanner/src/main/proto/login.proto diff --git a/java-spanner/google-cloud-spanner/pom.xml b/java-spanner/google-cloud-spanner/pom.xml index a4f57e2e7740..2b4590be1c3b 100644 --- a/java-spanner/google-cloud-spanner/pom.xml +++ b/java-spanner/google-cloud-spanner/pom.xml @@ -159,14 +159,19 @@ 0.6.1 com.google.protobuf:protoc:4.33.2:exe:${os.detected.classifier} + grpc-java + io.grpc:protoc-gen-grpc-java:1.64.0:exe:${os.detected.classifier} ${project.basedir}/../proto-google-cloud-spanner-v1/src/main/proto + ${project.basedir}/../google-cloud-spanner/src/main/proto - test-compile + compile + compile + compile-custom test-compile @@ -544,6 +549,16 @@ javax.annotation javax.annotation-api + + org.bouncycastle + bcprov-jdk18on + 1.78 + + + com.google.crypto.tink + tink + 1.13.0 + diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java index 2995730664e2..257dc1f263f5 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java @@ -91,6 +91,7 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.time.Duration; @@ -1817,6 +1818,84 @@ public Builder setExperimentalHost(String host) { return this; } + + /** + * Authenticates to Spanner Omni using the provided username and password file, and configures + * the resulting token for use in subsequent Spanner API calls. The endpoint must be set on the + * builder before calling this method. + * + * @param username The username for login. + * @param passwordFile The path to a file containing the password. + * @return this builder + */ + public Builder login(String username, String passwordFile) { + return login(username, passwordFile, true); + } + + /** + * Authenticates to Spanner Omni using the provided username and password file, and configures + * the resulting token for use in subsequent Spanner API calls. The endpoint must be set on the + * builder before calling this method. + * + * @param username The username for login. + * @param passwordFile The path to a file containing the password. + * @param backgroundRefresh Whether to proactively refresh the token in a background thread before it expires. If false, GAX still triggers a synchronous inline refresh upon UNAUTHENTICATED error. + * @return this builder + */ + public Builder login(String username, String passwordFile, boolean backgroundRefresh) { + try { + byte[] rawBytes = Files.readAllBytes(Paths.get(passwordFile)); + int len = rawBytes.length; + while (len > 0 && (rawBytes[len - 1] == '\n' || rawBytes[len - 1] == '\r')) { + len--; + } + byte[] passwordBytes = java.util.Arrays.copyOf(rawBytes, len); + return loginWithPasswordBytes(username, passwordBytes, backgroundRefresh); + } catch (IOException e) { + throw SpannerExceptionFactory.newSpannerException( + ErrorCode.NOT_FOUND, "Could not read password file: " + passwordFile, e); + } + } + + /** + * Authenticates to Spanner Omni using the provided username and password, and configures the + * resulting token for use in subsequent Spanner API calls. The endpoint must be set on the + * builder before calling this method. + * + * @param username The username for login. + * @param password The password for login. + * @return this builder + */ + public Builder loginWithPassword(String username, String password) { + return loginWithPassword(username, password, true); + } + + /** + * Authenticates to Spanner Omni using the provided username and password, and configures the + * resulting token for use in subsequent Spanner API calls. The endpoint must be set on the + * builder before calling this method. + * + * @param username The username for login. + * @param password The password for login. + * @param backgroundRefresh Whether to proactively refresh the token in a background thread before it expires. If false, GAX still triggers a synchronous inline refresh upon UNAUTHENTICATED error. + * @return this builder + */ + public Builder loginWithPassword(String username, String password, boolean backgroundRefresh) { + return loginWithPasswordBytes(username, password.getBytes(StandardCharsets.UTF_8), backgroundRefresh); + } + + private Builder loginWithPasswordBytes(String username, byte[] password, boolean backgroundRefresh) { + if (this.experimentalHost == null) { + throw new IllegalStateException("Endpoint must be set before calling login."); + } + String target = this.experimentalHost.replaceFirst("^https?://", ""); + com.google.crypto.tink.util.SecretBytes secretBytes = com.google.crypto.tink.util.SecretBytes.copyFrom( + password, com.google.crypto.tink.InsecureSecretKeyAccess.get()); + java.util.Arrays.fill(password, (byte) 0); + super.setCredentials(new com.google.cloud.spanner.omni.SpannerOmniCredentials(username, secretBytes, target, backgroundRefresh)); + return this; + } + /** Enables gRPC-GCP extension with the default settings. This option is enabled by default. */ public Builder enableGrpcGcpExtension() { return this.enableGrpcGcpExtension(null); diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java new file mode 100644 index 000000000000..3d8396ba19a9 --- /dev/null +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java @@ -0,0 +1,270 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner.omni; + +import com.google.cloud.spanner.SpannerException; +import com.google.cloud.spanner.SpannerExceptionFactory; +import com.google.common.base.Preconditions; +import com.google.cloud.spanner.omni.opaque.OpaqueUtil; +import com.google.protobuf.ByteString; +import google.spanner.omni.v1.AccessToken; +import google.spanner.omni.v1.FinalOpaqueLoginRequest; +import google.spanner.omni.v1.InitialOpaqueLoginRequest; +import google.spanner.omni.v1.InitialOpaqueLoginResponse; +import google.spanner.omni.v1.LoginRequest; +import google.spanner.omni.v1.LoginResponse; +import google.spanner.omni.v1.LoginServiceGrpc; +import google.spanner.omni.v1.OpaqueLoginRequest; +import io.grpc.ManagedChannel; +import io.grpc.stub.StreamObserver; +import java.io.IOException; +import java.security.GeneralSecurityException; + +import com.google.crypto.tink.util.SecretBytes; +import com.google.crypto.tink.InsecureSecretKeyAccess; + +/** + * Client for {@link google.spanner.omni.v1.LoginServiceGrpc}. This class is used to + * authenticate to Spanner Omni using username/password. + */ +public class LoginClient { + private static final java.security.SecureRandom SECURE_RANDOM = new java.security.SecureRandom(); + + private final LoginServiceGrpc.LoginServiceStub stub; + + public LoginClient(ManagedChannel channel) { + this.stub = LoginServiceGrpc.newStub(channel).withDeadlineAfter(60, java.util.concurrent.TimeUnit.SECONDS); + } + + /** + * Logs in to Spanner Omni using OPAQUE protocol. + * + * @param username The username to login with. + * @param password The password to login with. + * @return The access token. + * @throws SpannerException if login fails. + */ + public AccessToken login(String username, SecretBytes password) throws SpannerException { + Preconditions.checkNotNull(username); + Preconditions.checkNotNull(password); + byte[] passwordBytes = null; + try { + passwordBytes = password.toByteArray(InsecureSecretKeyAccess.get()); + byte[] randomNonce = OpaqueUtil.nonce(); + byte[][] keyPair = OpaqueUtil.generateKeyPair(OpaqueUtil.concat(randomNonce, OpaqueUtil.DIFFIE_HELLMAN_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8))); + byte[] clientPrivateKeyshare = keyPair[0]; + byte[] clientPublicKeyshare = keyPair[1]; + byte[] clientNonce = OpaqueUtil.nonce(); + byte[] blind = new byte[32]; + SECURE_RANDOM.nextBytes(blind); + + byte[] blindedMessage = OpaqueUtil.blind(passwordBytes, blind); + + LoginRequest initialRequest = + LoginRequest.newBuilder() + .setUsername(username) + .setOpaqueRequest( + OpaqueLoginRequest.newBuilder() + .setInitialRequest( + InitialOpaqueLoginRequest.newBuilder() + .setBlindedMessage(ByteString.copyFrom(blindedMessage)) + .setClientNonce(ByteString.copyFrom(clientNonce)) + .setClientPublicKeyshare(ByteString.copyFrom(clientPublicKeyshare)))) + .build(); + + LoginStreamIOCall call = new LoginStreamIOCall(stub); + call.send(initialRequest); + LoginResponse initialResponse = call.getResponse(); + + InitialOpaqueLoginResponse initialOpaqueResponse = + initialResponse.getOpaqueResponse().getInitialResponse(); + + byte[] clientMac = + generateClientMac( + username, + passwordBytes, + blind, + clientNonce, + clientPublicKeyshare, + clientPrivateKeyshare, + initialOpaqueResponse); + + LoginRequest finalRequest = + LoginRequest.newBuilder() + .setUsername(username) + .setOpaqueRequest( + OpaqueLoginRequest.newBuilder() + .setFinalRequest( + FinalOpaqueLoginRequest.newBuilder() + .setClientMac(ByteString.copyFrom(clientMac)))) + .build(); + + call.send(finalRequest); + call.halfClose(); + LoginResponse finalResponse = call.getResponse(); + return finalResponse.getAccessToken(); + } catch (GeneralSecurityException | IOException | InterruptedException e) { + throw SpannerExceptionFactory.newSpannerException(e); + } finally { + if (passwordBytes != null) { + java.util.Arrays.fill(passwordBytes, (byte) 0); + } + } + } + + private byte[] generateClientMac( + String username, + byte[] password, + byte[] blind, + byte[] clientNonce, + byte[] clientPublicKeyshare, + byte[] clientPrivateKeyshare, + InitialOpaqueLoginResponse initialOpaqueResponse) + throws GeneralSecurityException, IOException { + byte[] oprf = + OpaqueUtil.finalize(blind, initialOpaqueResponse.getEvaluatedMessage().toByteArray()); + byte[] stretchedOprf = OpaqueUtil.stretch(oprf); + byte[] randomizedPassword = OpaqueUtil.extract(OpaqueUtil.concat(oprf, stretchedOprf)); + byte[] maskingKey = + OpaqueUtil.expand(randomizedPassword, OpaqueUtil.MASKING_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8), 32); + byte[] credentialResponsePad = + OpaqueUtil.expand( + maskingKey, + OpaqueUtil.concat( + initialOpaqueResponse.getMaskingNonce().toByteArray(), + "CredentialResponsePad".getBytes(java.nio.charset.StandardCharsets.UTF_8)), + 16 + 33 + 16); + byte[] serializedEnvelope = + OpaqueUtil.xorBytes( + initialOpaqueResponse.getMaskedResponse().toByteArray(), credentialResponsePad); + ByteString envelope = ByteString.copyFrom(serializedEnvelope); + ByteString serverPublicKey = envelope.substring(0, 33); + ByteString envelopeNonce = envelope.substring(33, 33 + 16); + ByteString authTag = envelope.substring(33 + 16, 33 + 16 + 16); + + byte[] authKey = + OpaqueUtil.expand( + randomizedPassword, + OpaqueUtil.concat(envelopeNonce.toByteArray(), OpaqueUtil.AUTH_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8)), + 32); + byte[] seed = + OpaqueUtil.expand( + randomizedPassword, + OpaqueUtil.concat(envelopeNonce.toByteArray(), OpaqueUtil.PRIVATE_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8)), + 32); + byte[][] clientKeyPair = OpaqueUtil.generateKeyPair(OpaqueUtil.concat(seed, OpaqueUtil.DIFFIE_HELLMAN_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8))); + byte[] clientPrivateKey = clientKeyPair[0]; + byte[] clientPublicKey = clientKeyPair[1]; + + + byte[] expectedTag = + OpaqueUtil.mac( + authKey, + OpaqueUtil.concat( + envelopeNonce.toByteArray(), serverPublicKey.toByteArray(), username.getBytes(java.nio.charset.StandardCharsets.UTF_8))); + if (!ByteString.copyFrom(expectedTag).equals(authTag)) { + throw new GeneralSecurityException("Auth tag mismatch"); + } + + byte[] dh1 = + OpaqueUtil.diffieHellman( + clientPrivateKeyshare, initialOpaqueResponse.getServerPublicKeyshare().toByteArray()); + byte[] dh2 = OpaqueUtil.diffieHellman(clientPrivateKeyshare, serverPublicKey.toByteArray()); + byte[] dh3 = + OpaqueUtil.diffieHellman( + clientPrivateKey, initialOpaqueResponse.getServerPublicKeyshare().toByteArray()); + + byte[] inputKeyMaterial = OpaqueUtil.concat(dh1, dh2, dh3); + + byte[] preamble = + OpaqueUtil.concat( + "OPAQUEv1-".getBytes(java.nio.charset.StandardCharsets.UTF_8), + username.getBytes(java.nio.charset.StandardCharsets.UTF_8), + clientNonce, + clientPublicKeyshare, + serverPublicKey.toByteArray(), + initialOpaqueResponse.getEvaluatedMessage().toByteArray(), + initialOpaqueResponse.getServerNonce().toByteArray(), + initialOpaqueResponse.getServerPublicKeyshare().toByteArray()); + byte[] prk = OpaqueUtil.extract(inputKeyMaterial); + byte[] preambleHash = OpaqueUtil.sha256(preamble); + byte[] handshakeSecret = + OpaqueUtil.expand(prk, OpaqueUtil.concat("OPAQUE-HandshakeSecret".getBytes(java.nio.charset.StandardCharsets.UTF_8), preambleHash), 32); + byte[] km2 = OpaqueUtil.expand(handshakeSecret, "OPAQUE-ServerMAC".getBytes(java.nio.charset.StandardCharsets.UTF_8), 32); + byte[] km3 = OpaqueUtil.expand(handshakeSecret, "OPAQUE-ClientMAC".getBytes(java.nio.charset.StandardCharsets.UTF_8), 32); + + byte[] expectedServerMac = OpaqueUtil.mac(km2, OpaqueUtil.sha256(preamble)); + if (!ByteString.copyFrom(expectedServerMac).equals(initialOpaqueResponse.getServerMac())) { + throw new GeneralSecurityException("Server MAC mismatch"); + } + return OpaqueUtil.mac(km3, OpaqueUtil.sha256(OpaqueUtil.concat(preamble, expectedServerMac))); + } + + static class LoginStreamIOCall { + private final LoginServiceGrpc.LoginServiceStub stub; + private final java.util.concurrent.BlockingQueue responseQueue = new java.util.concurrent.LinkedBlockingQueue<>(); + private StreamObserver requestObserver; + private Throwable error; + private boolean completed = false; + + LoginStreamIOCall(LoginServiceGrpc.LoginServiceStub stub) { + this.stub = stub; + requestObserver = + stub.login( + new StreamObserver() { + @Override + public void onNext(LoginResponse value) { + responseQueue.add(value); + } + + @Override + public void onError(Throwable t) { + error = t; + // Add a dummy response to unblock getResponse if it's waiting + responseQueue.add(LoginResponse.getDefaultInstance()); + } + + @Override + public void onCompleted() { + completed = true; + // Add a dummy response to unblock getResponse if it's waiting + responseQueue.add(LoginResponse.getDefaultInstance()); + } + }); + } + + void send(LoginRequest request) { + requestObserver.onNext(request); + } + + LoginResponse getResponse() throws InterruptedException { + LoginResponse response = responseQueue.take(); + if (error != null) { + throw SpannerExceptionFactory.newSpannerException(error); + } + if (response == LoginResponse.getDefaultInstance() && completed) { + return null; + } + return response; + } + + void halfClose() { + requestObserver.onCompleted(); + } + } +} + diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java new file mode 100644 index 000000000000..4a7daada507c --- /dev/null +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java @@ -0,0 +1,141 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner.omni; + +import com.google.auth.oauth2.GoogleCredentials; +import com.google.auth.oauth2.AccessToken; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import java.io.IOException; +import java.util.Date; +import java.util.Base64; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.google.crypto.tink.util.SecretBytes; + +/** + * Credentials implementation for Spanner Omni. Uses the OPAQUE protocol to + * authenticate and fetches short-lived access tokens. Supports optional + * background auto-refreshing before token expiry. + */ +public class SpannerOmniCredentials extends GoogleCredentials { + private static final Logger logger = Logger.getLogger(SpannerOmniCredentials.class.getName()); + + private static final ScheduledExecutorService SHARED_EXECUTOR = Executors.newScheduledThreadPool(1, r -> { + Thread t = new Thread(r, "spanner-omni-refresh"); + t.setDaemon(true); + return t; + }); + + private final String username; + private final SecretBytes password; + private final String target; + private final boolean backgroundRefresh; + private final ManagedChannel loginChannel; + + private ScheduledFuture refreshTask; + + public SpannerOmniCredentials(String username, SecretBytes password, String target) { + this(username, password, target, true); + } + + public SpannerOmniCredentials(String username, SecretBytes password, String target, boolean backgroundRefresh) { + this.username = username; + this.password = password; + this.target = target; + this.backgroundRefresh = backgroundRefresh; + this.loginChannel = ManagedChannelBuilder.forTarget(target).build(); + } + + @Override + public AccessToken refreshAccessToken() throws IOException { + try { + LoginClient loginClient = new LoginClient(this.loginChannel); + google.spanner.omni.v1.AccessToken protoToken = loginClient.login(username, password); + String tokenValue = Base64.getEncoder().encodeToString(protoToken.toByteArray()); + + long createTimeMillis = protoToken.getCreationTime().getSeconds() * 1000 + + protoToken.getCreationTime().getNanos() / 1000000; + long expireTimeMillis = protoToken.getExpirationTime().getSeconds() * 1000 + + protoToken.getExpirationTime().getNanos() / 1000000; + + long tokenLifetimeMillis = expireTimeMillis - createTimeMillis; + if (tokenLifetimeMillis <= 0) { + tokenLifetimeMillis = TimeUnit.MINUTES.toMillis(60); + } + + AccessToken newAccessToken = new AccessToken(tokenValue, new Date(System.currentTimeMillis() + tokenLifetimeMillis)); + + if (backgroundRefresh && !SHARED_EXECUTOR.isShutdown()) { + scheduleRefresh(tokenLifetimeMillis); + } + + return newAccessToken; + } catch (Exception e) { + logger.log(Level.SEVERE, "Failed to login to Spanner Omni. Username: " + username + ", Target: " + target, e); + throw new IOException("Failed to login to Spanner Omni", e); + } + } + + private void scheduleRefresh(long tokenLifetimeMillis) { + if (refreshTask != null && !refreshTask.isDone()) { + refreshTask.cancel(false); + } + + long delayMillis; + if (tokenLifetimeMillis <= TimeUnit.MINUTES.toMillis(5)) { + // For very short-lived tokens (e.g. 15s), refresh at half their lifetime + delayMillis = tokenLifetimeMillis / 2; + } else { + // For long-lived tokens, refresh 5 minutes before expiry + delayMillis = tokenLifetimeMillis - TimeUnit.MINUTES.toMillis(5); + } + + if (delayMillis < 0) { + delayMillis = 0; + } + + java.lang.ref.WeakReference weakThis = new java.lang.ref.WeakReference<>(this); + + Runnable refreshAction = new Runnable() { + @Override + public void run() { + SpannerOmniCredentials creds = weakThis.get(); + if (creds == null) { + // The credentials instance was garbage collected. Stop the background refresh loop. + return; + } + try { + creds.refresh(); + } catch (IOException e) { + logger.log(Level.WARNING, "Failed to auto-refresh Spanner Omni credentials", e); + // Retry in a short interval on failure + long retryDelay = Math.min(TimeUnit.SECONDS.toMillis(5), tokenLifetimeMillis / 4); + if (retryDelay <= 0) retryDelay = 1000; + creds.refreshTask = SHARED_EXECUTOR.schedule(this, retryDelay, TimeUnit.MILLISECONDS); + } + } + }; + + refreshTask = SHARED_EXECUTOR.schedule(refreshAction, delayMillis, TimeUnit.MILLISECONDS); + } +} diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java new file mode 100644 index 000000000000..460727403cce --- /dev/null +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java @@ -0,0 +1,355 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner.omni.opaque; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import com.google.crypto.tink.subtle.Hkdf; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.ec.CustomNamedCurves; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.crypto.generators.Argon2BytesGenerator; +import org.bouncycastle.crypto.params.Argon2Parameters; + +public class OpaqueUtil { + + public static final String LOGIN_DOMAIN_SEPARATION_TAG = "Spanner-Omni-Login"; + public static final String CURVE_NAME = "secp256r1"; + public static final String AUTH_KEY_INFO = "AuthKey"; + public static final String EXPORT_KEY_INFO = "ExportKey"; + public static final String PRIVATE_KEY_INFO = "PrivateKey"; + public static final String MASKING_KEY_INFO = "MaskingKey"; + public static final String DIFFIE_HELLMAN_KEY_INFO = "OPAQUE-DeriveDiffieHellmanKeyPair"; + public static final String HMAC_SHA256 = "HmacSHA256"; + + private static final int NONCE_LENGTH = 16; + private static final int MAC_TAG_LENGTH = 16; + private static final int EXTRACT_OUTPUT_LENGTH = 32; + private static final int STRETCH_OUTPUT_LENGTH = 32; + + // Argon2ID parameters. + private static final int ARGON2_ITERATION_COUNT = 3; + private static final int ARGON2_MEMORY_LIMIT = 64 * 1024; + private static final int ARGON2_THREADS = 4; + private static final int ARGON2_SALT_LENGTH = 32; + + private static final SecureRandom random = new SecureRandom(); + + public static byte[] nonce() { + byte[] nonce = new byte[NONCE_LENGTH]; + random.nextBytes(nonce); + return nonce; + } + + public static byte[] hmacSha256(byte[] key, byte[] message) throws GeneralSecurityException { + Mac mac = Mac.getInstance(HMAC_SHA256); + mac.init(new SecretKeySpec(key, HMAC_SHA256)); + return mac.doFinal(message); + } + + public static byte[] sha256(byte[] message) throws NoSuchAlgorithmException { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + return digest.digest(message); + } + + private static final BigInteger p = new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951"); + private static final BigInteger A = p.subtract(new BigInteger("3")); + private static final BigInteger B = new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16); + private static final BigInteger Z = p.subtract(BigInteger.valueOf(10)); + + private static byte[] expandMessageXmd(byte[] msg, byte[] DST, int lenInBytes) throws GeneralSecurityException { + try { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + int bInBytes = 32; + int ell = (lenInBytes + bInBytes - 1) / bInBytes; + + byte[] dstPrime = new byte[DST.length + 1]; + System.arraycopy(DST, 0, dstPrime, 0, DST.length); + dstPrime[DST.length] = (byte) DST.length; + + byte[] zPad = new byte[64]; + byte[] libStr = new byte[] { (byte) (lenInBytes >> 8), (byte) (lenInBytes & 0xFF) }; + + md.update(zPad); + md.update(msg); + md.update(libStr); + md.update((byte) 0); + md.update(dstPrime); + byte[] b0 = md.digest(); + + byte[] bOut = new byte[ell * bInBytes]; + + md.update(b0); + md.update((byte) 1); + md.update(dstPrime); + byte[] b1 = md.digest(); + System.arraycopy(b1, 0, bOut, 0, bInBytes); + + byte[] bi = b1; + for (int i = 2; i <= ell; i++) { + byte[] bXor = new byte[bInBytes]; + for (int j = 0; j < bInBytes; j++) { + bXor[j] = (byte) (b0[j] ^ bi[j]); + } + md.update(bXor); + md.update((byte) i); + md.update(dstPrime); + bi = md.digest(); + System.arraycopy(bi, 0, bOut, (i - 1) * bInBytes, bInBytes); + } + + byte[] res = new byte[lenInBytes]; + System.arraycopy(bOut, 0, res, 0, lenInBytes); + return res; + } catch (Exception e) { + throw new GeneralSecurityException("Failed to expand message", e); + } + } + + private static int sgn0(BigInteger x) { + return x.testBit(0) ? 1 : 0; + } + + private static ECPoint mapToCurveSSWU(BigInteger u, ECCurve curve) { + BigInteger u2 = u.multiply(u).mod(p); + BigInteger z_u2 = Z.multiply(u2).mod(p); + BigInteger z2_u4 = z_u2.multiply(z_u2).mod(p); + BigInteger den = z2_u4.add(z_u2).mod(p); + + BigInteger tv1; + if (den.equals(BigInteger.ZERO)) { + tv1 = BigInteger.ZERO; + } else { + tv1 = den.modInverse(p); + } + + BigInteger x1; + if (tv1.equals(BigInteger.ZERO)) { + BigInteger za = Z.multiply(A).mod(p); + x1 = B.multiply(za.modInverse(p)).mod(p); + } else { + BigInteger negB_div_A = B.negate().multiply(A.modInverse(p)).mod(p); + BigInteger one_plus_tv1 = BigInteger.ONE.add(tv1).mod(p); + x1 = negB_div_A.multiply(one_plus_tv1).mod(p); + } + + BigInteger gx1 = x1.pow(3).add(A.multiply(x1)).add(B).mod(p); + BigInteger x2 = z_u2.multiply(x1).mod(p); + BigInteger gx2 = x2.pow(3).add(A.multiply(x2)).add(B).mod(p); + + BigInteger c1 = p.add(BigInteger.ONE).divide(BigInteger.valueOf(4)); + BigInteger root1 = gx1.modPow(c1, p); + boolean isSquare = root1.multiply(root1).mod(p).equals(gx1); + + BigInteger x, y; + if (isSquare) { + x = x1; + y = root1; + } else { + x = x2; + y = gx2.modPow(c1, p); + } + + if (sgn0(u) != sgn0(y)) { + y = y.negate().mod(p); + } + + return curve.createPoint(x, y); + } + + public static byte[] getHashToCurve(byte[] message, byte[] domain) throws GeneralSecurityException { + byte[] uniformBytes = expandMessageXmd(message, domain, 96); + byte[] u0Bytes = new byte[48]; + byte[] u1Bytes = new byte[48]; + System.arraycopy(uniformBytes, 0, u0Bytes, 0, 48); + System.arraycopy(uniformBytes, 48, u1Bytes, 0, 48); + + BigInteger u0 = new BigInteger(1, u0Bytes).mod(p); + BigInteger u1 = new BigInteger(1, u1Bytes).mod(p); + + X9ECParameters params = CustomNamedCurves.getByName(CURVE_NAME); + ECCurve curve = params.getCurve(); + + ECPoint q0 = mapToCurveSSWU(u0, curve); + ECPoint q1 = mapToCurveSSWU(u1, curve); + + ECPoint r = q0.add(q1).normalize(); + return r.getEncoded(true); + } + + public static byte[] blind(byte[] password, byte[] blindScalar) throws GeneralSecurityException { + byte[] hashedPoint = getHashToCurve(password, LOGIN_DOMAIN_SEPARATION_TAG.getBytes(UTF_8)); + + X9ECParameters params = CustomNamedCurves.getByName(CURVE_NAME); + ECCurve curve = params.getCurve(); + + ECPoint point = curve.decodePoint(hashedPoint); + BigInteger scalar = new BigInteger(1, blindScalar); + + return point.multiply(scalar).getEncoded(true); + } + + public static byte[] expand(byte[] keyMaterial, byte[] info, int size) + throws GeneralSecurityException { + return Hkdf.computeHkdf(HMAC_SHA256, keyMaterial, new byte[0], info, size); + } + + public static byte[] stretch(byte[] input) throws GeneralSecurityException { + byte[] salt = expand(input, "Stretch".getBytes(UTF_8), ARGON2_SALT_LENGTH); + Argon2Parameters params = + new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id) + .withSalt(salt) + .withParallelism(ARGON2_THREADS) + .withMemoryAsKB(ARGON2_MEMORY_LIMIT) + .withIterations(ARGON2_ITERATION_COUNT) + .build(); + Argon2BytesGenerator generator = new Argon2BytesGenerator(); + generator.init(params); + byte[] result = new byte[STRETCH_OUTPUT_LENGTH]; + generator.generateBytes(input, result); + return result; + } + + public static byte[] extract(byte[] inputKeyMaterial) throws GeneralSecurityException { + return expand(inputKeyMaterial, "Extract".getBytes(UTF_8), EXTRACT_OUTPUT_LENGTH); + } + + public static byte[] xorBytes(byte[] a, byte[] b) { + if (a.length != b.length) { + throw new IllegalArgumentException("Byte arrays must have same length"); + } + byte[] result = new byte[a.length]; + for (int i = 0; i < a.length; i++) { + result[i] = (byte) (a[i] ^ b[i]); + } + return result; + } + + public static byte[] concat(byte[]... arrays) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + for (byte[] array : arrays) { + out.write(array); + } + return out.toByteArray(); + } + + public static byte[] mac(byte[] key, byte[] data) throws GeneralSecurityException { + byte[] result = hmacSha256(key, data); + byte[] truncated = new byte[MAC_TAG_LENGTH]; + System.arraycopy(result, 0, truncated, 0, MAC_TAG_LENGTH); + return truncated; + } + + public static byte[] finalize(byte[] blind, byte[] evaluatedMessage) + throws GeneralSecurityException { + BigInteger blindBigInt = new BigInteger(1, blind); + X9ECParameters params = CustomNamedCurves.getByName(CURVE_NAME); + BigInteger order = params.getN(); + BigInteger inverseBlind = blindBigInt.modInverse(order); + + ECCurve curve = params.getCurve(); + ECPoint evaluatedPoint = curve.decodePoint(evaluatedMessage); + + return evaluatedPoint.multiply(inverseBlind).getEncoded(true); + } + + public static byte[] diffieHellman(byte[] privateKey, byte[] peerPublicKey) + throws GeneralSecurityException { + X9ECParameters params = CustomNamedCurves.getByName(CURVE_NAME); + ECCurve curve = params.getCurve(); + ECPoint peerPublicPoint = curve.decodePoint(peerPublicKey); + BigInteger priv = new BigInteger(1, privateKey); + return peerPublicPoint.multiply(priv).getEncoded(true); + } + + public static byte[] randomOracleSha256(byte[] x, BigInteger max) throws GeneralSecurityException { + int hashOutputLength = 256; + int outputBitLength = max.bitLength() + hashOutputLength; + int iterCount = (int) Math.ceil((double) outputBitLength / hashOutputLength); + if (iterCount * hashOutputLength > 130048) { + throw new GeneralSecurityException("the domain bit length must not be greater than 130048"); + } + int excessBitCount = (iterCount * hashOutputLength) - outputBitLength; + BigInteger hashOutput = BigInteger.ZERO; + + for (int i = 1; i <= iterCount; i++) { + hashOutput = hashOutput.shiftLeft(hashOutputLength); + byte[] iBytes = BigInteger.valueOf(i).toByteArray(); + // Remove leading zero byte if present from two's complement representation + if (iBytes.length > 1 && iBytes[0] == 0) { + byte[] tmp = new byte[iBytes.length - 1]; + System.arraycopy(iBytes, 1, tmp, 0, tmp.length); + iBytes = tmp; + } + + byte[] bignumBytes; + try { + bignumBytes = concat(iBytes, x); + } catch (IOException e) { + throw new GeneralSecurityException(e); + } + byte[] hashedString = sha256(bignumBytes); + + // Ensure hashedString is treated as a positive integer (prepend 0x00) + byte[] positiveHashedString = new byte[hashedString.length + 1]; + System.arraycopy(hashedString, 0, positiveHashedString, 1, hashedString.length); + BigInteger newBigNum = new BigInteger(positiveHashedString); + + hashOutput = hashOutput.add(newBigNum); + } + + hashOutput = hashOutput.shiftRight(excessBitCount); + hashOutput = hashOutput.mod(max); + + byte[] scalarBytes = new byte[hashOutputLength / 8]; + byte[] hashOutputBytes = hashOutput.toByteArray(); + + // Copy into 32 byte array + if (hashOutputBytes.length <= scalarBytes.length) { + System.arraycopy(hashOutputBytes, 0, scalarBytes, scalarBytes.length - hashOutputBytes.length, hashOutputBytes.length); + } else { + // If hashOutputBytes is 33 bytes due to sign bit + System.arraycopy(hashOutputBytes, hashOutputBytes.length - scalarBytes.length, scalarBytes, 0, scalarBytes.length); + } + return scalarBytes; + } + + public static byte[][] generateKeyPair(byte[] deriveInput) throws GeneralSecurityException { + X9ECParameters params = CustomNamedCurves.getByName(CURVE_NAME); + BigInteger order = params.getN(); + byte[] privateKeyBytes = randomOracleSha256(deriveInput, order); + BigInteger privateKey = new BigInteger(1, privateKeyBytes); + + if (privateKey.equals(BigInteger.ZERO)) { + privateKey = BigInteger.ONE; + privateKeyBytes = new byte[32]; + privateKeyBytes[31] = 1; + } + ECPoint publicKey = params.getG().multiply(privateKey); + return new byte[][] {privateKeyBytes, publicKey.getEncoded(true)}; + } +} \ No newline at end of file diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/ExperimentalHostHelper.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/ExperimentalHostHelper.java index f6387535e4d8..1fd182bbdefa 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/ExperimentalHostHelper.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/ExperimentalHostHelper.java @@ -25,6 +25,8 @@ public class ExperimentalHostHelper { private static final String USE_MTLS = "spanner.mtls"; private static final String CLIENT_CERT_PATH = "spanner.client_cert_path"; private static final String CLIENT_CERT_KEY_PATH = "spanner.client_cert_key_path"; + private static final String USERNAME = "spanner.username"; + private static final String PASSWORD_FILE = "spanner.password_file"; /** * Checks whether the emulator is being used. This is done by checking if the @@ -55,6 +57,11 @@ public static void setExperimentalHostSpannerOptions(SpannerOptions.Builder buil boolean usePlainText = Boolean.getBoolean(USE_PLAIN_TEXT); builder.setExperimentalHost(experimentalHost); builder.setBuiltInMetricsEnabled(false); + String username = System.getProperty(USERNAME,""); + String passwordFile = System.getProperty(PASSWORD_FILE,""); + if(!Strings.isNullOrEmpty(username)){ + builder.login(username,passwordFile,true); + } if (usePlainText) { builder.usePlainText(); } diff --git a/java-spanner/google-cloud-spanner/src/main/proto/login.proto b/java-spanner/google-cloud-spanner/src/main/proto/login.proto new file mode 100644 index 000000000000..cb283debd99d --- /dev/null +++ b/java-spanner/google-cloud-spanner/src/main/proto/login.proto @@ -0,0 +1,180 @@ +syntax = "proto3"; + +package google.spanner.omni.v1; + +import "google/protobuf/timestamp.proto"; + +option java_multiple_files = true; + +// AccessToken is returned by the LoginService after a successful login. +message AccessToken { + // The username of the logged in user. + string username = 1; + // The creation time of the access token. + google.protobuf.Timestamp creation_time = 2; + // The expiration time of the access token, this will be checked by the + // server. + google.protobuf.Timestamp expiration_time = 3; + // The signature of the access token, this will be verified by the server. + bytes signature = 4; + // The ID of the key used to sign/verify the access token. + int64 key_id = 5; + enum AccessTokenType { + ACCESS_TOKEN_TYPE_UNSPECIFIED = 0; + ACCESS_TOKEN_TYPE_API = 1; + ACCESS_TOKEN_TYPE_UI = 2; + } + // The type of the access token, this will be checked by the server. + AccessTokenType access_token_type = 6; +} + +// InitialOpaqueLoginRequest is used to start the OPAQUE handshake, it will +// contain the blinded message provided by the client. +message InitialOpaqueLoginRequest { + // The blinded message is used to fetch the user's credentials from the + // server. + bytes blinded_message = 1; + + // The AuthRequest fields as defined in rfc9807. + bytes client_nonce = 2; + bytes client_public_keyshare = 3; +} + +message FinalOpaqueLoginRequest { + // The client calculated MAC, this is used to authenticate the client. + bytes client_mac = 1; +} + +// The initial response from the server when using OPAQUE authentication. +// This is referred to as the `K2` message in rfc9807. +message InitialOpaqueLoginResponse { + // The fields that make up the `AuthResponse` message as defined in + // rfc9807. + bytes server_nonce = 1; + bytes server_public_keyshare = 2; + bytes server_mac = 3; + + // The fields that make up the `CredentialResponse` message as defined in + // rfc9807. + bytes evaluated_message = 4; + // The masking_nonce is used to protect the confidential masked response. + bytes masking_nonce = 5; + // The masked_response is the ciphertext containing the user's envelope. + bytes masked_response = 6; +} + +// OpaqueLoginRequest is used to authenticate the user using OPAQUE +// authentication. +message OpaqueLoginRequest { + oneof request { + InitialOpaqueLoginRequest initial_request = 1; + FinalOpaqueLoginRequest final_request = 2; + } +} + +// OpaqueLoginResponse is returned by the server when the user is using OPAQUE +// authentication. +message OpaqueLoginResponse { + message FinalResponse {} + oneof response { + InitialOpaqueLoginResponse initial_response = 1; + FinalResponse final_response = 2; + } +} + +// LoginRequest is used to authenticate the user, and if successful, return an +// access token. +message LoginRequest { + // The username of the user to log in. + string username = 1; + + oneof request { + // OPAQUE authentication as defined in rfc9807. + OpaqueLoginRequest opaque_request = 4; + } +} + +// LoginResponse contains the information the client needs to call the +// Spanner API. +message LoginResponse { + // The access token for the logged in user. This should be included in + // requests to the Spanner API. + AccessToken access_token = 1; + oneof response { + // The response from the server when the user is using OPAQUE + // authentication. + OpaqueLoginResponse opaque_response = 4; + } +} + +// OpaqueUpdatePasswordRequest is used to authenticate the user using OPAQUE +// authentication for password updates. +message OpaqueUpdatePasswordRequest { + message InitialRequest { + InitialOpaqueLoginRequest opaque_request = 1; + + // The blinded message based on the new password. + bytes new_password_blinded_message = 4; + } + message FinalRequest { + FinalOpaqueLoginRequest opaque_request = 1; + + // The new credential provided by the client. + bytes new_credential = 2; + } + oneof request { + InitialRequest initial_request = 1; + FinalRequest final_request = 2; + } +} + +// OpaqueUpdatePasswordResponse is returned by the server when the user is using +// OPAQUE authentication for password updates. +message OpaqueUpdatePasswordResponse { + message InitialResponse { + InitialOpaqueLoginResponse opaque_response = 1; + + // The fields used to create a new envelope for the user. + bytes server_public_key = 7; + bytes new_credential_evaluated_message = 8; + } + message FinalResponse {} + oneof response { + InitialResponse initial_response = 1; + FinalResponse final_response = 2; + } +} + +// UpdatePasswordRequest is used to update the password for a user. +message UpdatePasswordRequest { + // The username of the user to update the password for. + string username = 1; + + oneof request { + // The request to the server when the user is using OPAQUE authentication. + OpaqueUpdatePasswordRequest opaque_request = 4; + } +} + +// UpdatePasswordResponse is returned after a successful password update. +message UpdatePasswordResponse { + // The access token for the logged in user. This should be included in + // requests to the Spanner API. + AccessToken access_token = 1; + + oneof response { + OpaqueUpdatePasswordResponse opaque_response = 4; + } +} + +service LoginService { + // Performs the login for Spanner Omni. + rpc Login(stream LoginRequest) returns (stream LoginResponse) { + } + + // Updates the password for a user. + rpc UpdatePassword(stream UpdatePasswordRequest) + returns (stream UpdatePasswordResponse) { + + } +} \ No newline at end of file From a0e7c912f954923c53fa9875dc7b21638748f1fe Mon Sep 17 00:00:00 2001 From: sagnghos Date: Mon, 8 Jun 2026 18:53:00 +0000 Subject: [PATCH 02/15] use generated classes instead of proto --- .../google/cloud/spanner/SpannerOptions.java | 76 +- .../spanner/connection/ConnectionOptions.java | 22 + .../connection/ConnectionProperties.java | 14 + .../com/google/cloud/spanner/omni/Login.java | 11145 ++++++++++++++++ .../cloud/spanner/omni/LoginClient.java | 110 +- .../cloud/spanner/omni/LoginServiceGrpc.java | 345 + .../spanner/omni/SpannerOmniCredentials.java | 224 +- .../cloud/spanner/omni/opaque/OpaqueUtil.java | 98 +- .../testing/ExperimentalHostHelper.java | 18 +- .../src/main/proto/login.proto | 180 - 10 files changed, 11813 insertions(+), 419 deletions(-) create mode 100644 java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/Login.java create mode 100644 java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginServiceGrpc.java delete mode 100644 java-spanner/google-cloud-spanner/src/main/proto/login.proto diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java index 257dc1f263f5..7dd59cf882c4 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java @@ -91,7 +91,6 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.time.Duration; @@ -1818,45 +1817,6 @@ public Builder setExperimentalHost(String host) { return this; } - - /** - * Authenticates to Spanner Omni using the provided username and password file, and configures - * the resulting token for use in subsequent Spanner API calls. The endpoint must be set on the - * builder before calling this method. - * - * @param username The username for login. - * @param passwordFile The path to a file containing the password. - * @return this builder - */ - public Builder login(String username, String passwordFile) { - return login(username, passwordFile, true); - } - - /** - * Authenticates to Spanner Omni using the provided username and password file, and configures - * the resulting token for use in subsequent Spanner API calls. The endpoint must be set on the - * builder before calling this method. - * - * @param username The username for login. - * @param passwordFile The path to a file containing the password. - * @param backgroundRefresh Whether to proactively refresh the token in a background thread before it expires. If false, GAX still triggers a synchronous inline refresh upon UNAUTHENTICATED error. - * @return this builder - */ - public Builder login(String username, String passwordFile, boolean backgroundRefresh) { - try { - byte[] rawBytes = Files.readAllBytes(Paths.get(passwordFile)); - int len = rawBytes.length; - while (len > 0 && (rawBytes[len - 1] == '\n' || rawBytes[len - 1] == '\r')) { - len--; - } - byte[] passwordBytes = java.util.Arrays.copyOf(rawBytes, len); - return loginWithPasswordBytes(username, passwordBytes, backgroundRefresh); - } catch (IOException e) { - throw SpannerExceptionFactory.newSpannerException( - ErrorCode.NOT_FOUND, "Could not read password file: " + passwordFile, e); - } - } - /** * Authenticates to Spanner Omni using the provided username and password, and configures the * resulting token for use in subsequent Spanner API calls. The endpoint must be set on the @@ -1866,33 +1826,19 @@ public Builder login(String username, String passwordFile, boolean backgroundRef * @param password The password for login. * @return this builder */ - public Builder loginWithPassword(String username, String password) { - return loginWithPassword(username, password, true); - } - - /** - * Authenticates to Spanner Omni using the provided username and password, and configures the - * resulting token for use in subsequent Spanner API calls. The endpoint must be set on the - * builder before calling this method. - * - * @param username The username for login. - * @param password The password for login. - * @param backgroundRefresh Whether to proactively refresh the token in a background thread before it expires. If false, GAX still triggers a synchronous inline refresh upon UNAUTHENTICATED error. - * @return this builder - */ - public Builder loginWithPassword(String username, String password, boolean backgroundRefresh) { - return loginWithPasswordBytes(username, password.getBytes(StandardCharsets.UTF_8), backgroundRefresh); - } - - private Builder loginWithPasswordBytes(String username, byte[] password, boolean backgroundRefresh) { + public Builder login(String username, String password) { if (this.experimentalHost == null) { throw new IllegalStateException("Endpoint must be set before calling login."); } String target = this.experimentalHost.replaceFirst("^https?://", ""); - com.google.crypto.tink.util.SecretBytes secretBytes = com.google.crypto.tink.util.SecretBytes.copyFrom( - password, com.google.crypto.tink.InsecureSecretKeyAccess.get()); - java.util.Arrays.fill(password, (byte) 0); - super.setCredentials(new com.google.cloud.spanner.omni.SpannerOmniCredentials(username, secretBytes, target, backgroundRefresh)); + byte[] passwordBytes = password.getBytes(java.nio.charset.StandardCharsets.UTF_8); + com.google.crypto.tink.util.SecretBytes secretBytes = + com.google.crypto.tink.util.SecretBytes.copyFrom( + passwordBytes, com.google.crypto.tink.InsecureSecretKeyAccess.get()); + java.util.Arrays.fill(passwordBytes, (byte) 0); + super.setCredentials( + new com.google.cloud.spanner.omni.SpannerOmniCredentials( + username, secretBytes, target)); return this; } @@ -2215,6 +2161,10 @@ public SpannerOptions build() { } else if (experimentalHost != null && credentials == null) { credentials = environment.getDefaultExperimentalHostCredentials(); } + if (credentials instanceof com.google.cloud.spanner.omni.SpannerOmniCredentials) { + ((com.google.cloud.spanner.omni.SpannerOmniCredentials) credentials) + .initChannel(this.usePlainText, this.mTLSContext); + } if (this.numChannels == null) { this.numChannels = this.grpcGcpExtensionEnabled ? GRPC_GCP_ENABLED_DEFAULT_CHANNELS : DEFAULT_CHANNELS; diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java index 771cbfc24dad..dd5564eeb8ea 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java @@ -148,6 +148,8 @@ public class ConnectionOptions { new LocalConnectionChecker(); static final boolean DEFAULT_USE_PLAIN_TEXT = false; static final boolean DEFAULT_IS_EXPERIMENTAL_HOST = false; + static final String DEFAULT_USERNAME = ""; + static final String DEFAULT_PASSWORD = ""; static final boolean DEFAULT_AUTOCOMMIT = true; static final boolean DEFAULT_READONLY = false; static final boolean DEFAULT_RETRY_ABORTS_INTERNALLY = true; @@ -208,6 +210,12 @@ public class ConnectionOptions { /** Connect to a Experimental Host * */ static final String IS_EXPERIMENTAL_HOST_PROPERTY_NAME = "isExperimentalHost"; + /** Username for OPAQUE login */ + public static final String USERNAME_PROPERTY_NAME = "username"; + + /** Password for OPAQUE login */ + public static final String PASSWORD_PROPERTY_NAME = "password"; + /** Client certificate path to establish mTLS */ static final String CLIENT_CERTIFICATE_PROPERTY_NAME = "clientCertificate"; @@ -733,6 +741,8 @@ private ConnectionOptions(Builder builder) { System.getenv()); GoogleCredentials defaultExperimentalHostCredentials = SpannerOptions.getDefaultExperimentalCredentialsFromSysEnv(); + String username = getInitialConnectionPropertyValue(ConnectionProperties.USERNAME); + String password = getInitialConnectionPropertyValue(ConnectionProperties.PASSWORD); // Using credentials on a plain text connection is not allowed, so if the user has not specified // any credentials and is using a plain text connection, we should not try to get the // credentials from the environment, but default to NoCredentials. @@ -747,6 +757,18 @@ && getInitialConnectionPropertyValue(OAUTH_TOKEN) == null this.credentials = new GoogleCredentials( new AccessToken(getInitialConnectionPropertyValue(OAUTH_TOKEN), null)); + } else if ((isExperimentalHostPattern || isExperimentalHost()) + && !com.google.common.base.Strings.isNullOrEmpty(username) + && !com.google.common.base.Strings.isNullOrEmpty(password)) { + String target = this.host.replaceFirst("^https?://", ""); + byte[] passwordBytes = password.getBytes(java.nio.charset.StandardCharsets.UTF_8); + com.google.crypto.tink.util.SecretBytes secretBytes = + com.google.crypto.tink.util.SecretBytes.copyFrom( + passwordBytes, com.google.crypto.tink.InsecureSecretKeyAccess.get()); + java.util.Arrays.fill(passwordBytes, (byte) 0); + this.credentials = + new com.google.cloud.spanner.omni.SpannerOmniCredentials( + username, secretBytes, target); } else if ((isExperimentalHostPattern || isExperimentalHost()) && defaultExperimentalHostCredentials != null) { this.credentials = defaultExperimentalHostCredentials; diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionProperties.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionProperties.java index 6d59cf1db3bb..186d6d442ad8 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionProperties.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionProperties.java @@ -250,6 +250,20 @@ public class ConnectionProperties { BOOLEANS, BooleanConverter.INSTANCE, Context.STARTUP); + static final ConnectionProperty USERNAME = + create( + ConnectionOptions.USERNAME_PROPERTY_NAME, + "The username to use for OPAQUE login.", + ConnectionOptions.DEFAULT_USERNAME, + StringValueConverter.INSTANCE, + Context.STARTUP); + static final ConnectionProperty PASSWORD = + create( + ConnectionOptions.PASSWORD_PROPERTY_NAME, + "The password to use for OPAQUE login.", + ConnectionOptions.DEFAULT_PASSWORD, + StringValueConverter.INSTANCE, + Context.STARTUP); static final ConnectionProperty CLIENT_CERTIFICATE = create( CLIENT_CERTIFICATE_PROPERTY_NAME, diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/Login.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/Login.java new file mode 100644 index 000000000000..205ea0b06f32 --- /dev/null +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/Login.java @@ -0,0 +1,11145 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: login.proto +// Protobuf Java Version: 4.33.2 + +package com.google.cloud.spanner.omni; + +@com.google.protobuf.Generated +public final class Login extends com.google.protobuf.GeneratedFile { + private Login() {} + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 2, + /* suffix= */ "", + "Login"); + } + + public static void registerAllExtensions(com.google.protobuf.ExtensionRegistryLite registry) {} + + public static void registerAllExtensions(com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions((com.google.protobuf.ExtensionRegistryLite) registry); + } + + /** Protobuf enum {@code google.spanner.auth.v1.AuthenticationMethod} */ + public enum AuthenticationMethod implements com.google.protobuf.ProtocolMessageEnum { + /** AUTHENTICATION_METHOD_UNSPECIFIED = 0; */ + AUTHENTICATION_METHOD_UNSPECIFIED(0), + /** AUTHENTICATION_METHOD_OPAQUE = 2; */ + AUTHENTICATION_METHOD_OPAQUE(2), + UNRECOGNIZED(-1), + ; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 2, + /* suffix= */ "", + "AuthenticationMethod"); + } + + /** AUTHENTICATION_METHOD_UNSPECIFIED = 0; */ + public static final int AUTHENTICATION_METHOD_UNSPECIFIED_VALUE = 0; + + /** AUTHENTICATION_METHOD_OPAQUE = 2; */ + public static final int AUTHENTICATION_METHOD_OPAQUE_VALUE = 2; + + public final int getNumber() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalArgumentException( + "Can't get the number of an unknown enum value."); + } + return value; + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static AuthenticationMethod valueOf(int value) { + return forNumber(value); + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + */ + public static AuthenticationMethod forNumber(int value) { + switch (value) { + case 0: + return AUTHENTICATION_METHOD_UNSPECIFIED; + case 2: + return AUTHENTICATION_METHOD_OPAQUE; + default: + return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + + private static final com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public AuthenticationMethod findValueByNumber(int number) { + return AuthenticationMethod.forNumber(number); + } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalStateException( + "Can't get the descriptor of an unrecognized enum value."); + } + return getDescriptor().getValues().get(ordinal()); + } + + public final com.google.protobuf.Descriptors.EnumDescriptor getDescriptorForType() { + return getDescriptor(); + } + + public static com.google.protobuf.Descriptors.EnumDescriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login.getDescriptor().getEnumTypes().get(0); + } + + private static final AuthenticationMethod[] VALUES = values(); + + public static AuthenticationMethod valueOf( + com.google.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new java.lang.IllegalArgumentException("EnumValueDescriptor is not for this type."); + } + if (desc.getIndex() == -1) { + return UNRECOGNIZED; + } + return VALUES[desc.getIndex()]; + } + + private final int value; + + private AuthenticationMethod(int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:google.spanner.auth.v1.AuthenticationMethod) + } + + public interface AuthenticationHandshakeRequestOrBuilder + extends + // @@protoc_insertion_point(interface_extends:google.spanner.auth.v1.AuthenticationHandshakeRequest) + com.google.protobuf.MessageOrBuilder {} + + /** Protobuf type {@code google.spanner.auth.v1.AuthenticationHandshakeRequest} */ + public static final class AuthenticationHandshakeRequest + extends com.google.protobuf.GeneratedMessage + implements + // @@protoc_insertion_point(message_implements:google.spanner.auth.v1.AuthenticationHandshakeRequest) + AuthenticationHandshakeRequestOrBuilder { + private static final long serialVersionUID = 0L; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 2, + /* suffix= */ "", + "AuthenticationHandshakeRequest"); + } + + // Use AuthenticationHandshakeRequest.newBuilder() to construct. + private AuthenticationHandshakeRequest( + com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + + private AuthenticationHandshakeRequest() {} + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_AuthenticationHandshakeRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_AuthenticationHandshakeRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest.class, + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest.Builder.class); + } + + private byte memoizedIsInitialized = -1; + + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest)) { + return super.equals(obj); + } + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest other = + (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest) obj; + + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest parseFrom( + java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest parseFrom( + java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest parseFrom( + byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest parseFrom( + byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest parseFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest parseFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest + parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest + parseDelimitedFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest parseFrom( + com.google.protobuf.CodedInputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder( + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** Protobuf type {@code google.spanner.auth.v1.AuthenticationHandshakeRequest} */ + public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder + implements + // @@protoc_insertion_point(builder_implements:google.spanner.auth.v1.AuthenticationHandshakeRequest) + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_AuthenticationHandshakeRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_AuthenticationHandshakeRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest.class, + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest.Builder.class); + } + + // Construct using + // com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest.newBuilder() + private Builder() {} + + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + } + + @java.lang.Override + public Builder clear() { + super.clear(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_AuthenticationHandshakeRequest_descriptor; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest + getDefaultInstanceForType() { + return com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest + .getDefaultInstance(); + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest build() { + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest buildPartial() { + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest result = + new com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest(this); + onBuilt(); + return result; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest) { + return mergeFrom( + (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom( + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest other) { + if (other + == com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest + .getDefaultInstance()) return this; + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: + { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + // @@protoc_insertion_point(builder_scope:google.spanner.auth.v1.AuthenticationHandshakeRequest) + } + + // @@protoc_insertion_point(class_scope:google.spanner.auth.v1.AuthenticationHandshakeRequest) + private static final com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest + DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest(); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest + getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AuthenticationHandshakeRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException() + .setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest + getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + } + + public interface AuthenticationHandshakeResponseOrBuilder + extends + // @@protoc_insertion_point(interface_extends:google.spanner.auth.v1.AuthenticationHandshakeResponse) + com.google.protobuf.MessageOrBuilder { + + /** + * .google.spanner.auth.v1.AuthenticationMethod authentication_method = 1; + * + * @return The enum numeric value on the wire for authenticationMethod. + */ + int getAuthenticationMethodValue(); + + /** + * .google.spanner.auth.v1.AuthenticationMethod authentication_method = 1; + * + * @return The authenticationMethod. + */ + com.google.cloud.spanner.omni.Login.AuthenticationMethod getAuthenticationMethod(); + } + + /** Protobuf type {@code google.spanner.auth.v1.AuthenticationHandshakeResponse} */ + public static final class AuthenticationHandshakeResponse + extends com.google.protobuf.GeneratedMessage + implements + // @@protoc_insertion_point(message_implements:google.spanner.auth.v1.AuthenticationHandshakeResponse) + AuthenticationHandshakeResponseOrBuilder { + private static final long serialVersionUID = 0L; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 2, + /* suffix= */ "", + "AuthenticationHandshakeResponse"); + } + + // Use AuthenticationHandshakeResponse.newBuilder() to construct. + private AuthenticationHandshakeResponse( + com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + + private AuthenticationHandshakeResponse() { + authenticationMethod_ = 0; + } + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_AuthenticationHandshakeResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_AuthenticationHandshakeResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse.class, + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse.Builder.class); + } + + public static final int AUTHENTICATION_METHOD_FIELD_NUMBER = 1; + private int authenticationMethod_ = 0; + + /** + * .google.spanner.auth.v1.AuthenticationMethod authentication_method = 1; + * + * @return The enum numeric value on the wire for authenticationMethod. + */ + @java.lang.Override + public int getAuthenticationMethodValue() { + return authenticationMethod_; + } + + /** + * .google.spanner.auth.v1.AuthenticationMethod authentication_method = 1; + * + * @return The authenticationMethod. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AuthenticationMethod getAuthenticationMethod() { + com.google.cloud.spanner.omni.Login.AuthenticationMethod result = + com.google.cloud.spanner.omni.Login.AuthenticationMethod.forNumber(authenticationMethod_); + return result == null + ? com.google.cloud.spanner.omni.Login.AuthenticationMethod.UNRECOGNIZED + : result; + } + + private byte memoizedIsInitialized = -1; + + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { + if (authenticationMethod_ + != com.google.cloud.spanner.omni.Login.AuthenticationMethod + .AUTHENTICATION_METHOD_UNSPECIFIED + .getNumber()) { + output.writeEnum(1, authenticationMethod_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (authenticationMethod_ + != com.google.cloud.spanner.omni.Login.AuthenticationMethod + .AUTHENTICATION_METHOD_UNSPECIFIED + .getNumber()) { + size += com.google.protobuf.CodedOutputStream.computeEnumSize(1, authenticationMethod_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse)) { + return super.equals(obj); + } + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse other = + (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse) obj; + + if (authenticationMethod_ != other.authenticationMethod_) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + AUTHENTICATION_METHOD_FIELD_NUMBER; + hash = (53 * hash) + authenticationMethod_; + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse parseFrom( + java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse parseFrom( + java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse parseFrom( + byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse parseFrom( + byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse parseFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse parseFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse + parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse + parseDelimitedFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse parseFrom( + com.google.protobuf.CodedInputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder( + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** Protobuf type {@code google.spanner.auth.v1.AuthenticationHandshakeResponse} */ + public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder + implements + // @@protoc_insertion_point(builder_implements:google.spanner.auth.v1.AuthenticationHandshakeResponse) + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponseOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_AuthenticationHandshakeResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_AuthenticationHandshakeResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse.class, + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse.Builder.class); + } + + // Construct using + // com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse.newBuilder() + private Builder() {} + + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + } + + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + authenticationMethod_ = 0; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_AuthenticationHandshakeResponse_descriptor; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse + getDefaultInstanceForType() { + return com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse + .getDefaultInstance(); + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse build() { + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse buildPartial() { + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse result = + new com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse(this); + if (bitField0_ != 0) { + buildPartial0(result); + } + onBuilt(); + return result; + } + + private void buildPartial0( + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.authenticationMethod_ = authenticationMethod_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse) { + return mergeFrom( + (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom( + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse other) { + if (other + == com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse + .getDefaultInstance()) return this; + if (other.authenticationMethod_ != 0) { + setAuthenticationMethodValue(other.getAuthenticationMethodValue()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 8: + { + authenticationMethod_ = input.readEnum(); + bitField0_ |= 0x00000001; + break; + } // case 8 + default: + { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + private int bitField0_; + + private int authenticationMethod_ = 0; + + /** + * .google.spanner.auth.v1.AuthenticationMethod authentication_method = 1; + * + * @return The enum numeric value on the wire for authenticationMethod. + */ + @java.lang.Override + public int getAuthenticationMethodValue() { + return authenticationMethod_; + } + + /** + * .google.spanner.auth.v1.AuthenticationMethod authentication_method = 1; + * + * @param value The enum numeric value on the wire for authenticationMethod to set. + * @return This builder for chaining. + */ + public Builder setAuthenticationMethodValue(int value) { + authenticationMethod_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + /** + * .google.spanner.auth.v1.AuthenticationMethod authentication_method = 1; + * + * @return The authenticationMethod. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AuthenticationMethod getAuthenticationMethod() { + com.google.cloud.spanner.omni.Login.AuthenticationMethod result = + com.google.cloud.spanner.omni.Login.AuthenticationMethod.forNumber( + authenticationMethod_); + return result == null + ? com.google.cloud.spanner.omni.Login.AuthenticationMethod.UNRECOGNIZED + : result; + } + + /** + * .google.spanner.auth.v1.AuthenticationMethod authentication_method = 1; + * + * @param value The authenticationMethod to set. + * @return This builder for chaining. + */ + public Builder setAuthenticationMethod( + com.google.cloud.spanner.omni.Login.AuthenticationMethod value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + authenticationMethod_ = value.getNumber(); + onChanged(); + return this; + } + + /** + * .google.spanner.auth.v1.AuthenticationMethod authentication_method = 1; + * + * @return This builder for chaining. + */ + public Builder clearAuthenticationMethod() { + bitField0_ = (bitField0_ & ~0x00000001); + authenticationMethod_ = 0; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:google.spanner.auth.v1.AuthenticationHandshakeResponse) + } + + // @@protoc_insertion_point(class_scope:google.spanner.auth.v1.AuthenticationHandshakeResponse) + private static final com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse + DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse(); + } + + public static com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse + getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AuthenticationHandshakeResponse parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException() + .setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse + getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + } + + public interface AccessTokenOrBuilder + extends + // @@protoc_insertion_point(interface_extends:google.spanner.auth.v1.AccessToken) + com.google.protobuf.MessageOrBuilder { + + /** + * + * + *
+     * The username of the logged in user.
+     * 
+ * + * string username = 1; + * + * @return The username. + */ + java.lang.String getUsername(); + + /** + * + * + *
+     * The username of the logged in user.
+     * 
+ * + * string username = 1; + * + * @return The bytes for username. + */ + com.google.protobuf.ByteString getUsernameBytes(); + + /** + * + * + *
+     * The creation time of the access token.
+     * 
+ * + * .google.protobuf.Timestamp creation_time = 2; + * + * @return Whether the creationTime field is set. + */ + boolean hasCreationTime(); + + /** + * + * + *
+     * The creation time of the access token.
+     * 
+ * + * .google.protobuf.Timestamp creation_time = 2; + * + * @return The creationTime. + */ + com.google.protobuf.Timestamp getCreationTime(); + + /** + * + * + *
+     * The creation time of the access token.
+     * 
+ * + * .google.protobuf.Timestamp creation_time = 2; + */ + com.google.protobuf.TimestampOrBuilder getCreationTimeOrBuilder(); + + /** + * + * + *
+     * The expiration time of the access token, this will be checked by the
+     * server.
+     * 
+ * + * .google.protobuf.Timestamp expiration_time = 3; + * + * @return Whether the expirationTime field is set. + */ + boolean hasExpirationTime(); + + /** + * + * + *
+     * The expiration time of the access token, this will be checked by the
+     * server.
+     * 
+ * + * .google.protobuf.Timestamp expiration_time = 3; + * + * @return The expirationTime. + */ + com.google.protobuf.Timestamp getExpirationTime(); + + /** + * + * + *
+     * The expiration time of the access token, this will be checked by the
+     * server.
+     * 
+ * + * .google.protobuf.Timestamp expiration_time = 3; + */ + com.google.protobuf.TimestampOrBuilder getExpirationTimeOrBuilder(); + + /** + * + * + *
+     * The signature of the access token, this will be verified by the server.
+     * 
+ * + * bytes signature = 4; + * + * @return The signature. + */ + com.google.protobuf.ByteString getSignature(); + + /** + * + * + *
+     * The ID of the key used to sign/verify the access token.
+     * 
+ * + * int64 key_id = 5; + * + * @return The keyId. + */ + long getKeyId(); + + /** + * + * + *
+     * The type of the access token, this will be checked by the server.
+     * 
+ * + * .google.spanner.auth.v1.AccessToken.AccessTokenType access_token_type = 6; + * + * @return The enum numeric value on the wire for accessTokenType. + */ + int getAccessTokenTypeValue(); + + /** + * + * + *
+     * The type of the access token, this will be checked by the server.
+     * 
+ * + * .google.spanner.auth.v1.AccessToken.AccessTokenType access_token_type = 6; + * + * @return The accessTokenType. + */ + com.google.cloud.spanner.omni.Login.AccessToken.AccessTokenType getAccessTokenType(); + } + + /** + * + * + *
+   * AccessToken is returned by the LoginService after a successful login.
+   * 
+ * + * Protobuf type {@code google.spanner.auth.v1.AccessToken} + */ + public static final class AccessToken extends com.google.protobuf.GeneratedMessage + implements + // @@protoc_insertion_point(message_implements:google.spanner.auth.v1.AccessToken) + AccessTokenOrBuilder { + private static final long serialVersionUID = 0L; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 2, + /* suffix= */ "", + "AccessToken"); + } + + // Use AccessToken.newBuilder() to construct. + private AccessToken(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + + private AccessToken() { + username_ = ""; + signature_ = com.google.protobuf.ByteString.EMPTY; + accessTokenType_ = 0; + } + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_AccessToken_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_AccessToken_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.AccessToken.class, + com.google.cloud.spanner.omni.Login.AccessToken.Builder.class); + } + + /** Protobuf enum {@code google.spanner.auth.v1.AccessToken.AccessTokenType} */ + public enum AccessTokenType implements com.google.protobuf.ProtocolMessageEnum { + /** + * + * + *
+       * The access token type is unspecified.
+       * 
+ * + * ACCESS_TOKEN_TYPE_UNSPECIFIED = 0; + */ + ACCESS_TOKEN_TYPE_UNSPECIFIED(0), + /** + * + * + *
+       * The access token is used for API calls.
+       * 
+ * + * ACCESS_TOKEN_TYPE_API = 1; + */ + ACCESS_TOKEN_TYPE_API(1), + /** + * + * + *
+       * The access token is used for UI calls.
+       * 
+ * + * ACCESS_TOKEN_TYPE_UI = 2; + */ + ACCESS_TOKEN_TYPE_UI(2), + UNRECOGNIZED(-1), + ; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 2, + /* suffix= */ "", + "AccessTokenType"); + } + + /** + * + * + *
+       * The access token type is unspecified.
+       * 
+ * + * ACCESS_TOKEN_TYPE_UNSPECIFIED = 0; + */ + public static final int ACCESS_TOKEN_TYPE_UNSPECIFIED_VALUE = 0; + + /** + * + * + *
+       * The access token is used for API calls.
+       * 
+ * + * ACCESS_TOKEN_TYPE_API = 1; + */ + public static final int ACCESS_TOKEN_TYPE_API_VALUE = 1; + + /** + * + * + *
+       * The access token is used for UI calls.
+       * 
+ * + * ACCESS_TOKEN_TYPE_UI = 2; + */ + public static final int ACCESS_TOKEN_TYPE_UI_VALUE = 2; + + public final int getNumber() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalArgumentException( + "Can't get the number of an unknown enum value."); + } + return value; + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static AccessTokenType valueOf(int value) { + return forNumber(value); + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + */ + public static AccessTokenType forNumber(int value) { + switch (value) { + case 0: + return ACCESS_TOKEN_TYPE_UNSPECIFIED; + case 1: + return ACCESS_TOKEN_TYPE_API; + case 2: + return ACCESS_TOKEN_TYPE_UI; + default: + return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + + private static final com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public AccessTokenType findValueByNumber(int number) { + return AccessTokenType.forNumber(number); + } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalStateException( + "Can't get the descriptor of an unrecognized enum value."); + } + return getDescriptor().getValues().get(ordinal()); + } + + public final com.google.protobuf.Descriptors.EnumDescriptor getDescriptorForType() { + return getDescriptor(); + } + + public static com.google.protobuf.Descriptors.EnumDescriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login.AccessToken.getDescriptor() + .getEnumTypes() + .get(0); + } + + private static final AccessTokenType[] VALUES = values(); + + public static AccessTokenType valueOf( + com.google.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new java.lang.IllegalArgumentException("EnumValueDescriptor is not for this type."); + } + if (desc.getIndex() == -1) { + return UNRECOGNIZED; + } + return VALUES[desc.getIndex()]; + } + + private final int value; + + private AccessTokenType(int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:google.spanner.auth.v1.AccessToken.AccessTokenType) + } + + private int bitField0_; + public static final int USERNAME_FIELD_NUMBER = 1; + + @SuppressWarnings("serial") + private volatile java.lang.Object username_ = ""; + + /** + * + * + *
+     * The username of the logged in user.
+     * 
+ * + * string username = 1; + * + * @return The username. + */ + @java.lang.Override + public java.lang.String getUsername() { + java.lang.Object ref = username_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + username_ = s; + return s; + } + } + + /** + * + * + *
+     * The username of the logged in user.
+     * 
+ * + * string username = 1; + * + * @return The bytes for username. + */ + @java.lang.Override + public com.google.protobuf.ByteString getUsernameBytes() { + java.lang.Object ref = username_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref); + username_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CREATION_TIME_FIELD_NUMBER = 2; + private com.google.protobuf.Timestamp creationTime_; + + /** + * + * + *
+     * The creation time of the access token.
+     * 
+ * + * .google.protobuf.Timestamp creation_time = 2; + * + * @return Whether the creationTime field is set. + */ + @java.lang.Override + public boolean hasCreationTime() { + return ((bitField0_ & 0x00000001) != 0); + } + + /** + * + * + *
+     * The creation time of the access token.
+     * 
+ * + * .google.protobuf.Timestamp creation_time = 2; + * + * @return The creationTime. + */ + @java.lang.Override + public com.google.protobuf.Timestamp getCreationTime() { + return creationTime_ == null + ? com.google.protobuf.Timestamp.getDefaultInstance() + : creationTime_; + } + + /** + * + * + *
+     * The creation time of the access token.
+     * 
+ * + * .google.protobuf.Timestamp creation_time = 2; + */ + @java.lang.Override + public com.google.protobuf.TimestampOrBuilder getCreationTimeOrBuilder() { + return creationTime_ == null + ? com.google.protobuf.Timestamp.getDefaultInstance() + : creationTime_; + } + + public static final int EXPIRATION_TIME_FIELD_NUMBER = 3; + private com.google.protobuf.Timestamp expirationTime_; + + /** + * + * + *
+     * The expiration time of the access token, this will be checked by the
+     * server.
+     * 
+ * + * .google.protobuf.Timestamp expiration_time = 3; + * + * @return Whether the expirationTime field is set. + */ + @java.lang.Override + public boolean hasExpirationTime() { + return ((bitField0_ & 0x00000002) != 0); + } + + /** + * + * + *
+     * The expiration time of the access token, this will be checked by the
+     * server.
+     * 
+ * + * .google.protobuf.Timestamp expiration_time = 3; + * + * @return The expirationTime. + */ + @java.lang.Override + public com.google.protobuf.Timestamp getExpirationTime() { + return expirationTime_ == null + ? com.google.protobuf.Timestamp.getDefaultInstance() + : expirationTime_; + } + + /** + * + * + *
+     * The expiration time of the access token, this will be checked by the
+     * server.
+     * 
+ * + * .google.protobuf.Timestamp expiration_time = 3; + */ + @java.lang.Override + public com.google.protobuf.TimestampOrBuilder getExpirationTimeOrBuilder() { + return expirationTime_ == null + ? com.google.protobuf.Timestamp.getDefaultInstance() + : expirationTime_; + } + + public static final int SIGNATURE_FIELD_NUMBER = 4; + private com.google.protobuf.ByteString signature_ = com.google.protobuf.ByteString.EMPTY; + + /** + * + * + *
+     * The signature of the access token, this will be verified by the server.
+     * 
+ * + * bytes signature = 4; + * + * @return The signature. + */ + @java.lang.Override + public com.google.protobuf.ByteString getSignature() { + return signature_; + } + + public static final int KEY_ID_FIELD_NUMBER = 5; + private long keyId_ = 0L; + + /** + * + * + *
+     * The ID of the key used to sign/verify the access token.
+     * 
+ * + * int64 key_id = 5; + * + * @return The keyId. + */ + @java.lang.Override + public long getKeyId() { + return keyId_; + } + + public static final int ACCESS_TOKEN_TYPE_FIELD_NUMBER = 6; + private int accessTokenType_ = 0; + + /** + * + * + *
+     * The type of the access token, this will be checked by the server.
+     * 
+ * + * .google.spanner.auth.v1.AccessToken.AccessTokenType access_token_type = 6; + * + * @return The enum numeric value on the wire for accessTokenType. + */ + @java.lang.Override + public int getAccessTokenTypeValue() { + return accessTokenType_; + } + + /** + * + * + *
+     * The type of the access token, this will be checked by the server.
+     * 
+ * + * .google.spanner.auth.v1.AccessToken.AccessTokenType access_token_type = 6; + * + * @return The accessTokenType. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AccessToken.AccessTokenType getAccessTokenType() { + com.google.cloud.spanner.omni.Login.AccessToken.AccessTokenType result = + com.google.cloud.spanner.omni.Login.AccessToken.AccessTokenType.forNumber( + accessTokenType_); + return result == null + ? com.google.cloud.spanner.omni.Login.AccessToken.AccessTokenType.UNRECOGNIZED + : result; + } + + private byte memoizedIsInitialized = -1; + + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(username_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, username_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(2, getCreationTime()); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeMessage(3, getExpirationTime()); + } + if (!signature_.isEmpty()) { + output.writeBytes(4, signature_); + } + if (keyId_ != 0L) { + output.writeInt64(5, keyId_); + } + if (accessTokenType_ + != com.google.cloud.spanner.omni.Login.AccessToken.AccessTokenType + .ACCESS_TOKEN_TYPE_UNSPECIFIED + .getNumber()) { + output.writeEnum(6, accessTokenType_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(username_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, username_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream.computeMessageSize(2, getCreationTime()); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream.computeMessageSize(3, getExpirationTime()); + } + if (!signature_.isEmpty()) { + size += com.google.protobuf.CodedOutputStream.computeBytesSize(4, signature_); + } + if (keyId_ != 0L) { + size += com.google.protobuf.CodedOutputStream.computeInt64Size(5, keyId_); + } + if (accessTokenType_ + != com.google.cloud.spanner.omni.Login.AccessToken.AccessTokenType + .ACCESS_TOKEN_TYPE_UNSPECIFIED + .getNumber()) { + size += com.google.protobuf.CodedOutputStream.computeEnumSize(6, accessTokenType_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.google.cloud.spanner.omni.Login.AccessToken)) { + return super.equals(obj); + } + com.google.cloud.spanner.omni.Login.AccessToken other = + (com.google.cloud.spanner.omni.Login.AccessToken) obj; + + if (!getUsername().equals(other.getUsername())) return false; + if (hasCreationTime() != other.hasCreationTime()) return false; + if (hasCreationTime()) { + if (!getCreationTime().equals(other.getCreationTime())) return false; + } + if (hasExpirationTime() != other.hasExpirationTime()) return false; + if (hasExpirationTime()) { + if (!getExpirationTime().equals(other.getExpirationTime())) return false; + } + if (!getSignature().equals(other.getSignature())) return false; + if (getKeyId() != other.getKeyId()) return false; + if (accessTokenType_ != other.accessTokenType_) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + USERNAME_FIELD_NUMBER; + hash = (53 * hash) + getUsername().hashCode(); + if (hasCreationTime()) { + hash = (37 * hash) + CREATION_TIME_FIELD_NUMBER; + hash = (53 * hash) + getCreationTime().hashCode(); + } + if (hasExpirationTime()) { + hash = (37 * hash) + EXPIRATION_TIME_FIELD_NUMBER; + hash = (53 * hash) + getExpirationTime().hashCode(); + } + hash = (37 * hash) + SIGNATURE_FIELD_NUMBER; + hash = (53 * hash) + getSignature().hashCode(); + hash = (37 * hash) + KEY_ID_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashLong(getKeyId()); + hash = (37 * hash) + ACCESS_TOKEN_TYPE_FIELD_NUMBER; + hash = (53 * hash) + accessTokenType_; + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.google.cloud.spanner.omni.Login.AccessToken parseFrom( + java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.AccessToken parseFrom( + java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.AccessToken parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.AccessToken parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.AccessToken parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.AccessToken parseFrom( + byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.AccessToken parseFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.AccessToken parseFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.AccessToken parseDelimitedFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.AccessToken parseDelimitedFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.AccessToken parseFrom( + com.google.protobuf.CodedInputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.AccessToken parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(com.google.cloud.spanner.omni.Login.AccessToken prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** + * + * + *
+     * AccessToken is returned by the LoginService after a successful login.
+     * 
+ * + * Protobuf type {@code google.spanner.auth.v1.AccessToken} + */ + public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder + implements + // @@protoc_insertion_point(builder_implements:google.spanner.auth.v1.AccessToken) + com.google.cloud.spanner.omni.Login.AccessTokenOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_AccessToken_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_AccessToken_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.AccessToken.class, + com.google.cloud.spanner.omni.Login.AccessToken.Builder.class); + } + + // Construct using com.google.cloud.spanner.omni.Login.AccessToken.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + internalGetCreationTimeFieldBuilder(); + internalGetExpirationTimeFieldBuilder(); + } + } + + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + username_ = ""; + creationTime_ = null; + if (creationTimeBuilder_ != null) { + creationTimeBuilder_.dispose(); + creationTimeBuilder_ = null; + } + expirationTime_ = null; + if (expirationTimeBuilder_ != null) { + expirationTimeBuilder_.dispose(); + expirationTimeBuilder_ = null; + } + signature_ = com.google.protobuf.ByteString.EMPTY; + keyId_ = 0L; + accessTokenType_ = 0; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_AccessToken_descriptor; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AccessToken getDefaultInstanceForType() { + return com.google.cloud.spanner.omni.Login.AccessToken.getDefaultInstance(); + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AccessToken build() { + com.google.cloud.spanner.omni.Login.AccessToken result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AccessToken buildPartial() { + com.google.cloud.spanner.omni.Login.AccessToken result = + new com.google.cloud.spanner.omni.Login.AccessToken(this); + if (bitField0_ != 0) { + buildPartial0(result); + } + onBuilt(); + return result; + } + + private void buildPartial0(com.google.cloud.spanner.omni.Login.AccessToken result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.username_ = username_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000002) != 0)) { + result.creationTime_ = + creationTimeBuilder_ == null ? creationTime_ : creationTimeBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.expirationTime_ = + expirationTimeBuilder_ == null ? expirationTime_ : expirationTimeBuilder_.build(); + to_bitField0_ |= 0x00000002; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.signature_ = signature_; + } + if (((from_bitField0_ & 0x00000010) != 0)) { + result.keyId_ = keyId_; + } + if (((from_bitField0_ & 0x00000020) != 0)) { + result.accessTokenType_ = accessTokenType_; + } + result.bitField0_ |= to_bitField0_; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.google.cloud.spanner.omni.Login.AccessToken) { + return mergeFrom((com.google.cloud.spanner.omni.Login.AccessToken) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(com.google.cloud.spanner.omni.Login.AccessToken other) { + if (other == com.google.cloud.spanner.omni.Login.AccessToken.getDefaultInstance()) + return this; + if (!other.getUsername().isEmpty()) { + username_ = other.username_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (other.hasCreationTime()) { + mergeCreationTime(other.getCreationTime()); + } + if (other.hasExpirationTime()) { + mergeExpirationTime(other.getExpirationTime()); + } + if (!other.getSignature().isEmpty()) { + setSignature(other.getSignature()); + } + if (other.getKeyId() != 0L) { + setKeyId(other.getKeyId()); + } + if (other.accessTokenType_ != 0) { + setAccessTokenTypeValue(other.getAccessTokenTypeValue()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: + { + username_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: + { + input.readMessage( + internalGetCreationTimeFieldBuilder().getBuilder(), extensionRegistry); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: + { + input.readMessage( + internalGetExpirationTimeFieldBuilder().getBuilder(), extensionRegistry); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: + { + signature_ = input.readBytes(); + bitField0_ |= 0x00000008; + break; + } // case 34 + case 40: + { + keyId_ = input.readInt64(); + bitField0_ |= 0x00000010; + break; + } // case 40 + case 48: + { + accessTokenType_ = input.readEnum(); + bitField0_ |= 0x00000020; + break; + } // case 48 + default: + { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + private int bitField0_; + + private java.lang.Object username_ = ""; + + /** + * + * + *
+       * The username of the logged in user.
+       * 
+ * + * string username = 1; + * + * @return The username. + */ + public java.lang.String getUsername() { + java.lang.Object ref = username_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + username_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + + /** + * + * + *
+       * The username of the logged in user.
+       * 
+ * + * string username = 1; + * + * @return The bytes for username. + */ + public com.google.protobuf.ByteString getUsernameBytes() { + java.lang.Object ref = username_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref); + username_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + * + * + *
+       * The username of the logged in user.
+       * 
+ * + * string username = 1; + * + * @param value The username to set. + * @return This builder for chaining. + */ + public Builder setUsername(java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + username_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + /** + * + * + *
+       * The username of the logged in user.
+       * 
+ * + * string username = 1; + * + * @return This builder for chaining. + */ + public Builder clearUsername() { + username_ = getDefaultInstance().getUsername(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + + /** + * + * + *
+       * The username of the logged in user.
+       * 
+ * + * string username = 1; + * + * @param value The bytes for username to set. + * @return This builder for chaining. + */ + public Builder setUsernameBytes(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + username_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private com.google.protobuf.Timestamp creationTime_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Timestamp, + com.google.protobuf.Timestamp.Builder, + com.google.protobuf.TimestampOrBuilder> + creationTimeBuilder_; + + /** + * + * + *
+       * The creation time of the access token.
+       * 
+ * + * .google.protobuf.Timestamp creation_time = 2; + * + * @return Whether the creationTime field is set. + */ + public boolean hasCreationTime() { + return ((bitField0_ & 0x00000002) != 0); + } + + /** + * + * + *
+       * The creation time of the access token.
+       * 
+ * + * .google.protobuf.Timestamp creation_time = 2; + * + * @return The creationTime. + */ + public com.google.protobuf.Timestamp getCreationTime() { + if (creationTimeBuilder_ == null) { + return creationTime_ == null + ? com.google.protobuf.Timestamp.getDefaultInstance() + : creationTime_; + } else { + return creationTimeBuilder_.getMessage(); + } + } + + /** + * + * + *
+       * The creation time of the access token.
+       * 
+ * + * .google.protobuf.Timestamp creation_time = 2; + */ + public Builder setCreationTime(com.google.protobuf.Timestamp value) { + if (creationTimeBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + creationTime_ = value; + } else { + creationTimeBuilder_.setMessage(value); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + /** + * + * + *
+       * The creation time of the access token.
+       * 
+ * + * .google.protobuf.Timestamp creation_time = 2; + */ + public Builder setCreationTime(com.google.protobuf.Timestamp.Builder builderForValue) { + if (creationTimeBuilder_ == null) { + creationTime_ = builderForValue.build(); + } else { + creationTimeBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + /** + * + * + *
+       * The creation time of the access token.
+       * 
+ * + * .google.protobuf.Timestamp creation_time = 2; + */ + public Builder mergeCreationTime(com.google.protobuf.Timestamp value) { + if (creationTimeBuilder_ == null) { + if (((bitField0_ & 0x00000002) != 0) + && creationTime_ != null + && creationTime_ != com.google.protobuf.Timestamp.getDefaultInstance()) { + getCreationTimeBuilder().mergeFrom(value); + } else { + creationTime_ = value; + } + } else { + creationTimeBuilder_.mergeFrom(value); + } + if (creationTime_ != null) { + bitField0_ |= 0x00000002; + onChanged(); + } + return this; + } + + /** + * + * + *
+       * The creation time of the access token.
+       * 
+ * + * .google.protobuf.Timestamp creation_time = 2; + */ + public Builder clearCreationTime() { + bitField0_ = (bitField0_ & ~0x00000002); + creationTime_ = null; + if (creationTimeBuilder_ != null) { + creationTimeBuilder_.dispose(); + creationTimeBuilder_ = null; + } + onChanged(); + return this; + } + + /** + * + * + *
+       * The creation time of the access token.
+       * 
+ * + * .google.protobuf.Timestamp creation_time = 2; + */ + public com.google.protobuf.Timestamp.Builder getCreationTimeBuilder() { + bitField0_ |= 0x00000002; + onChanged(); + return internalGetCreationTimeFieldBuilder().getBuilder(); + } + + /** + * + * + *
+       * The creation time of the access token.
+       * 
+ * + * .google.protobuf.Timestamp creation_time = 2; + */ + public com.google.protobuf.TimestampOrBuilder getCreationTimeOrBuilder() { + if (creationTimeBuilder_ != null) { + return creationTimeBuilder_.getMessageOrBuilder(); + } else { + return creationTime_ == null + ? com.google.protobuf.Timestamp.getDefaultInstance() + : creationTime_; + } + } + + /** + * + * + *
+       * The creation time of the access token.
+       * 
+ * + * .google.protobuf.Timestamp creation_time = 2; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Timestamp, + com.google.protobuf.Timestamp.Builder, + com.google.protobuf.TimestampOrBuilder> + internalGetCreationTimeFieldBuilder() { + if (creationTimeBuilder_ == null) { + creationTimeBuilder_ = + new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Timestamp, + com.google.protobuf.Timestamp.Builder, + com.google.protobuf.TimestampOrBuilder>( + getCreationTime(), getParentForChildren(), isClean()); + creationTime_ = null; + } + return creationTimeBuilder_; + } + + private com.google.protobuf.Timestamp expirationTime_; + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Timestamp, + com.google.protobuf.Timestamp.Builder, + com.google.protobuf.TimestampOrBuilder> + expirationTimeBuilder_; + + /** + * + * + *
+       * The expiration time of the access token, this will be checked by the
+       * server.
+       * 
+ * + * .google.protobuf.Timestamp expiration_time = 3; + * + * @return Whether the expirationTime field is set. + */ + public boolean hasExpirationTime() { + return ((bitField0_ & 0x00000004) != 0); + } + + /** + * + * + *
+       * The expiration time of the access token, this will be checked by the
+       * server.
+       * 
+ * + * .google.protobuf.Timestamp expiration_time = 3; + * + * @return The expirationTime. + */ + public com.google.protobuf.Timestamp getExpirationTime() { + if (expirationTimeBuilder_ == null) { + return expirationTime_ == null + ? com.google.protobuf.Timestamp.getDefaultInstance() + : expirationTime_; + } else { + return expirationTimeBuilder_.getMessage(); + } + } + + /** + * + * + *
+       * The expiration time of the access token, this will be checked by the
+       * server.
+       * 
+ * + * .google.protobuf.Timestamp expiration_time = 3; + */ + public Builder setExpirationTime(com.google.protobuf.Timestamp value) { + if (expirationTimeBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + expirationTime_ = value; + } else { + expirationTimeBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + /** + * + * + *
+       * The expiration time of the access token, this will be checked by the
+       * server.
+       * 
+ * + * .google.protobuf.Timestamp expiration_time = 3; + */ + public Builder setExpirationTime(com.google.protobuf.Timestamp.Builder builderForValue) { + if (expirationTimeBuilder_ == null) { + expirationTime_ = builderForValue.build(); + } else { + expirationTimeBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + /** + * + * + *
+       * The expiration time of the access token, this will be checked by the
+       * server.
+       * 
+ * + * .google.protobuf.Timestamp expiration_time = 3; + */ + public Builder mergeExpirationTime(com.google.protobuf.Timestamp value) { + if (expirationTimeBuilder_ == null) { + if (((bitField0_ & 0x00000004) != 0) + && expirationTime_ != null + && expirationTime_ != com.google.protobuf.Timestamp.getDefaultInstance()) { + getExpirationTimeBuilder().mergeFrom(value); + } else { + expirationTime_ = value; + } + } else { + expirationTimeBuilder_.mergeFrom(value); + } + if (expirationTime_ != null) { + bitField0_ |= 0x00000004; + onChanged(); + } + return this; + } + + /** + * + * + *
+       * The expiration time of the access token, this will be checked by the
+       * server.
+       * 
+ * + * .google.protobuf.Timestamp expiration_time = 3; + */ + public Builder clearExpirationTime() { + bitField0_ = (bitField0_ & ~0x00000004); + expirationTime_ = null; + if (expirationTimeBuilder_ != null) { + expirationTimeBuilder_.dispose(); + expirationTimeBuilder_ = null; + } + onChanged(); + return this; + } + + /** + * + * + *
+       * The expiration time of the access token, this will be checked by the
+       * server.
+       * 
+ * + * .google.protobuf.Timestamp expiration_time = 3; + */ + public com.google.protobuf.Timestamp.Builder getExpirationTimeBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return internalGetExpirationTimeFieldBuilder().getBuilder(); + } + + /** + * + * + *
+       * The expiration time of the access token, this will be checked by the
+       * server.
+       * 
+ * + * .google.protobuf.Timestamp expiration_time = 3; + */ + public com.google.protobuf.TimestampOrBuilder getExpirationTimeOrBuilder() { + if (expirationTimeBuilder_ != null) { + return expirationTimeBuilder_.getMessageOrBuilder(); + } else { + return expirationTime_ == null + ? com.google.protobuf.Timestamp.getDefaultInstance() + : expirationTime_; + } + } + + /** + * + * + *
+       * The expiration time of the access token, this will be checked by the
+       * server.
+       * 
+ * + * .google.protobuf.Timestamp expiration_time = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Timestamp, + com.google.protobuf.Timestamp.Builder, + com.google.protobuf.TimestampOrBuilder> + internalGetExpirationTimeFieldBuilder() { + if (expirationTimeBuilder_ == null) { + expirationTimeBuilder_ = + new com.google.protobuf.SingleFieldBuilder< + com.google.protobuf.Timestamp, + com.google.protobuf.Timestamp.Builder, + com.google.protobuf.TimestampOrBuilder>( + getExpirationTime(), getParentForChildren(), isClean()); + expirationTime_ = null; + } + return expirationTimeBuilder_; + } + + private com.google.protobuf.ByteString signature_ = com.google.protobuf.ByteString.EMPTY; + + /** + * + * + *
+       * The signature of the access token, this will be verified by the server.
+       * 
+ * + * bytes signature = 4; + * + * @return The signature. + */ + @java.lang.Override + public com.google.protobuf.ByteString getSignature() { + return signature_; + } + + /** + * + * + *
+       * The signature of the access token, this will be verified by the server.
+       * 
+ * + * bytes signature = 4; + * + * @param value The signature to set. + * @return This builder for chaining. + */ + public Builder setSignature(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + signature_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + + /** + * + * + *
+       * The signature of the access token, this will be verified by the server.
+       * 
+ * + * bytes signature = 4; + * + * @return This builder for chaining. + */ + public Builder clearSignature() { + bitField0_ = (bitField0_ & ~0x00000008); + signature_ = getDefaultInstance().getSignature(); + onChanged(); + return this; + } + + private long keyId_; + + /** + * + * + *
+       * The ID of the key used to sign/verify the access token.
+       * 
+ * + * int64 key_id = 5; + * + * @return The keyId. + */ + @java.lang.Override + public long getKeyId() { + return keyId_; + } + + /** + * + * + *
+       * The ID of the key used to sign/verify the access token.
+       * 
+ * + * int64 key_id = 5; + * + * @param value The keyId to set. + * @return This builder for chaining. + */ + public Builder setKeyId(long value) { + + keyId_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + + /** + * + * + *
+       * The ID of the key used to sign/verify the access token.
+       * 
+ * + * int64 key_id = 5; + * + * @return This builder for chaining. + */ + public Builder clearKeyId() { + bitField0_ = (bitField0_ & ~0x00000010); + keyId_ = 0L; + onChanged(); + return this; + } + + private int accessTokenType_ = 0; + + /** + * + * + *
+       * The type of the access token, this will be checked by the server.
+       * 
+ * + * .google.spanner.auth.v1.AccessToken.AccessTokenType access_token_type = 6; + * + * @return The enum numeric value on the wire for accessTokenType. + */ + @java.lang.Override + public int getAccessTokenTypeValue() { + return accessTokenType_; + } + + /** + * + * + *
+       * The type of the access token, this will be checked by the server.
+       * 
+ * + * .google.spanner.auth.v1.AccessToken.AccessTokenType access_token_type = 6; + * + * @param value The enum numeric value on the wire for accessTokenType to set. + * @return This builder for chaining. + */ + public Builder setAccessTokenTypeValue(int value) { + accessTokenType_ = value; + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + + /** + * + * + *
+       * The type of the access token, this will be checked by the server.
+       * 
+ * + * .google.spanner.auth.v1.AccessToken.AccessTokenType access_token_type = 6; + * + * @return The accessTokenType. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AccessToken.AccessTokenType getAccessTokenType() { + com.google.cloud.spanner.omni.Login.AccessToken.AccessTokenType result = + com.google.cloud.spanner.omni.Login.AccessToken.AccessTokenType.forNumber( + accessTokenType_); + return result == null + ? com.google.cloud.spanner.omni.Login.AccessToken.AccessTokenType.UNRECOGNIZED + : result; + } + + /** + * + * + *
+       * The type of the access token, this will be checked by the server.
+       * 
+ * + * .google.spanner.auth.v1.AccessToken.AccessTokenType access_token_type = 6; + * + * @param value The accessTokenType to set. + * @return This builder for chaining. + */ + public Builder setAccessTokenType( + com.google.cloud.spanner.omni.Login.AccessToken.AccessTokenType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000020; + accessTokenType_ = value.getNumber(); + onChanged(); + return this; + } + + /** + * + * + *
+       * The type of the access token, this will be checked by the server.
+       * 
+ * + * .google.spanner.auth.v1.AccessToken.AccessTokenType access_token_type = 6; + * + * @return This builder for chaining. + */ + public Builder clearAccessTokenType() { + bitField0_ = (bitField0_ & ~0x00000020); + accessTokenType_ = 0; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:google.spanner.auth.v1.AccessToken) + } + + // @@protoc_insertion_point(class_scope:google.spanner.auth.v1.AccessToken) + private static final com.google.cloud.spanner.omni.Login.AccessToken DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new com.google.cloud.spanner.omni.Login.AccessToken(); + } + + public static com.google.cloud.spanner.omni.Login.AccessToken getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + @java.lang.Override + public AccessToken parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException() + .setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AccessToken getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + } + + public interface InitialOpaqueLoginRequestOrBuilder + extends + // @@protoc_insertion_point(interface_extends:google.spanner.auth.v1.InitialOpaqueLoginRequest) + com.google.protobuf.MessageOrBuilder { + + /** + * + * + *
+     * The blinded message is used to fetch the user's credentials from the
+     * server.
+     * 
+ * + * bytes blinded_message = 1; + * + * @return The blindedMessage. + */ + com.google.protobuf.ByteString getBlindedMessage(); + + /** + * + * + *
+     * The AuthRequest fields as defined in rfc9807.
+     * 
+ * + * bytes client_nonce = 2; + * + * @return The clientNonce. + */ + com.google.protobuf.ByteString getClientNonce(); + + /** + * bytes client_public_keyshare = 3; + * + * @return The clientPublicKeyshare. + */ + com.google.protobuf.ByteString getClientPublicKeyshare(); + } + + /** + * + * + *
+   * InitialOpaqueLoginRequest is used to start the OPAQUE handshake, it will
+   * contain the blinded message provided by the client.
+   * 
+ * + * Protobuf type {@code google.spanner.auth.v1.InitialOpaqueLoginRequest} + */ + public static final class InitialOpaqueLoginRequest extends com.google.protobuf.GeneratedMessage + implements + // @@protoc_insertion_point(message_implements:google.spanner.auth.v1.InitialOpaqueLoginRequest) + InitialOpaqueLoginRequestOrBuilder { + private static final long serialVersionUID = 0L; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 2, + /* suffix= */ "", + "InitialOpaqueLoginRequest"); + } + + // Use InitialOpaqueLoginRequest.newBuilder() to construct. + private InitialOpaqueLoginRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + + private InitialOpaqueLoginRequest() { + blindedMessage_ = com.google.protobuf.ByteString.EMPTY; + clientNonce_ = com.google.protobuf.ByteString.EMPTY; + clientPublicKeyshare_ = com.google.protobuf.ByteString.EMPTY; + } + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_InitialOpaqueLoginRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_InitialOpaqueLoginRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest.class, + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest.Builder.class); + } + + public static final int BLINDED_MESSAGE_FIELD_NUMBER = 1; + private com.google.protobuf.ByteString blindedMessage_ = com.google.protobuf.ByteString.EMPTY; + + /** + * + * + *
+     * The blinded message is used to fetch the user's credentials from the
+     * server.
+     * 
+ * + * bytes blinded_message = 1; + * + * @return The blindedMessage. + */ + @java.lang.Override + public com.google.protobuf.ByteString getBlindedMessage() { + return blindedMessage_; + } + + public static final int CLIENT_NONCE_FIELD_NUMBER = 2; + private com.google.protobuf.ByteString clientNonce_ = com.google.protobuf.ByteString.EMPTY; + + /** + * + * + *
+     * The AuthRequest fields as defined in rfc9807.
+     * 
+ * + * bytes client_nonce = 2; + * + * @return The clientNonce. + */ + @java.lang.Override + public com.google.protobuf.ByteString getClientNonce() { + return clientNonce_; + } + + public static final int CLIENT_PUBLIC_KEYSHARE_FIELD_NUMBER = 3; + private com.google.protobuf.ByteString clientPublicKeyshare_ = + com.google.protobuf.ByteString.EMPTY; + + /** + * bytes client_public_keyshare = 3; + * + * @return The clientPublicKeyshare. + */ + @java.lang.Override + public com.google.protobuf.ByteString getClientPublicKeyshare() { + return clientPublicKeyshare_; + } + + private byte memoizedIsInitialized = -1; + + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { + if (!blindedMessage_.isEmpty()) { + output.writeBytes(1, blindedMessage_); + } + if (!clientNonce_.isEmpty()) { + output.writeBytes(2, clientNonce_); + } + if (!clientPublicKeyshare_.isEmpty()) { + output.writeBytes(3, clientPublicKeyshare_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!blindedMessage_.isEmpty()) { + size += com.google.protobuf.CodedOutputStream.computeBytesSize(1, blindedMessage_); + } + if (!clientNonce_.isEmpty()) { + size += com.google.protobuf.CodedOutputStream.computeBytesSize(2, clientNonce_); + } + if (!clientPublicKeyshare_.isEmpty()) { + size += com.google.protobuf.CodedOutputStream.computeBytesSize(3, clientPublicKeyshare_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest)) { + return super.equals(obj); + } + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest other = + (com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest) obj; + + if (!getBlindedMessage().equals(other.getBlindedMessage())) return false; + if (!getClientNonce().equals(other.getClientNonce())) return false; + if (!getClientPublicKeyshare().equals(other.getClientPublicKeyshare())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + BLINDED_MESSAGE_FIELD_NUMBER; + hash = (53 * hash) + getBlindedMessage().hashCode(); + hash = (37 * hash) + CLIENT_NONCE_FIELD_NUMBER; + hash = (53 * hash) + getClientNonce().hashCode(); + hash = (37 * hash) + CLIENT_PUBLIC_KEYSHARE_FIELD_NUMBER; + hash = (53 * hash) + getClientPublicKeyshare().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest parseFrom( + java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest parseFrom( + java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest parseFrom( + byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest parseFrom( + byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest parseFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest parseFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest parseDelimitedFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest parseDelimitedFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest parseFrom( + com.google.protobuf.CodedInputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder( + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** + * + * + *
+     * InitialOpaqueLoginRequest is used to start the OPAQUE handshake, it will
+     * contain the blinded message provided by the client.
+     * 
+ * + * Protobuf type {@code google.spanner.auth.v1.InitialOpaqueLoginRequest} + */ + public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder + implements + // @@protoc_insertion_point(builder_implements:google.spanner.auth.v1.InitialOpaqueLoginRequest) + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_InitialOpaqueLoginRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_InitialOpaqueLoginRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest.class, + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest.Builder.class); + } + + // Construct using com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest.newBuilder() + private Builder() {} + + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + } + + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + blindedMessage_ = com.google.protobuf.ByteString.EMPTY; + clientNonce_ = com.google.protobuf.ByteString.EMPTY; + clientPublicKeyshare_ = com.google.protobuf.ByteString.EMPTY; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_InitialOpaqueLoginRequest_descriptor; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest + getDefaultInstanceForType() { + return com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest.getDefaultInstance(); + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest build() { + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest buildPartial() { + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest result = + new com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest(this); + if (bitField0_ != 0) { + buildPartial0(result); + } + onBuilt(); + return result; + } + + private void buildPartial0( + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.blindedMessage_ = blindedMessage_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.clientNonce_ = clientNonce_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.clientPublicKeyshare_ = clientPublicKeyshare_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest) { + return mergeFrom((com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom( + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest other) { + if (other + == com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest.getDefaultInstance()) + return this; + if (!other.getBlindedMessage().isEmpty()) { + setBlindedMessage(other.getBlindedMessage()); + } + if (!other.getClientNonce().isEmpty()) { + setClientNonce(other.getClientNonce()); + } + if (!other.getClientPublicKeyshare().isEmpty()) { + setClientPublicKeyshare(other.getClientPublicKeyshare()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: + { + blindedMessage_ = input.readBytes(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: + { + clientNonce_ = input.readBytes(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: + { + clientPublicKeyshare_ = input.readBytes(); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: + { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + private int bitField0_; + + private com.google.protobuf.ByteString blindedMessage_ = com.google.protobuf.ByteString.EMPTY; + + /** + * + * + *
+       * The blinded message is used to fetch the user's credentials from the
+       * server.
+       * 
+ * + * bytes blinded_message = 1; + * + * @return The blindedMessage. + */ + @java.lang.Override + public com.google.protobuf.ByteString getBlindedMessage() { + return blindedMessage_; + } + + /** + * + * + *
+       * The blinded message is used to fetch the user's credentials from the
+       * server.
+       * 
+ * + * bytes blinded_message = 1; + * + * @param value The blindedMessage to set. + * @return This builder for chaining. + */ + public Builder setBlindedMessage(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + blindedMessage_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + /** + * + * + *
+       * The blinded message is used to fetch the user's credentials from the
+       * server.
+       * 
+ * + * bytes blinded_message = 1; + * + * @return This builder for chaining. + */ + public Builder clearBlindedMessage() { + bitField0_ = (bitField0_ & ~0x00000001); + blindedMessage_ = getDefaultInstance().getBlindedMessage(); + onChanged(); + return this; + } + + private com.google.protobuf.ByteString clientNonce_ = com.google.protobuf.ByteString.EMPTY; + + /** + * + * + *
+       * The AuthRequest fields as defined in rfc9807.
+       * 
+ * + * bytes client_nonce = 2; + * + * @return The clientNonce. + */ + @java.lang.Override + public com.google.protobuf.ByteString getClientNonce() { + return clientNonce_; + } + + /** + * + * + *
+       * The AuthRequest fields as defined in rfc9807.
+       * 
+ * + * bytes client_nonce = 2; + * + * @param value The clientNonce to set. + * @return This builder for chaining. + */ + public Builder setClientNonce(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + clientNonce_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + /** + * + * + *
+       * The AuthRequest fields as defined in rfc9807.
+       * 
+ * + * bytes client_nonce = 2; + * + * @return This builder for chaining. + */ + public Builder clearClientNonce() { + bitField0_ = (bitField0_ & ~0x00000002); + clientNonce_ = getDefaultInstance().getClientNonce(); + onChanged(); + return this; + } + + private com.google.protobuf.ByteString clientPublicKeyshare_ = + com.google.protobuf.ByteString.EMPTY; + + /** + * bytes client_public_keyshare = 3; + * + * @return The clientPublicKeyshare. + */ + @java.lang.Override + public com.google.protobuf.ByteString getClientPublicKeyshare() { + return clientPublicKeyshare_; + } + + /** + * bytes client_public_keyshare = 3; + * + * @param value The clientPublicKeyshare to set. + * @return This builder for chaining. + */ + public Builder setClientPublicKeyshare(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + clientPublicKeyshare_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + /** + * bytes client_public_keyshare = 3; + * + * @return This builder for chaining. + */ + public Builder clearClientPublicKeyshare() { + bitField0_ = (bitField0_ & ~0x00000004); + clientPublicKeyshare_ = getDefaultInstance().getClientPublicKeyshare(); + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:google.spanner.auth.v1.InitialOpaqueLoginRequest) + } + + // @@protoc_insertion_point(class_scope:google.spanner.auth.v1.InitialOpaqueLoginRequest) + private static final com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest + DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest(); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest + getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + @java.lang.Override + public InitialOpaqueLoginRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException() + .setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest + getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + } + + public interface FinalOpaqueLoginRequestOrBuilder + extends + // @@protoc_insertion_point(interface_extends:google.spanner.auth.v1.FinalOpaqueLoginRequest) + com.google.protobuf.MessageOrBuilder { + + /** + * + * + *
+     * The client calculated MAC, this is used to authenticate the client.
+     * 
+ * + * bytes client_mac = 1; + * + * @return The clientMac. + */ + com.google.protobuf.ByteString getClientMac(); + } + + /** + * + * + *
+   * FinalOpaqueLoginRequest is used to complete the OPAQUE handshake, it will
+   * contain the client calculated MAC, this is used to authenticate the client.
+   * 
+ * + * Protobuf type {@code google.spanner.auth.v1.FinalOpaqueLoginRequest} + */ + public static final class FinalOpaqueLoginRequest extends com.google.protobuf.GeneratedMessage + implements + // @@protoc_insertion_point(message_implements:google.spanner.auth.v1.FinalOpaqueLoginRequest) + FinalOpaqueLoginRequestOrBuilder { + private static final long serialVersionUID = 0L; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 2, + /* suffix= */ "", + "FinalOpaqueLoginRequest"); + } + + // Use FinalOpaqueLoginRequest.newBuilder() to construct. + private FinalOpaqueLoginRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + + private FinalOpaqueLoginRequest() { + clientMac_ = com.google.protobuf.ByteString.EMPTY; + } + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_FinalOpaqueLoginRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_FinalOpaqueLoginRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest.class, + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest.Builder.class); + } + + public static final int CLIENT_MAC_FIELD_NUMBER = 1; + private com.google.protobuf.ByteString clientMac_ = com.google.protobuf.ByteString.EMPTY; + + /** + * + * + *
+     * The client calculated MAC, this is used to authenticate the client.
+     * 
+ * + * bytes client_mac = 1; + * + * @return The clientMac. + */ + @java.lang.Override + public com.google.protobuf.ByteString getClientMac() { + return clientMac_; + } + + private byte memoizedIsInitialized = -1; + + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { + if (!clientMac_.isEmpty()) { + output.writeBytes(1, clientMac_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!clientMac_.isEmpty()) { + size += com.google.protobuf.CodedOutputStream.computeBytesSize(1, clientMac_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest)) { + return super.equals(obj); + } + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest other = + (com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest) obj; + + if (!getClientMac().equals(other.getClientMac())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + CLIENT_MAC_FIELD_NUMBER; + hash = (53 * hash) + getClientMac().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest parseFrom( + java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest parseFrom( + java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest parseFrom( + byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest parseFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest parseFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest parseDelimitedFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest parseDelimitedFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest parseFrom( + com.google.protobuf.CodedInputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder( + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** + * + * + *
+     * FinalOpaqueLoginRequest is used to complete the OPAQUE handshake, it will
+     * contain the client calculated MAC, this is used to authenticate the client.
+     * 
+ * + * Protobuf type {@code google.spanner.auth.v1.FinalOpaqueLoginRequest} + */ + public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder + implements + // @@protoc_insertion_point(builder_implements:google.spanner.auth.v1.FinalOpaqueLoginRequest) + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_FinalOpaqueLoginRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_FinalOpaqueLoginRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest.class, + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest.Builder.class); + } + + // Construct using com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest.newBuilder() + private Builder() {} + + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + } + + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + clientMac_ = com.google.protobuf.ByteString.EMPTY; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_FinalOpaqueLoginRequest_descriptor; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest + getDefaultInstanceForType() { + return com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest.getDefaultInstance(); + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest build() { + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest buildPartial() { + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest result = + new com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest(this); + if (bitField0_ != 0) { + buildPartial0(result); + } + onBuilt(); + return result; + } + + private void buildPartial0( + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.clientMac_ = clientMac_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest) { + return mergeFrom((com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest other) { + if (other + == com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest.getDefaultInstance()) + return this; + if (!other.getClientMac().isEmpty()) { + setClientMac(other.getClientMac()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: + { + clientMac_ = input.readBytes(); + bitField0_ |= 0x00000001; + break; + } // case 10 + default: + { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + private int bitField0_; + + private com.google.protobuf.ByteString clientMac_ = com.google.protobuf.ByteString.EMPTY; + + /** + * + * + *
+       * The client calculated MAC, this is used to authenticate the client.
+       * 
+ * + * bytes client_mac = 1; + * + * @return The clientMac. + */ + @java.lang.Override + public com.google.protobuf.ByteString getClientMac() { + return clientMac_; + } + + /** + * + * + *
+       * The client calculated MAC, this is used to authenticate the client.
+       * 
+ * + * bytes client_mac = 1; + * + * @param value The clientMac to set. + * @return This builder for chaining. + */ + public Builder setClientMac(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + clientMac_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + /** + * + * + *
+       * The client calculated MAC, this is used to authenticate the client.
+       * 
+ * + * bytes client_mac = 1; + * + * @return This builder for chaining. + */ + public Builder clearClientMac() { + bitField0_ = (bitField0_ & ~0x00000001); + clientMac_ = getDefaultInstance().getClientMac(); + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:google.spanner.auth.v1.FinalOpaqueLoginRequest) + } + + // @@protoc_insertion_point(class_scope:google.spanner.auth.v1.FinalOpaqueLoginRequest) + private static final com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest + DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest(); + } + + public static com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + @java.lang.Override + public FinalOpaqueLoginRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException() + .setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + } + + public interface InitialOpaqueLoginResponseOrBuilder + extends + // @@protoc_insertion_point(interface_extends:google.spanner.auth.v1.InitialOpaqueLoginResponse) + com.google.protobuf.MessageOrBuilder { + + /** + * + * + *
+     * The fields that make up the `AuthResponse` message as defined in
+     * rfc9807.
+     * 
+ * + * bytes server_nonce = 1; + * + * @return The serverNonce. + */ + com.google.protobuf.ByteString getServerNonce(); + + /** + * bytes server_public_keyshare = 2; + * + * @return The serverPublicKeyshare. + */ + com.google.protobuf.ByteString getServerPublicKeyshare(); + + /** + * bytes server_mac = 3; + * + * @return The serverMac. + */ + com.google.protobuf.ByteString getServerMac(); + + /** + * + * + *
+     * The fields that make up the `CredentialResponse` message as defined in
+     * rfc9807.
+     * 
+ * + * bytes evaluated_message = 4; + * + * @return The evaluatedMessage. + */ + com.google.protobuf.ByteString getEvaluatedMessage(); + + /** + * + * + *
+     * The masking_nonce is used to protect the confidential masked response.
+     * 
+ * + * bytes masking_nonce = 5; + * + * @return The maskingNonce. + */ + com.google.protobuf.ByteString getMaskingNonce(); + + /** + * + * + *
+     * The masked_response is the ciphertext containing the user's envelope.
+     * 
+ * + * bytes masked_response = 6; + * + * @return The maskedResponse. + */ + com.google.protobuf.ByteString getMaskedResponse(); + } + + /** + * + * + *
+   * The initial response from the server when using OPAQUE authentication.
+   * This is referred to as the `K2` message in rfc9807.
+   * 
+ * + * Protobuf type {@code google.spanner.auth.v1.InitialOpaqueLoginResponse} + */ + public static final class InitialOpaqueLoginResponse extends com.google.protobuf.GeneratedMessage + implements + // @@protoc_insertion_point(message_implements:google.spanner.auth.v1.InitialOpaqueLoginResponse) + InitialOpaqueLoginResponseOrBuilder { + private static final long serialVersionUID = 0L; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 2, + /* suffix= */ "", + "InitialOpaqueLoginResponse"); + } + + // Use InitialOpaqueLoginResponse.newBuilder() to construct. + private InitialOpaqueLoginResponse(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + + private InitialOpaqueLoginResponse() { + serverNonce_ = com.google.protobuf.ByteString.EMPTY; + serverPublicKeyshare_ = com.google.protobuf.ByteString.EMPTY; + serverMac_ = com.google.protobuf.ByteString.EMPTY; + evaluatedMessage_ = com.google.protobuf.ByteString.EMPTY; + maskingNonce_ = com.google.protobuf.ByteString.EMPTY; + maskedResponse_ = com.google.protobuf.ByteString.EMPTY; + } + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_InitialOpaqueLoginResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_InitialOpaqueLoginResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse.class, + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse.Builder.class); + } + + public static final int SERVER_NONCE_FIELD_NUMBER = 1; + private com.google.protobuf.ByteString serverNonce_ = com.google.protobuf.ByteString.EMPTY; + + /** + * + * + *
+     * The fields that make up the `AuthResponse` message as defined in
+     * rfc9807.
+     * 
+ * + * bytes server_nonce = 1; + * + * @return The serverNonce. + */ + @java.lang.Override + public com.google.protobuf.ByteString getServerNonce() { + return serverNonce_; + } + + public static final int SERVER_PUBLIC_KEYSHARE_FIELD_NUMBER = 2; + private com.google.protobuf.ByteString serverPublicKeyshare_ = + com.google.protobuf.ByteString.EMPTY; + + /** + * bytes server_public_keyshare = 2; + * + * @return The serverPublicKeyshare. + */ + @java.lang.Override + public com.google.protobuf.ByteString getServerPublicKeyshare() { + return serverPublicKeyshare_; + } + + public static final int SERVER_MAC_FIELD_NUMBER = 3; + private com.google.protobuf.ByteString serverMac_ = com.google.protobuf.ByteString.EMPTY; + + /** + * bytes server_mac = 3; + * + * @return The serverMac. + */ + @java.lang.Override + public com.google.protobuf.ByteString getServerMac() { + return serverMac_; + } + + public static final int EVALUATED_MESSAGE_FIELD_NUMBER = 4; + private com.google.protobuf.ByteString evaluatedMessage_ = com.google.protobuf.ByteString.EMPTY; + + /** + * + * + *
+     * The fields that make up the `CredentialResponse` message as defined in
+     * rfc9807.
+     * 
+ * + * bytes evaluated_message = 4; + * + * @return The evaluatedMessage. + */ + @java.lang.Override + public com.google.protobuf.ByteString getEvaluatedMessage() { + return evaluatedMessage_; + } + + public static final int MASKING_NONCE_FIELD_NUMBER = 5; + private com.google.protobuf.ByteString maskingNonce_ = com.google.protobuf.ByteString.EMPTY; + + /** + * + * + *
+     * The masking_nonce is used to protect the confidential masked response.
+     * 
+ * + * bytes masking_nonce = 5; + * + * @return The maskingNonce. + */ + @java.lang.Override + public com.google.protobuf.ByteString getMaskingNonce() { + return maskingNonce_; + } + + public static final int MASKED_RESPONSE_FIELD_NUMBER = 6; + private com.google.protobuf.ByteString maskedResponse_ = com.google.protobuf.ByteString.EMPTY; + + /** + * + * + *
+     * The masked_response is the ciphertext containing the user's envelope.
+     * 
+ * + * bytes masked_response = 6; + * + * @return The maskedResponse. + */ + @java.lang.Override + public com.google.protobuf.ByteString getMaskedResponse() { + return maskedResponse_; + } + + private byte memoizedIsInitialized = -1; + + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { + if (!serverNonce_.isEmpty()) { + output.writeBytes(1, serverNonce_); + } + if (!serverPublicKeyshare_.isEmpty()) { + output.writeBytes(2, serverPublicKeyshare_); + } + if (!serverMac_.isEmpty()) { + output.writeBytes(3, serverMac_); + } + if (!evaluatedMessage_.isEmpty()) { + output.writeBytes(4, evaluatedMessage_); + } + if (!maskingNonce_.isEmpty()) { + output.writeBytes(5, maskingNonce_); + } + if (!maskedResponse_.isEmpty()) { + output.writeBytes(6, maskedResponse_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!serverNonce_.isEmpty()) { + size += com.google.protobuf.CodedOutputStream.computeBytesSize(1, serverNonce_); + } + if (!serverPublicKeyshare_.isEmpty()) { + size += com.google.protobuf.CodedOutputStream.computeBytesSize(2, serverPublicKeyshare_); + } + if (!serverMac_.isEmpty()) { + size += com.google.protobuf.CodedOutputStream.computeBytesSize(3, serverMac_); + } + if (!evaluatedMessage_.isEmpty()) { + size += com.google.protobuf.CodedOutputStream.computeBytesSize(4, evaluatedMessage_); + } + if (!maskingNonce_.isEmpty()) { + size += com.google.protobuf.CodedOutputStream.computeBytesSize(5, maskingNonce_); + } + if (!maskedResponse_.isEmpty()) { + size += com.google.protobuf.CodedOutputStream.computeBytesSize(6, maskedResponse_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse)) { + return super.equals(obj); + } + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse other = + (com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse) obj; + + if (!getServerNonce().equals(other.getServerNonce())) return false; + if (!getServerPublicKeyshare().equals(other.getServerPublicKeyshare())) return false; + if (!getServerMac().equals(other.getServerMac())) return false; + if (!getEvaluatedMessage().equals(other.getEvaluatedMessage())) return false; + if (!getMaskingNonce().equals(other.getMaskingNonce())) return false; + if (!getMaskedResponse().equals(other.getMaskedResponse())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + SERVER_NONCE_FIELD_NUMBER; + hash = (53 * hash) + getServerNonce().hashCode(); + hash = (37 * hash) + SERVER_PUBLIC_KEYSHARE_FIELD_NUMBER; + hash = (53 * hash) + getServerPublicKeyshare().hashCode(); + hash = (37 * hash) + SERVER_MAC_FIELD_NUMBER; + hash = (53 * hash) + getServerMac().hashCode(); + hash = (37 * hash) + EVALUATED_MESSAGE_FIELD_NUMBER; + hash = (53 * hash) + getEvaluatedMessage().hashCode(); + hash = (37 * hash) + MASKING_NONCE_FIELD_NUMBER; + hash = (53 * hash) + getMaskingNonce().hashCode(); + hash = (37 * hash) + MASKED_RESPONSE_FIELD_NUMBER; + hash = (53 * hash) + getMaskedResponse().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse parseFrom( + java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse parseFrom( + java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse parseFrom( + byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse parseFrom( + byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse parseFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse parseFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse parseDelimitedFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse parseDelimitedFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse parseFrom( + com.google.protobuf.CodedInputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder( + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** + * + * + *
+     * The initial response from the server when using OPAQUE authentication.
+     * This is referred to as the `K2` message in rfc9807.
+     * 
+ * + * Protobuf type {@code google.spanner.auth.v1.InitialOpaqueLoginResponse} + */ + public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder + implements + // @@protoc_insertion_point(builder_implements:google.spanner.auth.v1.InitialOpaqueLoginResponse) + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponseOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_InitialOpaqueLoginResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_InitialOpaqueLoginResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse.class, + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse.Builder.class); + } + + // Construct using com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse.newBuilder() + private Builder() {} + + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + } + + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + serverNonce_ = com.google.protobuf.ByteString.EMPTY; + serverPublicKeyshare_ = com.google.protobuf.ByteString.EMPTY; + serverMac_ = com.google.protobuf.ByteString.EMPTY; + evaluatedMessage_ = com.google.protobuf.ByteString.EMPTY; + maskingNonce_ = com.google.protobuf.ByteString.EMPTY; + maskedResponse_ = com.google.protobuf.ByteString.EMPTY; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_InitialOpaqueLoginResponse_descriptor; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse + getDefaultInstanceForType() { + return com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse.getDefaultInstance(); + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse build() { + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse buildPartial() { + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse result = + new com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse(this); + if (bitField0_ != 0) { + buildPartial0(result); + } + onBuilt(); + return result; + } + + private void buildPartial0( + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.serverNonce_ = serverNonce_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.serverPublicKeyshare_ = serverPublicKeyshare_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.serverMac_ = serverMac_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.evaluatedMessage_ = evaluatedMessage_; + } + if (((from_bitField0_ & 0x00000010) != 0)) { + result.maskingNonce_ = maskingNonce_; + } + if (((from_bitField0_ & 0x00000020) != 0)) { + result.maskedResponse_ = maskedResponse_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse) { + return mergeFrom((com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom( + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse other) { + if (other + == com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse.getDefaultInstance()) + return this; + if (!other.getServerNonce().isEmpty()) { + setServerNonce(other.getServerNonce()); + } + if (!other.getServerPublicKeyshare().isEmpty()) { + setServerPublicKeyshare(other.getServerPublicKeyshare()); + } + if (!other.getServerMac().isEmpty()) { + setServerMac(other.getServerMac()); + } + if (!other.getEvaluatedMessage().isEmpty()) { + setEvaluatedMessage(other.getEvaluatedMessage()); + } + if (!other.getMaskingNonce().isEmpty()) { + setMaskingNonce(other.getMaskingNonce()); + } + if (!other.getMaskedResponse().isEmpty()) { + setMaskedResponse(other.getMaskedResponse()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: + { + serverNonce_ = input.readBytes(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: + { + serverPublicKeyshare_ = input.readBytes(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: + { + serverMac_ = input.readBytes(); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: + { + evaluatedMessage_ = input.readBytes(); + bitField0_ |= 0x00000008; + break; + } // case 34 + case 42: + { + maskingNonce_ = input.readBytes(); + bitField0_ |= 0x00000010; + break; + } // case 42 + case 50: + { + maskedResponse_ = input.readBytes(); + bitField0_ |= 0x00000020; + break; + } // case 50 + default: + { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + private int bitField0_; + + private com.google.protobuf.ByteString serverNonce_ = com.google.protobuf.ByteString.EMPTY; + + /** + * + * + *
+       * The fields that make up the `AuthResponse` message as defined in
+       * rfc9807.
+       * 
+ * + * bytes server_nonce = 1; + * + * @return The serverNonce. + */ + @java.lang.Override + public com.google.protobuf.ByteString getServerNonce() { + return serverNonce_; + } + + /** + * + * + *
+       * The fields that make up the `AuthResponse` message as defined in
+       * rfc9807.
+       * 
+ * + * bytes server_nonce = 1; + * + * @param value The serverNonce to set. + * @return This builder for chaining. + */ + public Builder setServerNonce(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + serverNonce_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + /** + * + * + *
+       * The fields that make up the `AuthResponse` message as defined in
+       * rfc9807.
+       * 
+ * + * bytes server_nonce = 1; + * + * @return This builder for chaining. + */ + public Builder clearServerNonce() { + bitField0_ = (bitField0_ & ~0x00000001); + serverNonce_ = getDefaultInstance().getServerNonce(); + onChanged(); + return this; + } + + private com.google.protobuf.ByteString serverPublicKeyshare_ = + com.google.protobuf.ByteString.EMPTY; + + /** + * bytes server_public_keyshare = 2; + * + * @return The serverPublicKeyshare. + */ + @java.lang.Override + public com.google.protobuf.ByteString getServerPublicKeyshare() { + return serverPublicKeyshare_; + } + + /** + * bytes server_public_keyshare = 2; + * + * @param value The serverPublicKeyshare to set. + * @return This builder for chaining. + */ + public Builder setServerPublicKeyshare(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + serverPublicKeyshare_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + /** + * bytes server_public_keyshare = 2; + * + * @return This builder for chaining. + */ + public Builder clearServerPublicKeyshare() { + bitField0_ = (bitField0_ & ~0x00000002); + serverPublicKeyshare_ = getDefaultInstance().getServerPublicKeyshare(); + onChanged(); + return this; + } + + private com.google.protobuf.ByteString serverMac_ = com.google.protobuf.ByteString.EMPTY; + + /** + * bytes server_mac = 3; + * + * @return The serverMac. + */ + @java.lang.Override + public com.google.protobuf.ByteString getServerMac() { + return serverMac_; + } + + /** + * bytes server_mac = 3; + * + * @param value The serverMac to set. + * @return This builder for chaining. + */ + public Builder setServerMac(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + serverMac_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + /** + * bytes server_mac = 3; + * + * @return This builder for chaining. + */ + public Builder clearServerMac() { + bitField0_ = (bitField0_ & ~0x00000004); + serverMac_ = getDefaultInstance().getServerMac(); + onChanged(); + return this; + } + + private com.google.protobuf.ByteString evaluatedMessage_ = + com.google.protobuf.ByteString.EMPTY; + + /** + * + * + *
+       * The fields that make up the `CredentialResponse` message as defined in
+       * rfc9807.
+       * 
+ * + * bytes evaluated_message = 4; + * + * @return The evaluatedMessage. + */ + @java.lang.Override + public com.google.protobuf.ByteString getEvaluatedMessage() { + return evaluatedMessage_; + } + + /** + * + * + *
+       * The fields that make up the `CredentialResponse` message as defined in
+       * rfc9807.
+       * 
+ * + * bytes evaluated_message = 4; + * + * @param value The evaluatedMessage to set. + * @return This builder for chaining. + */ + public Builder setEvaluatedMessage(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + evaluatedMessage_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + + /** + * + * + *
+       * The fields that make up the `CredentialResponse` message as defined in
+       * rfc9807.
+       * 
+ * + * bytes evaluated_message = 4; + * + * @return This builder for chaining. + */ + public Builder clearEvaluatedMessage() { + bitField0_ = (bitField0_ & ~0x00000008); + evaluatedMessage_ = getDefaultInstance().getEvaluatedMessage(); + onChanged(); + return this; + } + + private com.google.protobuf.ByteString maskingNonce_ = com.google.protobuf.ByteString.EMPTY; + + /** + * + * + *
+       * The masking_nonce is used to protect the confidential masked response.
+       * 
+ * + * bytes masking_nonce = 5; + * + * @return The maskingNonce. + */ + @java.lang.Override + public com.google.protobuf.ByteString getMaskingNonce() { + return maskingNonce_; + } + + /** + * + * + *
+       * The masking_nonce is used to protect the confidential masked response.
+       * 
+ * + * bytes masking_nonce = 5; + * + * @param value The maskingNonce to set. + * @return This builder for chaining. + */ + public Builder setMaskingNonce(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + maskingNonce_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + + /** + * + * + *
+       * The masking_nonce is used to protect the confidential masked response.
+       * 
+ * + * bytes masking_nonce = 5; + * + * @return This builder for chaining. + */ + public Builder clearMaskingNonce() { + bitField0_ = (bitField0_ & ~0x00000010); + maskingNonce_ = getDefaultInstance().getMaskingNonce(); + onChanged(); + return this; + } + + private com.google.protobuf.ByteString maskedResponse_ = com.google.protobuf.ByteString.EMPTY; + + /** + * + * + *
+       * The masked_response is the ciphertext containing the user's envelope.
+       * 
+ * + * bytes masked_response = 6; + * + * @return The maskedResponse. + */ + @java.lang.Override + public com.google.protobuf.ByteString getMaskedResponse() { + return maskedResponse_; + } + + /** + * + * + *
+       * The masked_response is the ciphertext containing the user's envelope.
+       * 
+ * + * bytes masked_response = 6; + * + * @param value The maskedResponse to set. + * @return This builder for chaining. + */ + public Builder setMaskedResponse(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + maskedResponse_ = value; + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + + /** + * + * + *
+       * The masked_response is the ciphertext containing the user's envelope.
+       * 
+ * + * bytes masked_response = 6; + * + * @return This builder for chaining. + */ + public Builder clearMaskedResponse() { + bitField0_ = (bitField0_ & ~0x00000020); + maskedResponse_ = getDefaultInstance().getMaskedResponse(); + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:google.spanner.auth.v1.InitialOpaqueLoginResponse) + } + + // @@protoc_insertion_point(class_scope:google.spanner.auth.v1.InitialOpaqueLoginResponse) + private static final com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse + DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse(); + } + + public static com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse + getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + @java.lang.Override + public InitialOpaqueLoginResponse parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException() + .setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse + getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + } + + public interface OpaqueLoginRequestOrBuilder + extends + // @@protoc_insertion_point(interface_extends:google.spanner.auth.v1.OpaqueLoginRequest) + com.google.protobuf.MessageOrBuilder { + + /** + * + * + *
+     * The initial request for OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginRequest initial_request = 1; + * + * @return Whether the initialRequest field is set. + */ + boolean hasInitialRequest(); + + /** + * + * + *
+     * The initial request for OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginRequest initial_request = 1; + * + * @return The initialRequest. + */ + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest getInitialRequest(); + + /** + * + * + *
+     * The initial request for OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginRequest initial_request = 1; + */ + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequestOrBuilder + getInitialRequestOrBuilder(); + + /** + * + * + *
+     * The final request for OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.FinalOpaqueLoginRequest final_request = 2; + * + * @return Whether the finalRequest field is set. + */ + boolean hasFinalRequest(); + + /** + * + * + *
+     * The final request for OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.FinalOpaqueLoginRequest final_request = 2; + * + * @return The finalRequest. + */ + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest getFinalRequest(); + + /** + * + * + *
+     * The final request for OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.FinalOpaqueLoginRequest final_request = 2; + */ + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequestOrBuilder getFinalRequestOrBuilder(); + + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.RequestCase getRequestCase(); + } + + /** + * + * + *
+   * OpaqueLoginRequest is used to authenticate the user using OPAQUE
+   * authentication.
+   * 
+ * + * Protobuf type {@code google.spanner.auth.v1.OpaqueLoginRequest} + */ + public static final class OpaqueLoginRequest extends com.google.protobuf.GeneratedMessage + implements + // @@protoc_insertion_point(message_implements:google.spanner.auth.v1.OpaqueLoginRequest) + OpaqueLoginRequestOrBuilder { + private static final long serialVersionUID = 0L; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 2, + /* suffix= */ "", + "OpaqueLoginRequest"); + } + + // Use OpaqueLoginRequest.newBuilder() to construct. + private OpaqueLoginRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + + private OpaqueLoginRequest() {} + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_OpaqueLoginRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_OpaqueLoginRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.class, + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.Builder.class); + } + + private int requestCase_ = 0; + + @SuppressWarnings("serial") + private java.lang.Object request_; + + public enum RequestCase + implements + com.google.protobuf.Internal.EnumLite, + com.google.protobuf.AbstractMessage.InternalOneOfEnum { + INITIAL_REQUEST(1), + FINAL_REQUEST(2), + REQUEST_NOT_SET(0); + private final int value; + + private RequestCase(int value) { + this.value = value; + } + + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static RequestCase valueOf(int value) { + return forNumber(value); + } + + public static RequestCase forNumber(int value) { + switch (value) { + case 1: + return INITIAL_REQUEST; + case 2: + return FINAL_REQUEST; + case 0: + return REQUEST_NOT_SET; + default: + return null; + } + } + + public int getNumber() { + return this.value; + } + }; + + public RequestCase getRequestCase() { + return RequestCase.forNumber(requestCase_); + } + + public static final int INITIAL_REQUEST_FIELD_NUMBER = 1; + + /** + * + * + *
+     * The initial request for OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginRequest initial_request = 1; + * + * @return Whether the initialRequest field is set. + */ + @java.lang.Override + public boolean hasInitialRequest() { + return requestCase_ == 1; + } + + /** + * + * + *
+     * The initial request for OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginRequest initial_request = 1; + * + * @return The initialRequest. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest getInitialRequest() { + if (requestCase_ == 1) { + return (com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest) request_; + } + return com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest.getDefaultInstance(); + } + + /** + * + * + *
+     * The initial request for OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginRequest initial_request = 1; + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequestOrBuilder + getInitialRequestOrBuilder() { + if (requestCase_ == 1) { + return (com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest) request_; + } + return com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest.getDefaultInstance(); + } + + public static final int FINAL_REQUEST_FIELD_NUMBER = 2; + + /** + * + * + *
+     * The final request for OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.FinalOpaqueLoginRequest final_request = 2; + * + * @return Whether the finalRequest field is set. + */ + @java.lang.Override + public boolean hasFinalRequest() { + return requestCase_ == 2; + } + + /** + * + * + *
+     * The final request for OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.FinalOpaqueLoginRequest final_request = 2; + * + * @return The finalRequest. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest getFinalRequest() { + if (requestCase_ == 2) { + return (com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest) request_; + } + return com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest.getDefaultInstance(); + } + + /** + * + * + *
+     * The final request for OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.FinalOpaqueLoginRequest final_request = 2; + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequestOrBuilder + getFinalRequestOrBuilder() { + if (requestCase_ == 2) { + return (com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest) request_; + } + return com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest.getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { + if (requestCase_ == 1) { + output.writeMessage( + 1, (com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest) request_); + } + if (requestCase_ == 2) { + output.writeMessage( + 2, (com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest) request_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (requestCase_ == 1) { + size += + com.google.protobuf.CodedOutputStream.computeMessageSize( + 1, (com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest) request_); + } + if (requestCase_ == 2) { + size += + com.google.protobuf.CodedOutputStream.computeMessageSize( + 2, (com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest) request_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.google.cloud.spanner.omni.Login.OpaqueLoginRequest)) { + return super.equals(obj); + } + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest other = + (com.google.cloud.spanner.omni.Login.OpaqueLoginRequest) obj; + + if (!getRequestCase().equals(other.getRequestCase())) return false; + switch (requestCase_) { + case 1: + if (!getInitialRequest().equals(other.getInitialRequest())) return false; + break; + case 2: + if (!getFinalRequest().equals(other.getFinalRequest())) return false; + break; + case 0: + default: + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + switch (requestCase_) { + case 1: + hash = (37 * hash) + INITIAL_REQUEST_FIELD_NUMBER; + hash = (53 * hash) + getInitialRequest().hashCode(); + break; + case 2: + hash = (37 * hash) + FINAL_REQUEST_FIELD_NUMBER; + hash = (53 * hash) + getFinalRequest().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginRequest parseFrom( + java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginRequest parseFrom( + java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginRequest parseFrom( + byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginRequest parseFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginRequest parseFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginRequest parseDelimitedFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginRequest parseDelimitedFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginRequest parseFrom( + com.google.protobuf.CodedInputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder( + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** + * + * + *
+     * OpaqueLoginRequest is used to authenticate the user using OPAQUE
+     * authentication.
+     * 
+ * + * Protobuf type {@code google.spanner.auth.v1.OpaqueLoginRequest} + */ + public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder + implements + // @@protoc_insertion_point(builder_implements:google.spanner.auth.v1.OpaqueLoginRequest) + com.google.cloud.spanner.omni.Login.OpaqueLoginRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_OpaqueLoginRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_OpaqueLoginRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.class, + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.Builder.class); + } + + // Construct using com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.newBuilder() + private Builder() {} + + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + } + + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + if (initialRequestBuilder_ != null) { + initialRequestBuilder_.clear(); + } + if (finalRequestBuilder_ != null) { + finalRequestBuilder_.clear(); + } + requestCase_ = 0; + request_ = null; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_OpaqueLoginRequest_descriptor; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginRequest getDefaultInstanceForType() { + return com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.getDefaultInstance(); + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginRequest build() { + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginRequest buildPartial() { + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest result = + new com.google.cloud.spanner.omni.Login.OpaqueLoginRequest(this); + if (bitField0_ != 0) { + buildPartial0(result); + } + buildPartialOneofs(result); + onBuilt(); + return result; + } + + private void buildPartial0(com.google.cloud.spanner.omni.Login.OpaqueLoginRequest result) { + int from_bitField0_ = bitField0_; + } + + private void buildPartialOneofs( + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest result) { + result.requestCase_ = requestCase_; + result.request_ = this.request_; + if (requestCase_ == 1 && initialRequestBuilder_ != null) { + result.request_ = initialRequestBuilder_.build(); + } + if (requestCase_ == 2 && finalRequestBuilder_ != null) { + result.request_ = finalRequestBuilder_.build(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.google.cloud.spanner.omni.Login.OpaqueLoginRequest) { + return mergeFrom((com.google.cloud.spanner.omni.Login.OpaqueLoginRequest) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(com.google.cloud.spanner.omni.Login.OpaqueLoginRequest other) { + if (other == com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.getDefaultInstance()) + return this; + switch (other.getRequestCase()) { + case INITIAL_REQUEST: + { + mergeInitialRequest(other.getInitialRequest()); + break; + } + case FINAL_REQUEST: + { + mergeFinalRequest(other.getFinalRequest()); + break; + } + case REQUEST_NOT_SET: + { + break; + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: + { + input.readMessage( + internalGetInitialRequestFieldBuilder().getBuilder(), extensionRegistry); + requestCase_ = 1; + break; + } // case 10 + case 18: + { + input.readMessage( + internalGetFinalRequestFieldBuilder().getBuilder(), extensionRegistry); + requestCase_ = 2; + break; + } // case 18 + default: + { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + private int requestCase_ = 0; + private java.lang.Object request_; + + public RequestCase getRequestCase() { + return RequestCase.forNumber(requestCase_); + } + + public Builder clearRequest() { + requestCase_ = 0; + request_ = null; + onChanged(); + return this; + } + + private int bitField0_; + + private com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest, + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest.Builder, + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequestOrBuilder> + initialRequestBuilder_; + + /** + * + * + *
+       * The initial request for OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginRequest initial_request = 1; + * + * @return Whether the initialRequest field is set. + */ + @java.lang.Override + public boolean hasInitialRequest() { + return requestCase_ == 1; + } + + /** + * + * + *
+       * The initial request for OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginRequest initial_request = 1; + * + * @return The initialRequest. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest getInitialRequest() { + if (initialRequestBuilder_ == null) { + if (requestCase_ == 1) { + return (com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest) request_; + } + return com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest.getDefaultInstance(); + } else { + if (requestCase_ == 1) { + return initialRequestBuilder_.getMessage(); + } + return com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest.getDefaultInstance(); + } + } + + /** + * + * + *
+       * The initial request for OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginRequest initial_request = 1; + */ + public Builder setInitialRequest( + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest value) { + if (initialRequestBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + request_ = value; + onChanged(); + } else { + initialRequestBuilder_.setMessage(value); + } + requestCase_ = 1; + return this; + } + + /** + * + * + *
+       * The initial request for OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginRequest initial_request = 1; + */ + public Builder setInitialRequest( + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest.Builder builderForValue) { + if (initialRequestBuilder_ == null) { + request_ = builderForValue.build(); + onChanged(); + } else { + initialRequestBuilder_.setMessage(builderForValue.build()); + } + requestCase_ = 1; + return this; + } + + /** + * + * + *
+       * The initial request for OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginRequest initial_request = 1; + */ + public Builder mergeInitialRequest( + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest value) { + if (initialRequestBuilder_ == null) { + if (requestCase_ == 1 + && request_ + != com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest + .getDefaultInstance()) { + request_ = + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest.newBuilder( + (com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest) request_) + .mergeFrom(value) + .buildPartial(); + } else { + request_ = value; + } + onChanged(); + } else { + if (requestCase_ == 1) { + initialRequestBuilder_.mergeFrom(value); + } else { + initialRequestBuilder_.setMessage(value); + } + } + requestCase_ = 1; + return this; + } + + /** + * + * + *
+       * The initial request for OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginRequest initial_request = 1; + */ + public Builder clearInitialRequest() { + if (initialRequestBuilder_ == null) { + if (requestCase_ == 1) { + requestCase_ = 0; + request_ = null; + onChanged(); + } + } else { + if (requestCase_ == 1) { + requestCase_ = 0; + request_ = null; + } + initialRequestBuilder_.clear(); + } + return this; + } + + /** + * + * + *
+       * The initial request for OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginRequest initial_request = 1; + */ + public com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest.Builder + getInitialRequestBuilder() { + return internalGetInitialRequestFieldBuilder().getBuilder(); + } + + /** + * + * + *
+       * The initial request for OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginRequest initial_request = 1; + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequestOrBuilder + getInitialRequestOrBuilder() { + if ((requestCase_ == 1) && (initialRequestBuilder_ != null)) { + return initialRequestBuilder_.getMessageOrBuilder(); + } else { + if (requestCase_ == 1) { + return (com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest) request_; + } + return com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest.getDefaultInstance(); + } + } + + /** + * + * + *
+       * The initial request for OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginRequest initial_request = 1; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest, + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest.Builder, + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequestOrBuilder> + internalGetInitialRequestFieldBuilder() { + if (initialRequestBuilder_ == null) { + if (!(requestCase_ == 1)) { + request_ = + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest.getDefaultInstance(); + } + initialRequestBuilder_ = + new com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest, + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest.Builder, + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequestOrBuilder>( + (com.google.cloud.spanner.omni.Login.InitialOpaqueLoginRequest) request_, + getParentForChildren(), + isClean()); + request_ = null; + } + requestCase_ = 1; + onChanged(); + return initialRequestBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest, + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest.Builder, + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequestOrBuilder> + finalRequestBuilder_; + + /** + * + * + *
+       * The final request for OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.FinalOpaqueLoginRequest final_request = 2; + * + * @return Whether the finalRequest field is set. + */ + @java.lang.Override + public boolean hasFinalRequest() { + return requestCase_ == 2; + } + + /** + * + * + *
+       * The final request for OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.FinalOpaqueLoginRequest final_request = 2; + * + * @return The finalRequest. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest getFinalRequest() { + if (finalRequestBuilder_ == null) { + if (requestCase_ == 2) { + return (com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest) request_; + } + return com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest.getDefaultInstance(); + } else { + if (requestCase_ == 2) { + return finalRequestBuilder_.getMessage(); + } + return com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest.getDefaultInstance(); + } + } + + /** + * + * + *
+       * The final request for OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.FinalOpaqueLoginRequest final_request = 2; + */ + public Builder setFinalRequest( + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest value) { + if (finalRequestBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + request_ = value; + onChanged(); + } else { + finalRequestBuilder_.setMessage(value); + } + requestCase_ = 2; + return this; + } + + /** + * + * + *
+       * The final request for OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.FinalOpaqueLoginRequest final_request = 2; + */ + public Builder setFinalRequest( + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest.Builder builderForValue) { + if (finalRequestBuilder_ == null) { + request_ = builderForValue.build(); + onChanged(); + } else { + finalRequestBuilder_.setMessage(builderForValue.build()); + } + requestCase_ = 2; + return this; + } + + /** + * + * + *
+       * The final request for OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.FinalOpaqueLoginRequest final_request = 2; + */ + public Builder mergeFinalRequest( + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest value) { + if (finalRequestBuilder_ == null) { + if (requestCase_ == 2 + && request_ + != com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest + .getDefaultInstance()) { + request_ = + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest.newBuilder( + (com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest) request_) + .mergeFrom(value) + .buildPartial(); + } else { + request_ = value; + } + onChanged(); + } else { + if (requestCase_ == 2) { + finalRequestBuilder_.mergeFrom(value); + } else { + finalRequestBuilder_.setMessage(value); + } + } + requestCase_ = 2; + return this; + } + + /** + * + * + *
+       * The final request for OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.FinalOpaqueLoginRequest final_request = 2; + */ + public Builder clearFinalRequest() { + if (finalRequestBuilder_ == null) { + if (requestCase_ == 2) { + requestCase_ = 0; + request_ = null; + onChanged(); + } + } else { + if (requestCase_ == 2) { + requestCase_ = 0; + request_ = null; + } + finalRequestBuilder_.clear(); + } + return this; + } + + /** + * + * + *
+       * The final request for OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.FinalOpaqueLoginRequest final_request = 2; + */ + public com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest.Builder + getFinalRequestBuilder() { + return internalGetFinalRequestFieldBuilder().getBuilder(); + } + + /** + * + * + *
+       * The final request for OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.FinalOpaqueLoginRequest final_request = 2; + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequestOrBuilder + getFinalRequestOrBuilder() { + if ((requestCase_ == 2) && (finalRequestBuilder_ != null)) { + return finalRequestBuilder_.getMessageOrBuilder(); + } else { + if (requestCase_ == 2) { + return (com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest) request_; + } + return com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest.getDefaultInstance(); + } + } + + /** + * + * + *
+       * The final request for OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.FinalOpaqueLoginRequest final_request = 2; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest, + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest.Builder, + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequestOrBuilder> + internalGetFinalRequestFieldBuilder() { + if (finalRequestBuilder_ == null) { + if (!(requestCase_ == 2)) { + request_ = + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest.getDefaultInstance(); + } + finalRequestBuilder_ = + new com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest, + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest.Builder, + com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequestOrBuilder>( + (com.google.cloud.spanner.omni.Login.FinalOpaqueLoginRequest) request_, + getParentForChildren(), + isClean()); + request_ = null; + } + requestCase_ = 2; + onChanged(); + return finalRequestBuilder_; + } + + // @@protoc_insertion_point(builder_scope:google.spanner.auth.v1.OpaqueLoginRequest) + } + + // @@protoc_insertion_point(class_scope:google.spanner.auth.v1.OpaqueLoginRequest) + private static final com.google.cloud.spanner.omni.Login.OpaqueLoginRequest DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new com.google.cloud.spanner.omni.Login.OpaqueLoginRequest(); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + @java.lang.Override + public OpaqueLoginRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException() + .setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + } + + public interface OpaqueLoginResponseOrBuilder + extends + // @@protoc_insertion_point(interface_extends:google.spanner.auth.v1.OpaqueLoginResponse) + com.google.protobuf.MessageOrBuilder { + + /** + * + * + *
+     * The initial response from the server when using OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginResponse initial_response = 1; + * + * @return Whether the initialResponse field is set. + */ + boolean hasInitialResponse(); + + /** + * + * + *
+     * The initial response from the server when using OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginResponse initial_response = 1; + * + * @return The initialResponse. + */ + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse getInitialResponse(); + + /** + * + * + *
+     * The initial response from the server when using OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginResponse initial_response = 1; + */ + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponseOrBuilder + getInitialResponseOrBuilder(); + + /** + * + * + *
+     * The final response from the server when using OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse final_response = 2; + * + * @return Whether the finalResponse field is set. + */ + boolean hasFinalResponse(); + + /** + * + * + *
+     * The final response from the server when using OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse final_response = 2; + * + * @return The finalResponse. + */ + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse getFinalResponse(); + + /** + * + * + *
+     * The final response from the server when using OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse final_response = 2; + */ + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponseOrBuilder + getFinalResponseOrBuilder(); + + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.ResponseCase getResponseCase(); + } + + /** + * + * + *
+   * OpaqueLoginResponse is returned by the server when the user is using OPAQUE
+   * authentication.
+   * 
+ * + * Protobuf type {@code google.spanner.auth.v1.OpaqueLoginResponse} + */ + public static final class OpaqueLoginResponse extends com.google.protobuf.GeneratedMessage + implements + // @@protoc_insertion_point(message_implements:google.spanner.auth.v1.OpaqueLoginResponse) + OpaqueLoginResponseOrBuilder { + private static final long serialVersionUID = 0L; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 2, + /* suffix= */ "", + "OpaqueLoginResponse"); + } + + // Use OpaqueLoginResponse.newBuilder() to construct. + private OpaqueLoginResponse(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + + private OpaqueLoginResponse() {} + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_OpaqueLoginResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_OpaqueLoginResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.class, + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.Builder.class); + } + + public interface FinalResponseOrBuilder + extends + // @@protoc_insertion_point(interface_extends:google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse) + com.google.protobuf.MessageOrBuilder {} + + /** + * + * + *
+     * The final response from the server when using OPAQUE authentication.
+     * 
+ * + * Protobuf type {@code google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse} + */ + public static final class FinalResponse extends com.google.protobuf.GeneratedMessage + implements + // @@protoc_insertion_point(message_implements:google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse) + FinalResponseOrBuilder { + private static final long serialVersionUID = 0L; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 2, + /* suffix= */ "", + "FinalResponse"); + } + + // Use FinalResponse.newBuilder() to construct. + private FinalResponse(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + + private FinalResponse() {} + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_OpaqueLoginResponse_FinalResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_OpaqueLoginResponse_FinalResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse.class, + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse.Builder + .class); + } + + private byte memoizedIsInitialized = -1; + + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj + instanceof com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse)) { + return super.equals(obj); + } + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse other = + (com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse) obj; + + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse parseFrom( + java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse parseFrom( + java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse parseFrom( + byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse parseFrom( + byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse parseFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse parseFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse + parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse + parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse parseFrom( + com.google.protobuf.CodedInputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder( + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** + * + * + *
+       * The final response from the server when using OPAQUE authentication.
+       * 
+ * + * Protobuf type {@code google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse} + */ + public static final class Builder + extends com.google.protobuf.GeneratedMessage.Builder + implements + // @@protoc_insertion_point(builder_implements:google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse) + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponseOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_OpaqueLoginResponse_FinalResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_OpaqueLoginResponse_FinalResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse.class, + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse.Builder + .class); + } + + // Construct using + // com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse.newBuilder() + private Builder() {} + + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + } + + @java.lang.Override + public Builder clear() { + super.clear(); + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_OpaqueLoginResponse_FinalResponse_descriptor; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse + getDefaultInstanceForType() { + return com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse + .getDefaultInstance(); + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse build() { + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse result = + buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse + buildPartial() { + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse result = + new com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse(this); + onBuilt(); + return result; + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other + instanceof com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse) { + return mergeFrom( + (com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom( + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse other) { + if (other + == com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse + .getDefaultInstance()) return this; + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: + { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + // @@protoc_insertion_point(builder_scope:google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse) + } + + // @@protoc_insertion_point(class_scope:google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse) + private static final com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse + DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = + new com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse(); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse + getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + @java.lang.Override + public FinalResponse parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException() + .setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse + getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + } + + private int responseCase_ = 0; + + @SuppressWarnings("serial") + private java.lang.Object response_; + + public enum ResponseCase + implements + com.google.protobuf.Internal.EnumLite, + com.google.protobuf.AbstractMessage.InternalOneOfEnum { + INITIAL_RESPONSE(1), + FINAL_RESPONSE(2), + RESPONSE_NOT_SET(0); + private final int value; + + private ResponseCase(int value) { + this.value = value; + } + + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static ResponseCase valueOf(int value) { + return forNumber(value); + } + + public static ResponseCase forNumber(int value) { + switch (value) { + case 1: + return INITIAL_RESPONSE; + case 2: + return FINAL_RESPONSE; + case 0: + return RESPONSE_NOT_SET; + default: + return null; + } + } + + public int getNumber() { + return this.value; + } + }; + + public ResponseCase getResponseCase() { + return ResponseCase.forNumber(responseCase_); + } + + public static final int INITIAL_RESPONSE_FIELD_NUMBER = 1; + + /** + * + * + *
+     * The initial response from the server when using OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginResponse initial_response = 1; + * + * @return Whether the initialResponse field is set. + */ + @java.lang.Override + public boolean hasInitialResponse() { + return responseCase_ == 1; + } + + /** + * + * + *
+     * The initial response from the server when using OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginResponse initial_response = 1; + * + * @return The initialResponse. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse getInitialResponse() { + if (responseCase_ == 1) { + return (com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse) response_; + } + return com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse.getDefaultInstance(); + } + + /** + * + * + *
+     * The initial response from the server when using OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginResponse initial_response = 1; + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponseOrBuilder + getInitialResponseOrBuilder() { + if (responseCase_ == 1) { + return (com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse) response_; + } + return com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse.getDefaultInstance(); + } + + public static final int FINAL_RESPONSE_FIELD_NUMBER = 2; + + /** + * + * + *
+     * The final response from the server when using OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse final_response = 2; + * + * @return Whether the finalResponse field is set. + */ + @java.lang.Override + public boolean hasFinalResponse() { + return responseCase_ == 2; + } + + /** + * + * + *
+     * The final response from the server when using OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse final_response = 2; + * + * @return The finalResponse. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse + getFinalResponse() { + if (responseCase_ == 2) { + return (com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse) response_; + } + return com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse + .getDefaultInstance(); + } + + /** + * + * + *
+     * The final response from the server when using OPAQUE authentication.
+     * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse final_response = 2; + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponseOrBuilder + getFinalResponseOrBuilder() { + if (responseCase_ == 2) { + return (com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse) response_; + } + return com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse + .getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { + if (responseCase_ == 1) { + output.writeMessage( + 1, (com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse) response_); + } + if (responseCase_ == 2) { + output.writeMessage( + 2, (com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse) response_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (responseCase_ == 1) { + size += + com.google.protobuf.CodedOutputStream.computeMessageSize( + 1, (com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse) response_); + } + if (responseCase_ == 2) { + size += + com.google.protobuf.CodedOutputStream.computeMessageSize( + 2, + (com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse) response_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.google.cloud.spanner.omni.Login.OpaqueLoginResponse)) { + return super.equals(obj); + } + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse other = + (com.google.cloud.spanner.omni.Login.OpaqueLoginResponse) obj; + + if (!getResponseCase().equals(other.getResponseCase())) return false; + switch (responseCase_) { + case 1: + if (!getInitialResponse().equals(other.getInitialResponse())) return false; + break; + case 2: + if (!getFinalResponse().equals(other.getFinalResponse())) return false; + break; + case 0: + default: + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + switch (responseCase_) { + case 1: + hash = (37 * hash) + INITIAL_RESPONSE_FIELD_NUMBER; + hash = (53 * hash) + getInitialResponse().hashCode(); + break; + case 2: + hash = (37 * hash) + FINAL_RESPONSE_FIELD_NUMBER; + hash = (53 * hash) + getFinalResponse().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse parseFrom( + java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse parseFrom( + java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse parseFrom( + byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse parseFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse parseFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse parseDelimitedFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse parseDelimitedFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse parseFrom( + com.google.protobuf.CodedInputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder( + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** + * + * + *
+     * OpaqueLoginResponse is returned by the server when the user is using OPAQUE
+     * authentication.
+     * 
+ * + * Protobuf type {@code google.spanner.auth.v1.OpaqueLoginResponse} + */ + public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder + implements + // @@protoc_insertion_point(builder_implements:google.spanner.auth.v1.OpaqueLoginResponse) + com.google.cloud.spanner.omni.Login.OpaqueLoginResponseOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_OpaqueLoginResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_OpaqueLoginResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.class, + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.Builder.class); + } + + // Construct using com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.newBuilder() + private Builder() {} + + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + } + + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + if (initialResponseBuilder_ != null) { + initialResponseBuilder_.clear(); + } + if (finalResponseBuilder_ != null) { + finalResponseBuilder_.clear(); + } + responseCase_ = 0; + response_ = null; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_OpaqueLoginResponse_descriptor; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginResponse getDefaultInstanceForType() { + return com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.getDefaultInstance(); + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginResponse build() { + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginResponse buildPartial() { + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse result = + new com.google.cloud.spanner.omni.Login.OpaqueLoginResponse(this); + if (bitField0_ != 0) { + buildPartial0(result); + } + buildPartialOneofs(result); + onBuilt(); + return result; + } + + private void buildPartial0(com.google.cloud.spanner.omni.Login.OpaqueLoginResponse result) { + int from_bitField0_ = bitField0_; + } + + private void buildPartialOneofs( + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse result) { + result.responseCase_ = responseCase_; + result.response_ = this.response_; + if (responseCase_ == 1 && initialResponseBuilder_ != null) { + result.response_ = initialResponseBuilder_.build(); + } + if (responseCase_ == 2 && finalResponseBuilder_ != null) { + result.response_ = finalResponseBuilder_.build(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.google.cloud.spanner.omni.Login.OpaqueLoginResponse) { + return mergeFrom((com.google.cloud.spanner.omni.Login.OpaqueLoginResponse) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(com.google.cloud.spanner.omni.Login.OpaqueLoginResponse other) { + if (other == com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.getDefaultInstance()) + return this; + switch (other.getResponseCase()) { + case INITIAL_RESPONSE: + { + mergeInitialResponse(other.getInitialResponse()); + break; + } + case FINAL_RESPONSE: + { + mergeFinalResponse(other.getFinalResponse()); + break; + } + case RESPONSE_NOT_SET: + { + break; + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: + { + input.readMessage( + internalGetInitialResponseFieldBuilder().getBuilder(), extensionRegistry); + responseCase_ = 1; + break; + } // case 10 + case 18: + { + input.readMessage( + internalGetFinalResponseFieldBuilder().getBuilder(), extensionRegistry); + responseCase_ = 2; + break; + } // case 18 + default: + { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + private int responseCase_ = 0; + private java.lang.Object response_; + + public ResponseCase getResponseCase() { + return ResponseCase.forNumber(responseCase_); + } + + public Builder clearResponse() { + responseCase_ = 0; + response_ = null; + onChanged(); + return this; + } + + private int bitField0_; + + private com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse, + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse.Builder, + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponseOrBuilder> + initialResponseBuilder_; + + /** + * + * + *
+       * The initial response from the server when using OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginResponse initial_response = 1; + * + * @return Whether the initialResponse field is set. + */ + @java.lang.Override + public boolean hasInitialResponse() { + return responseCase_ == 1; + } + + /** + * + * + *
+       * The initial response from the server when using OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginResponse initial_response = 1; + * + * @return The initialResponse. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse getInitialResponse() { + if (initialResponseBuilder_ == null) { + if (responseCase_ == 1) { + return (com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse) response_; + } + return com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse + .getDefaultInstance(); + } else { + if (responseCase_ == 1) { + return initialResponseBuilder_.getMessage(); + } + return com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse + .getDefaultInstance(); + } + } + + /** + * + * + *
+       * The initial response from the server when using OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginResponse initial_response = 1; + */ + public Builder setInitialResponse( + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse value) { + if (initialResponseBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + response_ = value; + onChanged(); + } else { + initialResponseBuilder_.setMessage(value); + } + responseCase_ = 1; + return this; + } + + /** + * + * + *
+       * The initial response from the server when using OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginResponse initial_response = 1; + */ + public Builder setInitialResponse( + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse.Builder builderForValue) { + if (initialResponseBuilder_ == null) { + response_ = builderForValue.build(); + onChanged(); + } else { + initialResponseBuilder_.setMessage(builderForValue.build()); + } + responseCase_ = 1; + return this; + } + + /** + * + * + *
+       * The initial response from the server when using OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginResponse initial_response = 1; + */ + public Builder mergeInitialResponse( + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse value) { + if (initialResponseBuilder_ == null) { + if (responseCase_ == 1 + && response_ + != com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse + .getDefaultInstance()) { + response_ = + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse.newBuilder( + (com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse) response_) + .mergeFrom(value) + .buildPartial(); + } else { + response_ = value; + } + onChanged(); + } else { + if (responseCase_ == 1) { + initialResponseBuilder_.mergeFrom(value); + } else { + initialResponseBuilder_.setMessage(value); + } + } + responseCase_ = 1; + return this; + } + + /** + * + * + *
+       * The initial response from the server when using OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginResponse initial_response = 1; + */ + public Builder clearInitialResponse() { + if (initialResponseBuilder_ == null) { + if (responseCase_ == 1) { + responseCase_ = 0; + response_ = null; + onChanged(); + } + } else { + if (responseCase_ == 1) { + responseCase_ = 0; + response_ = null; + } + initialResponseBuilder_.clear(); + } + return this; + } + + /** + * + * + *
+       * The initial response from the server when using OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginResponse initial_response = 1; + */ + public com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse.Builder + getInitialResponseBuilder() { + return internalGetInitialResponseFieldBuilder().getBuilder(); + } + + /** + * + * + *
+       * The initial response from the server when using OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginResponse initial_response = 1; + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponseOrBuilder + getInitialResponseOrBuilder() { + if ((responseCase_ == 1) && (initialResponseBuilder_ != null)) { + return initialResponseBuilder_.getMessageOrBuilder(); + } else { + if (responseCase_ == 1) { + return (com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse) response_; + } + return com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse + .getDefaultInstance(); + } + } + + /** + * + * + *
+       * The initial response from the server when using OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.InitialOpaqueLoginResponse initial_response = 1; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse, + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse.Builder, + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponseOrBuilder> + internalGetInitialResponseFieldBuilder() { + if (initialResponseBuilder_ == null) { + if (!(responseCase_ == 1)) { + response_ = + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse.getDefaultInstance(); + } + initialResponseBuilder_ = + new com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse, + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse.Builder, + com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponseOrBuilder>( + (com.google.cloud.spanner.omni.Login.InitialOpaqueLoginResponse) response_, + getParentForChildren(), + isClean()); + response_ = null; + } + responseCase_ = 1; + onChanged(); + return initialResponseBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse, + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse.Builder, + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponseOrBuilder> + finalResponseBuilder_; + + /** + * + * + *
+       * The final response from the server when using OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse final_response = 2; + * + * @return Whether the finalResponse field is set. + */ + @java.lang.Override + public boolean hasFinalResponse() { + return responseCase_ == 2; + } + + /** + * + * + *
+       * The final response from the server when using OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse final_response = 2; + * + * @return The finalResponse. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse + getFinalResponse() { + if (finalResponseBuilder_ == null) { + if (responseCase_ == 2) { + return (com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse) + response_; + } + return com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse + .getDefaultInstance(); + } else { + if (responseCase_ == 2) { + return finalResponseBuilder_.getMessage(); + } + return com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse + .getDefaultInstance(); + } + } + + /** + * + * + *
+       * The final response from the server when using OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse final_response = 2; + */ + public Builder setFinalResponse( + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse value) { + if (finalResponseBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + response_ = value; + onChanged(); + } else { + finalResponseBuilder_.setMessage(value); + } + responseCase_ = 2; + return this; + } + + /** + * + * + *
+       * The final response from the server when using OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse final_response = 2; + */ + public Builder setFinalResponse( + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse.Builder + builderForValue) { + if (finalResponseBuilder_ == null) { + response_ = builderForValue.build(); + onChanged(); + } else { + finalResponseBuilder_.setMessage(builderForValue.build()); + } + responseCase_ = 2; + return this; + } + + /** + * + * + *
+       * The final response from the server when using OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse final_response = 2; + */ + public Builder mergeFinalResponse( + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse value) { + if (finalResponseBuilder_ == null) { + if (responseCase_ == 2 + && response_ + != com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse + .getDefaultInstance()) { + response_ = + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse.newBuilder( + (com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse) + response_) + .mergeFrom(value) + .buildPartial(); + } else { + response_ = value; + } + onChanged(); + } else { + if (responseCase_ == 2) { + finalResponseBuilder_.mergeFrom(value); + } else { + finalResponseBuilder_.setMessage(value); + } + } + responseCase_ = 2; + return this; + } + + /** + * + * + *
+       * The final response from the server when using OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse final_response = 2; + */ + public Builder clearFinalResponse() { + if (finalResponseBuilder_ == null) { + if (responseCase_ == 2) { + responseCase_ = 0; + response_ = null; + onChanged(); + } + } else { + if (responseCase_ == 2) { + responseCase_ = 0; + response_ = null; + } + finalResponseBuilder_.clear(); + } + return this; + } + + /** + * + * + *
+       * The final response from the server when using OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse final_response = 2; + */ + public com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse.Builder + getFinalResponseBuilder() { + return internalGetFinalResponseFieldBuilder().getBuilder(); + } + + /** + * + * + *
+       * The final response from the server when using OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse final_response = 2; + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponseOrBuilder + getFinalResponseOrBuilder() { + if ((responseCase_ == 2) && (finalResponseBuilder_ != null)) { + return finalResponseBuilder_.getMessageOrBuilder(); + } else { + if (responseCase_ == 2) { + return (com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse) + response_; + } + return com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse + .getDefaultInstance(); + } + } + + /** + * + * + *
+       * The final response from the server when using OPAQUE authentication.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse.FinalResponse final_response = 2; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse, + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse.Builder, + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponseOrBuilder> + internalGetFinalResponseFieldBuilder() { + if (finalResponseBuilder_ == null) { + if (!(responseCase_ == 2)) { + response_ = + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse + .getDefaultInstance(); + } + finalResponseBuilder_ = + new com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse, + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse.Builder, + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponseOrBuilder>( + (com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.FinalResponse) response_, + getParentForChildren(), + isClean()); + response_ = null; + } + responseCase_ = 2; + onChanged(); + return finalResponseBuilder_; + } + + // @@protoc_insertion_point(builder_scope:google.spanner.auth.v1.OpaqueLoginResponse) + } + + // @@protoc_insertion_point(class_scope:google.spanner.auth.v1.OpaqueLoginResponse) + private static final com.google.cloud.spanner.omni.Login.OpaqueLoginResponse DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new com.google.cloud.spanner.omni.Login.OpaqueLoginResponse(); + } + + public static com.google.cloud.spanner.omni.Login.OpaqueLoginResponse getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + @java.lang.Override + public OpaqueLoginResponse parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException() + .setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginResponse getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + } + + public interface LoginRequestOrBuilder + extends + // @@protoc_insertion_point(interface_extends:google.spanner.auth.v1.LoginRequest) + com.google.protobuf.MessageOrBuilder { + + /** + * + * + *
+     * The username of the user to log in.
+     * 
+ * + * string username = 1; + * + * @return The username. + */ + java.lang.String getUsername(); + + /** + * + * + *
+     * The username of the user to log in.
+     * 
+ * + * string username = 1; + * + * @return The bytes for username. + */ + com.google.protobuf.ByteString getUsernameBytes(); + + /** + * + * + *
+     * OPAQUE authentication as defined in rfc9807.
+     * 
+ * + * .google.spanner.auth.v1.OpaqueLoginRequest opaque_request = 4; + * + * @return Whether the opaqueRequest field is set. + */ + boolean hasOpaqueRequest(); + + /** + * + * + *
+     * OPAQUE authentication as defined in rfc9807.
+     * 
+ * + * .google.spanner.auth.v1.OpaqueLoginRequest opaque_request = 4; + * + * @return The opaqueRequest. + */ + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest getOpaqueRequest(); + + /** + * + * + *
+     * OPAQUE authentication as defined in rfc9807.
+     * 
+ * + * .google.spanner.auth.v1.OpaqueLoginRequest opaque_request = 4; + */ + com.google.cloud.spanner.omni.Login.OpaqueLoginRequestOrBuilder getOpaqueRequestOrBuilder(); + + /** + * + * + *
+     * Handshake request for the client to determine how to authenticate.
+     * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeRequest handshake_request = 5; + * + * @return Whether the handshakeRequest field is set. + */ + boolean hasHandshakeRequest(); + + /** + * + * + *
+     * Handshake request for the client to determine how to authenticate.
+     * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeRequest handshake_request = 5; + * + * @return The handshakeRequest. + */ + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest getHandshakeRequest(); + + /** + * + * + *
+     * Handshake request for the client to determine how to authenticate.
+     * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeRequest handshake_request = 5; + */ + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequestOrBuilder + getHandshakeRequestOrBuilder(); + + com.google.cloud.spanner.omni.Login.LoginRequest.RequestCase getRequestCase(); + } + + /** + * + * + *
+   * LoginRequest is used to authenticate the user, and if successful, return an
+   * access token.
+   * 
+ * + * Protobuf type {@code google.spanner.auth.v1.LoginRequest} + */ + public static final class LoginRequest extends com.google.protobuf.GeneratedMessage + implements + // @@protoc_insertion_point(message_implements:google.spanner.auth.v1.LoginRequest) + LoginRequestOrBuilder { + private static final long serialVersionUID = 0L; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 2, + /* suffix= */ "", + "LoginRequest"); + } + + // Use LoginRequest.newBuilder() to construct. + private LoginRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + + private LoginRequest() { + username_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_LoginRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_LoginRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.LoginRequest.class, + com.google.cloud.spanner.omni.Login.LoginRequest.Builder.class); + } + + private int requestCase_ = 0; + + @SuppressWarnings("serial") + private java.lang.Object request_; + + public enum RequestCase + implements + com.google.protobuf.Internal.EnumLite, + com.google.protobuf.AbstractMessage.InternalOneOfEnum { + OPAQUE_REQUEST(4), + HANDSHAKE_REQUEST(5), + REQUEST_NOT_SET(0); + private final int value; + + private RequestCase(int value) { + this.value = value; + } + + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static RequestCase valueOf(int value) { + return forNumber(value); + } + + public static RequestCase forNumber(int value) { + switch (value) { + case 4: + return OPAQUE_REQUEST; + case 5: + return HANDSHAKE_REQUEST; + case 0: + return REQUEST_NOT_SET; + default: + return null; + } + } + + public int getNumber() { + return this.value; + } + }; + + public RequestCase getRequestCase() { + return RequestCase.forNumber(requestCase_); + } + + public static final int USERNAME_FIELD_NUMBER = 1; + + @SuppressWarnings("serial") + private volatile java.lang.Object username_ = ""; + + /** + * + * + *
+     * The username of the user to log in.
+     * 
+ * + * string username = 1; + * + * @return The username. + */ + @java.lang.Override + public java.lang.String getUsername() { + java.lang.Object ref = username_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + username_ = s; + return s; + } + } + + /** + * + * + *
+     * The username of the user to log in.
+     * 
+ * + * string username = 1; + * + * @return The bytes for username. + */ + @java.lang.Override + public com.google.protobuf.ByteString getUsernameBytes() { + java.lang.Object ref = username_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref); + username_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int OPAQUE_REQUEST_FIELD_NUMBER = 4; + + /** + * + * + *
+     * OPAQUE authentication as defined in rfc9807.
+     * 
+ * + * .google.spanner.auth.v1.OpaqueLoginRequest opaque_request = 4; + * + * @return Whether the opaqueRequest field is set. + */ + @java.lang.Override + public boolean hasOpaqueRequest() { + return requestCase_ == 4; + } + + /** + * + * + *
+     * OPAQUE authentication as defined in rfc9807.
+     * 
+ * + * .google.spanner.auth.v1.OpaqueLoginRequest opaque_request = 4; + * + * @return The opaqueRequest. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginRequest getOpaqueRequest() { + if (requestCase_ == 4) { + return (com.google.cloud.spanner.omni.Login.OpaqueLoginRequest) request_; + } + return com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.getDefaultInstance(); + } + + /** + * + * + *
+     * OPAQUE authentication as defined in rfc9807.
+     * 
+ * + * .google.spanner.auth.v1.OpaqueLoginRequest opaque_request = 4; + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginRequestOrBuilder + getOpaqueRequestOrBuilder() { + if (requestCase_ == 4) { + return (com.google.cloud.spanner.omni.Login.OpaqueLoginRequest) request_; + } + return com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.getDefaultInstance(); + } + + public static final int HANDSHAKE_REQUEST_FIELD_NUMBER = 5; + + /** + * + * + *
+     * Handshake request for the client to determine how to authenticate.
+     * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeRequest handshake_request = 5; + * + * @return Whether the handshakeRequest field is set. + */ + @java.lang.Override + public boolean hasHandshakeRequest() { + return requestCase_ == 5; + } + + /** + * + * + *
+     * Handshake request for the client to determine how to authenticate.
+     * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeRequest handshake_request = 5; + * + * @return The handshakeRequest. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest + getHandshakeRequest() { + if (requestCase_ == 5) { + return (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest) request_; + } + return com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest + .getDefaultInstance(); + } + + /** + * + * + *
+     * Handshake request for the client to determine how to authenticate.
+     * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeRequest handshake_request = 5; + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequestOrBuilder + getHandshakeRequestOrBuilder() { + if (requestCase_ == 5) { + return (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest) request_; + } + return com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest + .getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(username_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, username_); + } + if (requestCase_ == 4) { + output.writeMessage(4, (com.google.cloud.spanner.omni.Login.OpaqueLoginRequest) request_); + } + if (requestCase_ == 5) { + output.writeMessage( + 5, (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest) request_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(username_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, username_); + } + if (requestCase_ == 4) { + size += + com.google.protobuf.CodedOutputStream.computeMessageSize( + 4, (com.google.cloud.spanner.omni.Login.OpaqueLoginRequest) request_); + } + if (requestCase_ == 5) { + size += + com.google.protobuf.CodedOutputStream.computeMessageSize( + 5, (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest) request_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.google.cloud.spanner.omni.Login.LoginRequest)) { + return super.equals(obj); + } + com.google.cloud.spanner.omni.Login.LoginRequest other = + (com.google.cloud.spanner.omni.Login.LoginRequest) obj; + + if (!getUsername().equals(other.getUsername())) return false; + if (!getRequestCase().equals(other.getRequestCase())) return false; + switch (requestCase_) { + case 4: + if (!getOpaqueRequest().equals(other.getOpaqueRequest())) return false; + break; + case 5: + if (!getHandshakeRequest().equals(other.getHandshakeRequest())) return false; + break; + case 0: + default: + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + USERNAME_FIELD_NUMBER; + hash = (53 * hash) + getUsername().hashCode(); + switch (requestCase_) { + case 4: + hash = (37 * hash) + OPAQUE_REQUEST_FIELD_NUMBER; + hash = (53 * hash) + getOpaqueRequest().hashCode(); + break; + case 5: + hash = (37 * hash) + HANDSHAKE_REQUEST_FIELD_NUMBER; + hash = (53 * hash) + getHandshakeRequest().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.google.cloud.spanner.omni.Login.LoginRequest parseFrom( + java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.LoginRequest parseFrom( + java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.LoginRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.LoginRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.LoginRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.LoginRequest parseFrom( + byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.LoginRequest parseFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.LoginRequest parseFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.LoginRequest parseDelimitedFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.LoginRequest parseDelimitedFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.LoginRequest parseFrom( + com.google.protobuf.CodedInputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.LoginRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(com.google.cloud.spanner.omni.Login.LoginRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** + * + * + *
+     * LoginRequest is used to authenticate the user, and if successful, return an
+     * access token.
+     * 
+ * + * Protobuf type {@code google.spanner.auth.v1.LoginRequest} + */ + public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder + implements + // @@protoc_insertion_point(builder_implements:google.spanner.auth.v1.LoginRequest) + com.google.cloud.spanner.omni.Login.LoginRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_LoginRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_LoginRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.LoginRequest.class, + com.google.cloud.spanner.omni.Login.LoginRequest.Builder.class); + } + + // Construct using com.google.cloud.spanner.omni.Login.LoginRequest.newBuilder() + private Builder() {} + + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + } + + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + username_ = ""; + if (opaqueRequestBuilder_ != null) { + opaqueRequestBuilder_.clear(); + } + if (handshakeRequestBuilder_ != null) { + handshakeRequestBuilder_.clear(); + } + requestCase_ = 0; + request_ = null; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_LoginRequest_descriptor; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.LoginRequest getDefaultInstanceForType() { + return com.google.cloud.spanner.omni.Login.LoginRequest.getDefaultInstance(); + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.LoginRequest build() { + com.google.cloud.spanner.omni.Login.LoginRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.LoginRequest buildPartial() { + com.google.cloud.spanner.omni.Login.LoginRequest result = + new com.google.cloud.spanner.omni.Login.LoginRequest(this); + if (bitField0_ != 0) { + buildPartial0(result); + } + buildPartialOneofs(result); + onBuilt(); + return result; + } + + private void buildPartial0(com.google.cloud.spanner.omni.Login.LoginRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.username_ = username_; + } + } + + private void buildPartialOneofs(com.google.cloud.spanner.omni.Login.LoginRequest result) { + result.requestCase_ = requestCase_; + result.request_ = this.request_; + if (requestCase_ == 4 && opaqueRequestBuilder_ != null) { + result.request_ = opaqueRequestBuilder_.build(); + } + if (requestCase_ == 5 && handshakeRequestBuilder_ != null) { + result.request_ = handshakeRequestBuilder_.build(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.google.cloud.spanner.omni.Login.LoginRequest) { + return mergeFrom((com.google.cloud.spanner.omni.Login.LoginRequest) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(com.google.cloud.spanner.omni.Login.LoginRequest other) { + if (other == com.google.cloud.spanner.omni.Login.LoginRequest.getDefaultInstance()) + return this; + if (!other.getUsername().isEmpty()) { + username_ = other.username_; + bitField0_ |= 0x00000001; + onChanged(); + } + switch (other.getRequestCase()) { + case OPAQUE_REQUEST: + { + mergeOpaqueRequest(other.getOpaqueRequest()); + break; + } + case HANDSHAKE_REQUEST: + { + mergeHandshakeRequest(other.getHandshakeRequest()); + break; + } + case REQUEST_NOT_SET: + { + break; + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: + { + username_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 34: + { + input.readMessage( + internalGetOpaqueRequestFieldBuilder().getBuilder(), extensionRegistry); + requestCase_ = 4; + break; + } // case 34 + case 42: + { + input.readMessage( + internalGetHandshakeRequestFieldBuilder().getBuilder(), extensionRegistry); + requestCase_ = 5; + break; + } // case 42 + default: + { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + private int requestCase_ = 0; + private java.lang.Object request_; + + public RequestCase getRequestCase() { + return RequestCase.forNumber(requestCase_); + } + + public Builder clearRequest() { + requestCase_ = 0; + request_ = null; + onChanged(); + return this; + } + + private int bitField0_; + + private java.lang.Object username_ = ""; + + /** + * + * + *
+       * The username of the user to log in.
+       * 
+ * + * string username = 1; + * + * @return The username. + */ + public java.lang.String getUsername() { + java.lang.Object ref = username_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + username_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + + /** + * + * + *
+       * The username of the user to log in.
+       * 
+ * + * string username = 1; + * + * @return The bytes for username. + */ + public com.google.protobuf.ByteString getUsernameBytes() { + java.lang.Object ref = username_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8((java.lang.String) ref); + username_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + * + * + *
+       * The username of the user to log in.
+       * 
+ * + * string username = 1; + * + * @param value The username to set. + * @return This builder for chaining. + */ + public Builder setUsername(java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + username_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + /** + * + * + *
+       * The username of the user to log in.
+       * 
+ * + * string username = 1; + * + * @return This builder for chaining. + */ + public Builder clearUsername() { + username_ = getDefaultInstance().getUsername(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + + /** + * + * + *
+       * The username of the user to log in.
+       * 
+ * + * string username = 1; + * + * @param value The bytes for username to set. + * @return This builder for chaining. + */ + public Builder setUsernameBytes(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + username_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest, + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.Builder, + com.google.cloud.spanner.omni.Login.OpaqueLoginRequestOrBuilder> + opaqueRequestBuilder_; + + /** + * + * + *
+       * OPAQUE authentication as defined in rfc9807.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginRequest opaque_request = 4; + * + * @return Whether the opaqueRequest field is set. + */ + @java.lang.Override + public boolean hasOpaqueRequest() { + return requestCase_ == 4; + } + + /** + * + * + *
+       * OPAQUE authentication as defined in rfc9807.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginRequest opaque_request = 4; + * + * @return The opaqueRequest. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginRequest getOpaqueRequest() { + if (opaqueRequestBuilder_ == null) { + if (requestCase_ == 4) { + return (com.google.cloud.spanner.omni.Login.OpaqueLoginRequest) request_; + } + return com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.getDefaultInstance(); + } else { + if (requestCase_ == 4) { + return opaqueRequestBuilder_.getMessage(); + } + return com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.getDefaultInstance(); + } + } + + /** + * + * + *
+       * OPAQUE authentication as defined in rfc9807.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginRequest opaque_request = 4; + */ + public Builder setOpaqueRequest( + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest value) { + if (opaqueRequestBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + request_ = value; + onChanged(); + } else { + opaqueRequestBuilder_.setMessage(value); + } + requestCase_ = 4; + return this; + } + + /** + * + * + *
+       * OPAQUE authentication as defined in rfc9807.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginRequest opaque_request = 4; + */ + public Builder setOpaqueRequest( + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.Builder builderForValue) { + if (opaqueRequestBuilder_ == null) { + request_ = builderForValue.build(); + onChanged(); + } else { + opaqueRequestBuilder_.setMessage(builderForValue.build()); + } + requestCase_ = 4; + return this; + } + + /** + * + * + *
+       * OPAQUE authentication as defined in rfc9807.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginRequest opaque_request = 4; + */ + public Builder mergeOpaqueRequest( + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest value) { + if (opaqueRequestBuilder_ == null) { + if (requestCase_ == 4 + && request_ + != com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.getDefaultInstance()) { + request_ = + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.newBuilder( + (com.google.cloud.spanner.omni.Login.OpaqueLoginRequest) request_) + .mergeFrom(value) + .buildPartial(); + } else { + request_ = value; + } + onChanged(); + } else { + if (requestCase_ == 4) { + opaqueRequestBuilder_.mergeFrom(value); + } else { + opaqueRequestBuilder_.setMessage(value); + } + } + requestCase_ = 4; + return this; + } + + /** + * + * + *
+       * OPAQUE authentication as defined in rfc9807.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginRequest opaque_request = 4; + */ + public Builder clearOpaqueRequest() { + if (opaqueRequestBuilder_ == null) { + if (requestCase_ == 4) { + requestCase_ = 0; + request_ = null; + onChanged(); + } + } else { + if (requestCase_ == 4) { + requestCase_ = 0; + request_ = null; + } + opaqueRequestBuilder_.clear(); + } + return this; + } + + /** + * + * + *
+       * OPAQUE authentication as defined in rfc9807.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginRequest opaque_request = 4; + */ + public com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.Builder + getOpaqueRequestBuilder() { + return internalGetOpaqueRequestFieldBuilder().getBuilder(); + } + + /** + * + * + *
+       * OPAQUE authentication as defined in rfc9807.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginRequest opaque_request = 4; + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginRequestOrBuilder + getOpaqueRequestOrBuilder() { + if ((requestCase_ == 4) && (opaqueRequestBuilder_ != null)) { + return opaqueRequestBuilder_.getMessageOrBuilder(); + } else { + if (requestCase_ == 4) { + return (com.google.cloud.spanner.omni.Login.OpaqueLoginRequest) request_; + } + return com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.getDefaultInstance(); + } + } + + /** + * + * + *
+       * OPAQUE authentication as defined in rfc9807.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginRequest opaque_request = 4; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest, + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.Builder, + com.google.cloud.spanner.omni.Login.OpaqueLoginRequestOrBuilder> + internalGetOpaqueRequestFieldBuilder() { + if (opaqueRequestBuilder_ == null) { + if (!(requestCase_ == 4)) { + request_ = com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.getDefaultInstance(); + } + opaqueRequestBuilder_ = + new com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest, + com.google.cloud.spanner.omni.Login.OpaqueLoginRequest.Builder, + com.google.cloud.spanner.omni.Login.OpaqueLoginRequestOrBuilder>( + (com.google.cloud.spanner.omni.Login.OpaqueLoginRequest) request_, + getParentForChildren(), + isClean()); + request_ = null; + } + requestCase_ = 4; + onChanged(); + return opaqueRequestBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest, + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest.Builder, + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequestOrBuilder> + handshakeRequestBuilder_; + + /** + * + * + *
+       * Handshake request for the client to determine how to authenticate.
+       * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeRequest handshake_request = 5; + * + * @return Whether the handshakeRequest field is set. + */ + @java.lang.Override + public boolean hasHandshakeRequest() { + return requestCase_ == 5; + } + + /** + * + * + *
+       * Handshake request for the client to determine how to authenticate.
+       * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeRequest handshake_request = 5; + * + * @return The handshakeRequest. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest + getHandshakeRequest() { + if (handshakeRequestBuilder_ == null) { + if (requestCase_ == 5) { + return (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest) request_; + } + return com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest + .getDefaultInstance(); + } else { + if (requestCase_ == 5) { + return handshakeRequestBuilder_.getMessage(); + } + return com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest + .getDefaultInstance(); + } + } + + /** + * + * + *
+       * Handshake request for the client to determine how to authenticate.
+       * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeRequest handshake_request = 5; + */ + public Builder setHandshakeRequest( + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest value) { + if (handshakeRequestBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + request_ = value; + onChanged(); + } else { + handshakeRequestBuilder_.setMessage(value); + } + requestCase_ = 5; + return this; + } + + /** + * + * + *
+       * Handshake request for the client to determine how to authenticate.
+       * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeRequest handshake_request = 5; + */ + public Builder setHandshakeRequest( + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest.Builder + builderForValue) { + if (handshakeRequestBuilder_ == null) { + request_ = builderForValue.build(); + onChanged(); + } else { + handshakeRequestBuilder_.setMessage(builderForValue.build()); + } + requestCase_ = 5; + return this; + } + + /** + * + * + *
+       * Handshake request for the client to determine how to authenticate.
+       * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeRequest handshake_request = 5; + */ + public Builder mergeHandshakeRequest( + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest value) { + if (handshakeRequestBuilder_ == null) { + if (requestCase_ == 5 + && request_ + != com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest + .getDefaultInstance()) { + request_ = + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest.newBuilder( + (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest) + request_) + .mergeFrom(value) + .buildPartial(); + } else { + request_ = value; + } + onChanged(); + } else { + if (requestCase_ == 5) { + handshakeRequestBuilder_.mergeFrom(value); + } else { + handshakeRequestBuilder_.setMessage(value); + } + } + requestCase_ = 5; + return this; + } + + /** + * + * + *
+       * Handshake request for the client to determine how to authenticate.
+       * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeRequest handshake_request = 5; + */ + public Builder clearHandshakeRequest() { + if (handshakeRequestBuilder_ == null) { + if (requestCase_ == 5) { + requestCase_ = 0; + request_ = null; + onChanged(); + } + } else { + if (requestCase_ == 5) { + requestCase_ = 0; + request_ = null; + } + handshakeRequestBuilder_.clear(); + } + return this; + } + + /** + * + * + *
+       * Handshake request for the client to determine how to authenticate.
+       * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeRequest handshake_request = 5; + */ + public com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest.Builder + getHandshakeRequestBuilder() { + return internalGetHandshakeRequestFieldBuilder().getBuilder(); + } + + /** + * + * + *
+       * Handshake request for the client to determine how to authenticate.
+       * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeRequest handshake_request = 5; + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequestOrBuilder + getHandshakeRequestOrBuilder() { + if ((requestCase_ == 5) && (handshakeRequestBuilder_ != null)) { + return handshakeRequestBuilder_.getMessageOrBuilder(); + } else { + if (requestCase_ == 5) { + return (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest) request_; + } + return com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest + .getDefaultInstance(); + } + } + + /** + * + * + *
+       * Handshake request for the client to determine how to authenticate.
+       * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeRequest handshake_request = 5; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest, + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest.Builder, + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequestOrBuilder> + internalGetHandshakeRequestFieldBuilder() { + if (handshakeRequestBuilder_ == null) { + if (!(requestCase_ == 5)) { + request_ = + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest + .getDefaultInstance(); + } + handshakeRequestBuilder_ = + new com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest, + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest.Builder, + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequestOrBuilder>( + (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeRequest) request_, + getParentForChildren(), + isClean()); + request_ = null; + } + requestCase_ = 5; + onChanged(); + return handshakeRequestBuilder_; + } + + // @@protoc_insertion_point(builder_scope:google.spanner.auth.v1.LoginRequest) + } + + // @@protoc_insertion_point(class_scope:google.spanner.auth.v1.LoginRequest) + private static final com.google.cloud.spanner.omni.Login.LoginRequest DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new com.google.cloud.spanner.omni.Login.LoginRequest(); + } + + public static com.google.cloud.spanner.omni.Login.LoginRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + @java.lang.Override + public LoginRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException() + .setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.LoginRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + } + + public interface LoginResponseOrBuilder + extends + // @@protoc_insertion_point(interface_extends:google.spanner.auth.v1.LoginResponse) + com.google.protobuf.MessageOrBuilder { + + /** + * + * + *
+     * The access token for the logged in user.  This should be included in
+     * requests to the Spanner API.
+     * 
+ * + * .google.spanner.auth.v1.AccessToken access_token = 1; + * + * @return Whether the accessToken field is set. + */ + boolean hasAccessToken(); + + /** + * + * + *
+     * The access token for the logged in user.  This should be included in
+     * requests to the Spanner API.
+     * 
+ * + * .google.spanner.auth.v1.AccessToken access_token = 1; + * + * @return The accessToken. + */ + com.google.cloud.spanner.omni.Login.AccessToken getAccessToken(); + + /** + * + * + *
+     * The access token for the logged in user.  This should be included in
+     * requests to the Spanner API.
+     * 
+ * + * .google.spanner.auth.v1.AccessToken access_token = 1; + */ + com.google.cloud.spanner.omni.Login.AccessTokenOrBuilder getAccessTokenOrBuilder(); + + /** + * + * + *
+     * The response from the server when the user is using OPAQUE
+     * authentication.
+     * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse opaque_response = 4; + * + * @return Whether the opaqueResponse field is set. + */ + boolean hasOpaqueResponse(); + + /** + * + * + *
+     * The response from the server when the user is using OPAQUE
+     * authentication.
+     * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse opaque_response = 4; + * + * @return The opaqueResponse. + */ + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse getOpaqueResponse(); + + /** + * + * + *
+     * The response from the server when the user is using OPAQUE
+     * authentication.
+     * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse opaque_response = 4; + */ + com.google.cloud.spanner.omni.Login.OpaqueLoginResponseOrBuilder getOpaqueResponseOrBuilder(); + + /** + * + * + *
+     * Handshake response for the server to determine how to authenticate.
+     * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeResponse handshake_response = 5; + * + * @return Whether the handshakeResponse field is set. + */ + boolean hasHandshakeResponse(); + + /** + * + * + *
+     * Handshake response for the server to determine how to authenticate.
+     * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeResponse handshake_response = 5; + * + * @return The handshakeResponse. + */ + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse getHandshakeResponse(); + + /** + * + * + *
+     * Handshake response for the server to determine how to authenticate.
+     * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeResponse handshake_response = 5; + */ + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponseOrBuilder + getHandshakeResponseOrBuilder(); + + com.google.cloud.spanner.omni.Login.LoginResponse.ResponseCase getResponseCase(); + } + + /** + * + * + *
+   * LoginResponse contains the information the client needs to call the
+   * Spanner API.
+   * 
+ * + * Protobuf type {@code google.spanner.auth.v1.LoginResponse} + */ + public static final class LoginResponse extends com.google.protobuf.GeneratedMessage + implements + // @@protoc_insertion_point(message_implements:google.spanner.auth.v1.LoginResponse) + LoginResponseOrBuilder { + private static final long serialVersionUID = 0L; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 33, + /* patch= */ 2, + /* suffix= */ "", + "LoginResponse"); + } + + // Use LoginResponse.newBuilder() to construct. + private LoginResponse(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + + private LoginResponse() {} + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_LoginResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_LoginResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.LoginResponse.class, + com.google.cloud.spanner.omni.Login.LoginResponse.Builder.class); + } + + private int bitField0_; + private int responseCase_ = 0; + + @SuppressWarnings("serial") + private java.lang.Object response_; + + public enum ResponseCase + implements + com.google.protobuf.Internal.EnumLite, + com.google.protobuf.AbstractMessage.InternalOneOfEnum { + OPAQUE_RESPONSE(4), + HANDSHAKE_RESPONSE(5), + RESPONSE_NOT_SET(0); + private final int value; + + private ResponseCase(int value) { + this.value = value; + } + + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static ResponseCase valueOf(int value) { + return forNumber(value); + } + + public static ResponseCase forNumber(int value) { + switch (value) { + case 4: + return OPAQUE_RESPONSE; + case 5: + return HANDSHAKE_RESPONSE; + case 0: + return RESPONSE_NOT_SET; + default: + return null; + } + } + + public int getNumber() { + return this.value; + } + }; + + public ResponseCase getResponseCase() { + return ResponseCase.forNumber(responseCase_); + } + + public static final int ACCESS_TOKEN_FIELD_NUMBER = 1; + private com.google.cloud.spanner.omni.Login.AccessToken accessToken_; + + /** + * + * + *
+     * The access token for the logged in user.  This should be included in
+     * requests to the Spanner API.
+     * 
+ * + * .google.spanner.auth.v1.AccessToken access_token = 1; + * + * @return Whether the accessToken field is set. + */ + @java.lang.Override + public boolean hasAccessToken() { + return ((bitField0_ & 0x00000001) != 0); + } + + /** + * + * + *
+     * The access token for the logged in user.  This should be included in
+     * requests to the Spanner API.
+     * 
+ * + * .google.spanner.auth.v1.AccessToken access_token = 1; + * + * @return The accessToken. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AccessToken getAccessToken() { + return accessToken_ == null + ? com.google.cloud.spanner.omni.Login.AccessToken.getDefaultInstance() + : accessToken_; + } + + /** + * + * + *
+     * The access token for the logged in user.  This should be included in
+     * requests to the Spanner API.
+     * 
+ * + * .google.spanner.auth.v1.AccessToken access_token = 1; + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AccessTokenOrBuilder getAccessTokenOrBuilder() { + return accessToken_ == null + ? com.google.cloud.spanner.omni.Login.AccessToken.getDefaultInstance() + : accessToken_; + } + + public static final int OPAQUE_RESPONSE_FIELD_NUMBER = 4; + + /** + * + * + *
+     * The response from the server when the user is using OPAQUE
+     * authentication.
+     * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse opaque_response = 4; + * + * @return Whether the opaqueResponse field is set. + */ + @java.lang.Override + public boolean hasOpaqueResponse() { + return responseCase_ == 4; + } + + /** + * + * + *
+     * The response from the server when the user is using OPAQUE
+     * authentication.
+     * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse opaque_response = 4; + * + * @return The opaqueResponse. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginResponse getOpaqueResponse() { + if (responseCase_ == 4) { + return (com.google.cloud.spanner.omni.Login.OpaqueLoginResponse) response_; + } + return com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.getDefaultInstance(); + } + + /** + * + * + *
+     * The response from the server when the user is using OPAQUE
+     * authentication.
+     * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse opaque_response = 4; + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginResponseOrBuilder + getOpaqueResponseOrBuilder() { + if (responseCase_ == 4) { + return (com.google.cloud.spanner.omni.Login.OpaqueLoginResponse) response_; + } + return com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.getDefaultInstance(); + } + + public static final int HANDSHAKE_RESPONSE_FIELD_NUMBER = 5; + + /** + * + * + *
+     * Handshake response for the server to determine how to authenticate.
+     * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeResponse handshake_response = 5; + * + * @return Whether the handshakeResponse field is set. + */ + @java.lang.Override + public boolean hasHandshakeResponse() { + return responseCase_ == 5; + } + + /** + * + * + *
+     * Handshake response for the server to determine how to authenticate.
+     * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeResponse handshake_response = 5; + * + * @return The handshakeResponse. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse + getHandshakeResponse() { + if (responseCase_ == 5) { + return (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse) response_; + } + return com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse + .getDefaultInstance(); + } + + /** + * + * + *
+     * Handshake response for the server to determine how to authenticate.
+     * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeResponse handshake_response = 5; + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponseOrBuilder + getHandshakeResponseOrBuilder() { + if (responseCase_ == 5) { + return (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse) response_; + } + return com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse + .getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { + if (((bitField0_ & 0x00000001) != 0)) { + output.writeMessage(1, getAccessToken()); + } + if (responseCase_ == 4) { + output.writeMessage(4, (com.google.cloud.spanner.omni.Login.OpaqueLoginResponse) response_); + } + if (responseCase_ == 5) { + output.writeMessage( + 5, (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse) response_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream.computeMessageSize(1, getAccessToken()); + } + if (responseCase_ == 4) { + size += + com.google.protobuf.CodedOutputStream.computeMessageSize( + 4, (com.google.cloud.spanner.omni.Login.OpaqueLoginResponse) response_); + } + if (responseCase_ == 5) { + size += + com.google.protobuf.CodedOutputStream.computeMessageSize( + 5, (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse) response_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof com.google.cloud.spanner.omni.Login.LoginResponse)) { + return super.equals(obj); + } + com.google.cloud.spanner.omni.Login.LoginResponse other = + (com.google.cloud.spanner.omni.Login.LoginResponse) obj; + + if (hasAccessToken() != other.hasAccessToken()) return false; + if (hasAccessToken()) { + if (!getAccessToken().equals(other.getAccessToken())) return false; + } + if (!getResponseCase().equals(other.getResponseCase())) return false; + switch (responseCase_) { + case 4: + if (!getOpaqueResponse().equals(other.getOpaqueResponse())) return false; + break; + case 5: + if (!getHandshakeResponse().equals(other.getHandshakeResponse())) return false; + break; + case 0: + default: + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (hasAccessToken()) { + hash = (37 * hash) + ACCESS_TOKEN_FIELD_NUMBER; + hash = (53 * hash) + getAccessToken().hashCode(); + } + switch (responseCase_) { + case 4: + hash = (37 * hash) + OPAQUE_RESPONSE_FIELD_NUMBER; + hash = (53 * hash) + getOpaqueResponse().hashCode(); + break; + case 5: + hash = (37 * hash) + HANDSHAKE_RESPONSE_FIELD_NUMBER; + hash = (53 * hash) + getHandshakeResponse().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static com.google.cloud.spanner.omni.Login.LoginResponse parseFrom( + java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.LoginResponse parseFrom( + java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.LoginResponse parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.LoginResponse parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.LoginResponse parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static com.google.cloud.spanner.omni.Login.LoginResponse parseFrom( + byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.LoginResponse parseFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.LoginResponse parseFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.LoginResponse parseDelimitedFrom( + java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.LoginResponse parseDelimitedFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException( + PARSER, input, extensionRegistry); + } + + public static com.google.cloud.spanner.omni.Login.LoginResponse parseFrom( + com.google.protobuf.CodedInputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input); + } + + public static com.google.cloud.spanner.omni.Login.LoginResponse parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage.parseWithIOException( + PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(com.google.cloud.spanner.omni.Login.LoginResponse prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** + * + * + *
+     * LoginResponse contains the information the client needs to call the
+     * Spanner API.
+     * 
+ * + * Protobuf type {@code google.spanner.auth.v1.LoginResponse} + */ + public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder + implements + // @@protoc_insertion_point(builder_implements:google.spanner.auth.v1.LoginResponse) + com.google.cloud.spanner.omni.Login.LoginResponseOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_LoginResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_LoginResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + com.google.cloud.spanner.omni.Login.LoginResponse.class, + com.google.cloud.spanner.omni.Login.LoginResponse.Builder.class); + } + + // Construct using com.google.cloud.spanner.omni.Login.LoginResponse.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + internalGetAccessTokenFieldBuilder(); + } + } + + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + accessToken_ = null; + if (accessTokenBuilder_ != null) { + accessTokenBuilder_.dispose(); + accessTokenBuilder_ = null; + } + if (opaqueResponseBuilder_ != null) { + opaqueResponseBuilder_.clear(); + } + if (handshakeResponseBuilder_ != null) { + handshakeResponseBuilder_.clear(); + } + responseCase_ = 0; + response_ = null; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return com.google.cloud.spanner.omni.Login + .internal_static_google_spanner_auth_v1_LoginResponse_descriptor; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.LoginResponse getDefaultInstanceForType() { + return com.google.cloud.spanner.omni.Login.LoginResponse.getDefaultInstance(); + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.LoginResponse build() { + com.google.cloud.spanner.omni.Login.LoginResponse result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.LoginResponse buildPartial() { + com.google.cloud.spanner.omni.Login.LoginResponse result = + new com.google.cloud.spanner.omni.Login.LoginResponse(this); + if (bitField0_ != 0) { + buildPartial0(result); + } + buildPartialOneofs(result); + onBuilt(); + return result; + } + + private void buildPartial0(com.google.cloud.spanner.omni.Login.LoginResponse result) { + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.accessToken_ = + accessTokenBuilder_ == null ? accessToken_ : accessTokenBuilder_.build(); + to_bitField0_ |= 0x00000001; + } + result.bitField0_ |= to_bitField0_; + } + + private void buildPartialOneofs(com.google.cloud.spanner.omni.Login.LoginResponse result) { + result.responseCase_ = responseCase_; + result.response_ = this.response_; + if (responseCase_ == 4 && opaqueResponseBuilder_ != null) { + result.response_ = opaqueResponseBuilder_.build(); + } + if (responseCase_ == 5 && handshakeResponseBuilder_ != null) { + result.response_ = handshakeResponseBuilder_.build(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof com.google.cloud.spanner.omni.Login.LoginResponse) { + return mergeFrom((com.google.cloud.spanner.omni.Login.LoginResponse) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(com.google.cloud.spanner.omni.Login.LoginResponse other) { + if (other == com.google.cloud.spanner.omni.Login.LoginResponse.getDefaultInstance()) + return this; + if (other.hasAccessToken()) { + mergeAccessToken(other.getAccessToken()); + } + switch (other.getResponseCase()) { + case OPAQUE_RESPONSE: + { + mergeOpaqueResponse(other.getOpaqueResponse()); + break; + } + case HANDSHAKE_RESPONSE: + { + mergeHandshakeResponse(other.getHandshakeResponse()); + break; + } + case RESPONSE_NOT_SET: + { + break; + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: + { + input.readMessage( + internalGetAccessTokenFieldBuilder().getBuilder(), extensionRegistry); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 34: + { + input.readMessage( + internalGetOpaqueResponseFieldBuilder().getBuilder(), extensionRegistry); + responseCase_ = 4; + break; + } // case 34 + case 42: + { + input.readMessage( + internalGetHandshakeResponseFieldBuilder().getBuilder(), extensionRegistry); + responseCase_ = 5; + break; + } // case 42 + default: + { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + private int responseCase_ = 0; + private java.lang.Object response_; + + public ResponseCase getResponseCase() { + return ResponseCase.forNumber(responseCase_); + } + + public Builder clearResponse() { + responseCase_ = 0; + response_ = null; + onChanged(); + return this; + } + + private int bitField0_; + + private com.google.cloud.spanner.omni.Login.AccessToken accessToken_; + private com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.AccessToken, + com.google.cloud.spanner.omni.Login.AccessToken.Builder, + com.google.cloud.spanner.omni.Login.AccessTokenOrBuilder> + accessTokenBuilder_; + + /** + * + * + *
+       * The access token for the logged in user.  This should be included in
+       * requests to the Spanner API.
+       * 
+ * + * .google.spanner.auth.v1.AccessToken access_token = 1; + * + * @return Whether the accessToken field is set. + */ + public boolean hasAccessToken() { + return ((bitField0_ & 0x00000001) != 0); + } + + /** + * + * + *
+       * The access token for the logged in user.  This should be included in
+       * requests to the Spanner API.
+       * 
+ * + * .google.spanner.auth.v1.AccessToken access_token = 1; + * + * @return The accessToken. + */ + public com.google.cloud.spanner.omni.Login.AccessToken getAccessToken() { + if (accessTokenBuilder_ == null) { + return accessToken_ == null + ? com.google.cloud.spanner.omni.Login.AccessToken.getDefaultInstance() + : accessToken_; + } else { + return accessTokenBuilder_.getMessage(); + } + } + + /** + * + * + *
+       * The access token for the logged in user.  This should be included in
+       * requests to the Spanner API.
+       * 
+ * + * .google.spanner.auth.v1.AccessToken access_token = 1; + */ + public Builder setAccessToken(com.google.cloud.spanner.omni.Login.AccessToken value) { + if (accessTokenBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + accessToken_ = value; + } else { + accessTokenBuilder_.setMessage(value); + } + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + /** + * + * + *
+       * The access token for the logged in user.  This should be included in
+       * requests to the Spanner API.
+       * 
+ * + * .google.spanner.auth.v1.AccessToken access_token = 1; + */ + public Builder setAccessToken( + com.google.cloud.spanner.omni.Login.AccessToken.Builder builderForValue) { + if (accessTokenBuilder_ == null) { + accessToken_ = builderForValue.build(); + } else { + accessTokenBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + /** + * + * + *
+       * The access token for the logged in user.  This should be included in
+       * requests to the Spanner API.
+       * 
+ * + * .google.spanner.auth.v1.AccessToken access_token = 1; + */ + public Builder mergeAccessToken(com.google.cloud.spanner.omni.Login.AccessToken value) { + if (accessTokenBuilder_ == null) { + if (((bitField0_ & 0x00000001) != 0) + && accessToken_ != null + && accessToken_ + != com.google.cloud.spanner.omni.Login.AccessToken.getDefaultInstance()) { + getAccessTokenBuilder().mergeFrom(value); + } else { + accessToken_ = value; + } + } else { + accessTokenBuilder_.mergeFrom(value); + } + if (accessToken_ != null) { + bitField0_ |= 0x00000001; + onChanged(); + } + return this; + } + + /** + * + * + *
+       * The access token for the logged in user.  This should be included in
+       * requests to the Spanner API.
+       * 
+ * + * .google.spanner.auth.v1.AccessToken access_token = 1; + */ + public Builder clearAccessToken() { + bitField0_ = (bitField0_ & ~0x00000001); + accessToken_ = null; + if (accessTokenBuilder_ != null) { + accessTokenBuilder_.dispose(); + accessTokenBuilder_ = null; + } + onChanged(); + return this; + } + + /** + * + * + *
+       * The access token for the logged in user.  This should be included in
+       * requests to the Spanner API.
+       * 
+ * + * .google.spanner.auth.v1.AccessToken access_token = 1; + */ + public com.google.cloud.spanner.omni.Login.AccessToken.Builder getAccessTokenBuilder() { + bitField0_ |= 0x00000001; + onChanged(); + return internalGetAccessTokenFieldBuilder().getBuilder(); + } + + /** + * + * + *
+       * The access token for the logged in user.  This should be included in
+       * requests to the Spanner API.
+       * 
+ * + * .google.spanner.auth.v1.AccessToken access_token = 1; + */ + public com.google.cloud.spanner.omni.Login.AccessTokenOrBuilder getAccessTokenOrBuilder() { + if (accessTokenBuilder_ != null) { + return accessTokenBuilder_.getMessageOrBuilder(); + } else { + return accessToken_ == null + ? com.google.cloud.spanner.omni.Login.AccessToken.getDefaultInstance() + : accessToken_; + } + } + + /** + * + * + *
+       * The access token for the logged in user.  This should be included in
+       * requests to the Spanner API.
+       * 
+ * + * .google.spanner.auth.v1.AccessToken access_token = 1; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.AccessToken, + com.google.cloud.spanner.omni.Login.AccessToken.Builder, + com.google.cloud.spanner.omni.Login.AccessTokenOrBuilder> + internalGetAccessTokenFieldBuilder() { + if (accessTokenBuilder_ == null) { + accessTokenBuilder_ = + new com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.AccessToken, + com.google.cloud.spanner.omni.Login.AccessToken.Builder, + com.google.cloud.spanner.omni.Login.AccessTokenOrBuilder>( + getAccessToken(), getParentForChildren(), isClean()); + accessToken_ = null; + } + return accessTokenBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse, + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.Builder, + com.google.cloud.spanner.omni.Login.OpaqueLoginResponseOrBuilder> + opaqueResponseBuilder_; + + /** + * + * + *
+       * The response from the server when the user is using OPAQUE
+       * authentication.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse opaque_response = 4; + * + * @return Whether the opaqueResponse field is set. + */ + @java.lang.Override + public boolean hasOpaqueResponse() { + return responseCase_ == 4; + } + + /** + * + * + *
+       * The response from the server when the user is using OPAQUE
+       * authentication.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse opaque_response = 4; + * + * @return The opaqueResponse. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginResponse getOpaqueResponse() { + if (opaqueResponseBuilder_ == null) { + if (responseCase_ == 4) { + return (com.google.cloud.spanner.omni.Login.OpaqueLoginResponse) response_; + } + return com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.getDefaultInstance(); + } else { + if (responseCase_ == 4) { + return opaqueResponseBuilder_.getMessage(); + } + return com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.getDefaultInstance(); + } + } + + /** + * + * + *
+       * The response from the server when the user is using OPAQUE
+       * authentication.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse opaque_response = 4; + */ + public Builder setOpaqueResponse( + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse value) { + if (opaqueResponseBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + response_ = value; + onChanged(); + } else { + opaqueResponseBuilder_.setMessage(value); + } + responseCase_ = 4; + return this; + } + + /** + * + * + *
+       * The response from the server when the user is using OPAQUE
+       * authentication.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse opaque_response = 4; + */ + public Builder setOpaqueResponse( + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.Builder builderForValue) { + if (opaqueResponseBuilder_ == null) { + response_ = builderForValue.build(); + onChanged(); + } else { + opaqueResponseBuilder_.setMessage(builderForValue.build()); + } + responseCase_ = 4; + return this; + } + + /** + * + * + *
+       * The response from the server when the user is using OPAQUE
+       * authentication.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse opaque_response = 4; + */ + public Builder mergeOpaqueResponse( + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse value) { + if (opaqueResponseBuilder_ == null) { + if (responseCase_ == 4 + && response_ + != com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.getDefaultInstance()) { + response_ = + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.newBuilder( + (com.google.cloud.spanner.omni.Login.OpaqueLoginResponse) response_) + .mergeFrom(value) + .buildPartial(); + } else { + response_ = value; + } + onChanged(); + } else { + if (responseCase_ == 4) { + opaqueResponseBuilder_.mergeFrom(value); + } else { + opaqueResponseBuilder_.setMessage(value); + } + } + responseCase_ = 4; + return this; + } + + /** + * + * + *
+       * The response from the server when the user is using OPAQUE
+       * authentication.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse opaque_response = 4; + */ + public Builder clearOpaqueResponse() { + if (opaqueResponseBuilder_ == null) { + if (responseCase_ == 4) { + responseCase_ = 0; + response_ = null; + onChanged(); + } + } else { + if (responseCase_ == 4) { + responseCase_ = 0; + response_ = null; + } + opaqueResponseBuilder_.clear(); + } + return this; + } + + /** + * + * + *
+       * The response from the server when the user is using OPAQUE
+       * authentication.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse opaque_response = 4; + */ + public com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.Builder + getOpaqueResponseBuilder() { + return internalGetOpaqueResponseFieldBuilder().getBuilder(); + } + + /** + * + * + *
+       * The response from the server when the user is using OPAQUE
+       * authentication.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse opaque_response = 4; + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.OpaqueLoginResponseOrBuilder + getOpaqueResponseOrBuilder() { + if ((responseCase_ == 4) && (opaqueResponseBuilder_ != null)) { + return opaqueResponseBuilder_.getMessageOrBuilder(); + } else { + if (responseCase_ == 4) { + return (com.google.cloud.spanner.omni.Login.OpaqueLoginResponse) response_; + } + return com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.getDefaultInstance(); + } + } + + /** + * + * + *
+       * The response from the server when the user is using OPAQUE
+       * authentication.
+       * 
+ * + * .google.spanner.auth.v1.OpaqueLoginResponse opaque_response = 4; + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse, + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.Builder, + com.google.cloud.spanner.omni.Login.OpaqueLoginResponseOrBuilder> + internalGetOpaqueResponseFieldBuilder() { + if (opaqueResponseBuilder_ == null) { + if (!(responseCase_ == 4)) { + response_ = + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.getDefaultInstance(); + } + opaqueResponseBuilder_ = + new com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse, + com.google.cloud.spanner.omni.Login.OpaqueLoginResponse.Builder, + com.google.cloud.spanner.omni.Login.OpaqueLoginResponseOrBuilder>( + (com.google.cloud.spanner.omni.Login.OpaqueLoginResponse) response_, + getParentForChildren(), + isClean()); + response_ = null; + } + responseCase_ = 4; + onChanged(); + return opaqueResponseBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse, + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse.Builder, + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponseOrBuilder> + handshakeResponseBuilder_; + + /** + * + * + *
+       * Handshake response for the server to determine how to authenticate.
+       * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeResponse handshake_response = 5; + * + * + * @return Whether the handshakeResponse field is set. + */ + @java.lang.Override + public boolean hasHandshakeResponse() { + return responseCase_ == 5; + } + + /** + * + * + *
+       * Handshake response for the server to determine how to authenticate.
+       * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeResponse handshake_response = 5; + * + * + * @return The handshakeResponse. + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse + getHandshakeResponse() { + if (handshakeResponseBuilder_ == null) { + if (responseCase_ == 5) { + return (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse) response_; + } + return com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse + .getDefaultInstance(); + } else { + if (responseCase_ == 5) { + return handshakeResponseBuilder_.getMessage(); + } + return com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse + .getDefaultInstance(); + } + } + + /** + * + * + *
+       * Handshake response for the server to determine how to authenticate.
+       * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeResponse handshake_response = 5; + * + */ + public Builder setHandshakeResponse( + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse value) { + if (handshakeResponseBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + response_ = value; + onChanged(); + } else { + handshakeResponseBuilder_.setMessage(value); + } + responseCase_ = 5; + return this; + } + + /** + * + * + *
+       * Handshake response for the server to determine how to authenticate.
+       * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeResponse handshake_response = 5; + * + */ + public Builder setHandshakeResponse( + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse.Builder + builderForValue) { + if (handshakeResponseBuilder_ == null) { + response_ = builderForValue.build(); + onChanged(); + } else { + handshakeResponseBuilder_.setMessage(builderForValue.build()); + } + responseCase_ = 5; + return this; + } + + /** + * + * + *
+       * Handshake response for the server to determine how to authenticate.
+       * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeResponse handshake_response = 5; + * + */ + public Builder mergeHandshakeResponse( + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse value) { + if (handshakeResponseBuilder_ == null) { + if (responseCase_ == 5 + && response_ + != com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse + .getDefaultInstance()) { + response_ = + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse.newBuilder( + (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse) + response_) + .mergeFrom(value) + .buildPartial(); + } else { + response_ = value; + } + onChanged(); + } else { + if (responseCase_ == 5) { + handshakeResponseBuilder_.mergeFrom(value); + } else { + handshakeResponseBuilder_.setMessage(value); + } + } + responseCase_ = 5; + return this; + } + + /** + * + * + *
+       * Handshake response for the server to determine how to authenticate.
+       * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeResponse handshake_response = 5; + * + */ + public Builder clearHandshakeResponse() { + if (handshakeResponseBuilder_ == null) { + if (responseCase_ == 5) { + responseCase_ = 0; + response_ = null; + onChanged(); + } + } else { + if (responseCase_ == 5) { + responseCase_ = 0; + response_ = null; + } + handshakeResponseBuilder_.clear(); + } + return this; + } + + /** + * + * + *
+       * Handshake response for the server to determine how to authenticate.
+       * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeResponse handshake_response = 5; + * + */ + public com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse.Builder + getHandshakeResponseBuilder() { + return internalGetHandshakeResponseFieldBuilder().getBuilder(); + } + + /** + * + * + *
+       * Handshake response for the server to determine how to authenticate.
+       * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeResponse handshake_response = 5; + * + */ + @java.lang.Override + public com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponseOrBuilder + getHandshakeResponseOrBuilder() { + if ((responseCase_ == 5) && (handshakeResponseBuilder_ != null)) { + return handshakeResponseBuilder_.getMessageOrBuilder(); + } else { + if (responseCase_ == 5) { + return (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse) response_; + } + return com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse + .getDefaultInstance(); + } + } + + /** + * + * + *
+       * Handshake response for the server to determine how to authenticate.
+       * 
+ * + * .google.spanner.auth.v1.AuthenticationHandshakeResponse handshake_response = 5; + * + */ + private com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse, + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse.Builder, + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponseOrBuilder> + internalGetHandshakeResponseFieldBuilder() { + if (handshakeResponseBuilder_ == null) { + if (!(responseCase_ == 5)) { + response_ = + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse + .getDefaultInstance(); + } + handshakeResponseBuilder_ = + new com.google.protobuf.SingleFieldBuilder< + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse, + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse.Builder, + com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponseOrBuilder>( + (com.google.cloud.spanner.omni.Login.AuthenticationHandshakeResponse) response_, + getParentForChildren(), + isClean()); + response_ = null; + } + responseCase_ = 5; + onChanged(); + return handshakeResponseBuilder_; + } + + // @@protoc_insertion_point(builder_scope:google.spanner.auth.v1.LoginResponse) + } + + // @@protoc_insertion_point(class_scope:google.spanner.auth.v1.LoginResponse) + private static final com.google.cloud.spanner.omni.Login.LoginResponse DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new com.google.cloud.spanner.omni.Login.LoginResponse(); + } + + public static com.google.cloud.spanner.omni.Login.LoginResponse getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + @java.lang.Override + public LoginResponse parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException() + .setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public com.google.cloud.spanner.omni.Login.LoginResponse getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + } + + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_google_spanner_auth_v1_AuthenticationHandshakeRequest_descriptor; + private static final com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_google_spanner_auth_v1_AuthenticationHandshakeRequest_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_google_spanner_auth_v1_AuthenticationHandshakeResponse_descriptor; + private static final com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_google_spanner_auth_v1_AuthenticationHandshakeResponse_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_google_spanner_auth_v1_AccessToken_descriptor; + private static final com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_google_spanner_auth_v1_AccessToken_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_google_spanner_auth_v1_InitialOpaqueLoginRequest_descriptor; + private static final com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_google_spanner_auth_v1_InitialOpaqueLoginRequest_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_google_spanner_auth_v1_FinalOpaqueLoginRequest_descriptor; + private static final com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_google_spanner_auth_v1_FinalOpaqueLoginRequest_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_google_spanner_auth_v1_InitialOpaqueLoginResponse_descriptor; + private static final com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_google_spanner_auth_v1_InitialOpaqueLoginResponse_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_google_spanner_auth_v1_OpaqueLoginRequest_descriptor; + private static final com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_google_spanner_auth_v1_OpaqueLoginRequest_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_google_spanner_auth_v1_OpaqueLoginResponse_descriptor; + private static final com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_google_spanner_auth_v1_OpaqueLoginResponse_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_google_spanner_auth_v1_OpaqueLoginResponse_FinalResponse_descriptor; + private static final com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_google_spanner_auth_v1_OpaqueLoginResponse_FinalResponse_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_google_spanner_auth_v1_LoginRequest_descriptor; + private static final com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_google_spanner_auth_v1_LoginRequest_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_google_spanner_auth_v1_LoginResponse_descriptor; + private static final com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_google_spanner_auth_v1_LoginResponse_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + return descriptor; + } + + private static com.google.protobuf.Descriptors.FileDescriptor descriptor; + + static { + java.lang.String[] descriptorData = { + "\n\013login.proto\022\026google.spanner.auth.v1\032\037g" + + "oogle/protobuf/timestamp.proto\" \n\036Authen" + + "ticationHandshakeRequest\"n\n\037Authenticati" + + "onHandshakeResponse\022K\n\025authentication_me" + + "thod\030\001 \001(\0162,.google.spanner.auth.v1.Auth" + + "enticationMethod\"\345\002\n\013AccessToken\022\020\n\010user" + + "name\030\001 \001(\t\0221\n\rcreation_time\030\002 \001(\0132\032.goog" + + "le.protobuf.Timestamp\0223\n\017expiration_time" + + "\030\003 \001(\0132\032.google.protobuf.Timestamp\022\021\n\tsi" + + "gnature\030\004 \001(\014\022\016\n\006key_id\030\005 \001(\003\022N\n\021access_" + + "token_type\030\006 \001(\01623.google.spanner.auth.v" + + "1.AccessToken.AccessTokenType\"i\n\017AccessT" + + "okenType\022!\n\035ACCESS_TOKEN_TYPE_UNSPECIFIE" + + "D\020\000\022\031\n\025ACCESS_TOKEN_TYPE_API\020\001\022\030\n\024ACCESS" + + "_TOKEN_TYPE_UI\020\002\"j\n\031InitialOpaqueLoginRe" + + "quest\022\027\n\017blinded_message\030\001 \001(\014\022\024\n\014client" + + "_nonce\030\002 \001(\014\022\036\n\026client_public_keyshare\030\003" + + " \001(\014\"-\n\027FinalOpaqueLoginRequest\022\022\n\nclien" + + "t_mac\030\001 \001(\014\"\261\001\n\032InitialOpaqueLoginRespon" + + "se\022\024\n\014server_nonce\030\001 \001(\014\022\036\n\026server_publi" + + "c_keyshare\030\002 \001(\014\022\022\n\nserver_mac\030\003 \001(\014\022\031\n\021" + + "evaluated_message\030\004 \001(\014\022\025\n\rmasking_nonce" + + "\030\005 \001(\014\022\027\n\017masked_response\030\006 \001(\014\"\267\001\n\022Opaq" + + "ueLoginRequest\022L\n\017initial_request\030\001 \001(\0132" + + "1.google.spanner.auth.v1.InitialOpaqueLo" + + "ginRequestH\000\022H\n\rfinal_request\030\002 \001(\0132/.go" + + "ogle.spanner.auth.v1.FinalOpaqueLoginReq" + + "uestH\000B\t\n\007request\"\327\001\n\023OpaqueLoginRespons" + + "e\022N\n\020initial_response\030\001 \001(\01322.google.spa" + + "nner.auth.v1.InitialOpaqueLoginResponseH" + + "\000\022S\n\016final_response\030\002 \001(\01329.google.spann" + + "er.auth.v1.OpaqueLoginResponse.FinalResp" + + "onseH\000\032\017\n\rFinalResponseB\n\n\010response\"\306\001\n\014" + + "LoginRequest\022\020\n\010username\030\001 \001(\t\022D\n\016opaque" + + "_request\030\004 \001(\0132*.google.spanner.auth.v1." + + "OpaqueLoginRequestH\000\022S\n\021handshake_reques" + + "t\030\005 \001(\01326.google.spanner.auth.v1.Authent" + + "icationHandshakeRequestH\000B\t\n\007request\"\365\001\n" + + "\rLoginResponse\0229\n\014access_token\030\001 \001(\0132#.g" + + "oogle.spanner.auth.v1.AccessToken\022F\n\017opa" + + "que_response\030\004 \001(\0132+.google.spanner.auth" + + ".v1.OpaqueLoginResponseH\000\022U\n\022handshake_r" + + "esponse\030\005 \001(\01327.google.spanner.auth.v1.A" + + "uthenticationHandshakeResponseH\000B\n\n\010resp" + + "onse*_\n\024AuthenticationMethod\022%\n!AUTHENTI" + + "CATION_METHOD_UNSPECIFIED\020\000\022 \n\034AUTHENTIC" + + "ATION_METHOD_OPAQUE\020\0022j\n\014LoginService\022Z\n" + + "\005Login\022$.google.spanner.auth.v1.LoginReq" + + "uest\032%.google.spanner.auth.v1.LoginRespo" + + "nse\"\000(\0010\001B!\n\035com.google.cloud.spanner.om" + + "niP\000b\006proto3" + }; + descriptor = + com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom( + descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + com.google.protobuf.TimestampProto.getDescriptor(), + }); + internal_static_google_spanner_auth_v1_AuthenticationHandshakeRequest_descriptor = + getDescriptor().getMessageType(0); + internal_static_google_spanner_auth_v1_AuthenticationHandshakeRequest_fieldAccessorTable = + new com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_google_spanner_auth_v1_AuthenticationHandshakeRequest_descriptor, + new java.lang.String[] {}); + internal_static_google_spanner_auth_v1_AuthenticationHandshakeResponse_descriptor = + getDescriptor().getMessageType(1); + internal_static_google_spanner_auth_v1_AuthenticationHandshakeResponse_fieldAccessorTable = + new com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_google_spanner_auth_v1_AuthenticationHandshakeResponse_descriptor, + new java.lang.String[] { + "AuthenticationMethod", + }); + internal_static_google_spanner_auth_v1_AccessToken_descriptor = + getDescriptor().getMessageType(2); + internal_static_google_spanner_auth_v1_AccessToken_fieldAccessorTable = + new com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_google_spanner_auth_v1_AccessToken_descriptor, + new java.lang.String[] { + "Username", "CreationTime", "ExpirationTime", "Signature", "KeyId", "AccessTokenType", + }); + internal_static_google_spanner_auth_v1_InitialOpaqueLoginRequest_descriptor = + getDescriptor().getMessageType(3); + internal_static_google_spanner_auth_v1_InitialOpaqueLoginRequest_fieldAccessorTable = + new com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_google_spanner_auth_v1_InitialOpaqueLoginRequest_descriptor, + new java.lang.String[] { + "BlindedMessage", "ClientNonce", "ClientPublicKeyshare", + }); + internal_static_google_spanner_auth_v1_FinalOpaqueLoginRequest_descriptor = + getDescriptor().getMessageType(4); + internal_static_google_spanner_auth_v1_FinalOpaqueLoginRequest_fieldAccessorTable = + new com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_google_spanner_auth_v1_FinalOpaqueLoginRequest_descriptor, + new java.lang.String[] { + "ClientMac", + }); + internal_static_google_spanner_auth_v1_InitialOpaqueLoginResponse_descriptor = + getDescriptor().getMessageType(5); + internal_static_google_spanner_auth_v1_InitialOpaqueLoginResponse_fieldAccessorTable = + new com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_google_spanner_auth_v1_InitialOpaqueLoginResponse_descriptor, + new java.lang.String[] { + "ServerNonce", + "ServerPublicKeyshare", + "ServerMac", + "EvaluatedMessage", + "MaskingNonce", + "MaskedResponse", + }); + internal_static_google_spanner_auth_v1_OpaqueLoginRequest_descriptor = + getDescriptor().getMessageType(6); + internal_static_google_spanner_auth_v1_OpaqueLoginRequest_fieldAccessorTable = + new com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_google_spanner_auth_v1_OpaqueLoginRequest_descriptor, + new java.lang.String[] { + "InitialRequest", "FinalRequest", "Request", + }); + internal_static_google_spanner_auth_v1_OpaqueLoginResponse_descriptor = + getDescriptor().getMessageType(7); + internal_static_google_spanner_auth_v1_OpaqueLoginResponse_fieldAccessorTable = + new com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_google_spanner_auth_v1_OpaqueLoginResponse_descriptor, + new java.lang.String[] { + "InitialResponse", "FinalResponse", "Response", + }); + internal_static_google_spanner_auth_v1_OpaqueLoginResponse_FinalResponse_descriptor = + internal_static_google_spanner_auth_v1_OpaqueLoginResponse_descriptor.getNestedType(0); + internal_static_google_spanner_auth_v1_OpaqueLoginResponse_FinalResponse_fieldAccessorTable = + new com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_google_spanner_auth_v1_OpaqueLoginResponse_FinalResponse_descriptor, + new java.lang.String[] {}); + internal_static_google_spanner_auth_v1_LoginRequest_descriptor = + getDescriptor().getMessageType(8); + internal_static_google_spanner_auth_v1_LoginRequest_fieldAccessorTable = + new com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_google_spanner_auth_v1_LoginRequest_descriptor, + new java.lang.String[] { + "Username", "OpaqueRequest", "HandshakeRequest", "Request", + }); + internal_static_google_spanner_auth_v1_LoginResponse_descriptor = + getDescriptor().getMessageType(9); + internal_static_google_spanner_auth_v1_LoginResponse_fieldAccessorTable = + new com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_google_spanner_auth_v1_LoginResponse_descriptor, + new java.lang.String[] { + "AccessToken", "OpaqueResponse", "HandshakeResponse", "Response", + }); + descriptor.resolveAllFeaturesImmutable(); + com.google.protobuf.TimestampProto.getDescriptor(); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java index 3d8396ba19a9..48a19bef4481 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java @@ -18,28 +18,20 @@ import com.google.cloud.spanner.SpannerException; import com.google.cloud.spanner.SpannerExceptionFactory; -import com.google.common.base.Preconditions; +import com.google.cloud.spanner.omni.Login.*; import com.google.cloud.spanner.omni.opaque.OpaqueUtil; +import com.google.common.base.Preconditions; +import com.google.crypto.tink.InsecureSecretKeyAccess; +import com.google.crypto.tink.util.SecretBytes; import com.google.protobuf.ByteString; -import google.spanner.omni.v1.AccessToken; -import google.spanner.omni.v1.FinalOpaqueLoginRequest; -import google.spanner.omni.v1.InitialOpaqueLoginRequest; -import google.spanner.omni.v1.InitialOpaqueLoginResponse; -import google.spanner.omni.v1.LoginRequest; -import google.spanner.omni.v1.LoginResponse; -import google.spanner.omni.v1.LoginServiceGrpc; -import google.spanner.omni.v1.OpaqueLoginRequest; import io.grpc.ManagedChannel; import io.grpc.stub.StreamObserver; import java.io.IOException; import java.security.GeneralSecurityException; -import com.google.crypto.tink.util.SecretBytes; -import com.google.crypto.tink.InsecureSecretKeyAccess; - /** - * Client for {@link google.spanner.omni.v1.LoginServiceGrpc}. This class is used to - * authenticate to Spanner Omni using username/password. + * Client for {@link google.spanner.omni.v1.LoginServiceGrpc}. This class is used to authenticate to + * Spanner Omni using username/password. */ public class LoginClient { private static final java.security.SecureRandom SECURE_RANDOM = new java.security.SecureRandom(); @@ -47,7 +39,9 @@ public class LoginClient { private final LoginServiceGrpc.LoginServiceStub stub; public LoginClient(ManagedChannel channel) { - this.stub = LoginServiceGrpc.newStub(channel).withDeadlineAfter(60, java.util.concurrent.TimeUnit.SECONDS); + this.stub = + LoginServiceGrpc.newStub(channel) + .withDeadlineAfter(60, java.util.concurrent.TimeUnit.SECONDS); } /** @@ -65,7 +59,12 @@ public AccessToken login(String username, SecretBytes password) throws SpannerEx try { passwordBytes = password.toByteArray(InsecureSecretKeyAccess.get()); byte[] randomNonce = OpaqueUtil.nonce(); - byte[][] keyPair = OpaqueUtil.generateKeyPair(OpaqueUtil.concat(randomNonce, OpaqueUtil.DIFFIE_HELLMAN_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8))); + byte[][] keyPair = + OpaqueUtil.generateKeyPair( + OpaqueUtil.concat( + randomNonce, + OpaqueUtil.DIFFIE_HELLMAN_KEY_INFO.getBytes( + java.nio.charset.StandardCharsets.UTF_8))); byte[] clientPrivateKeyshare = keyPair[0]; byte[] clientPublicKeyshare = keyPair[1]; byte[] clientNonce = OpaqueUtil.nonce(); @@ -74,6 +73,32 @@ public AccessToken login(String username, SecretBytes password) throws SpannerEx byte[] blindedMessage = OpaqueUtil.blind(passwordBytes, blind); + LoginStreamIOCall call = new LoginStreamIOCall(stub); + + // 1. Send Handshake Request + LoginRequest handshakeRequest = + LoginRequest.newBuilder() + .setUsername(username) + .setHandshakeRequest(AuthenticationHandshakeRequest.newBuilder()) + .build(); + call.send(handshakeRequest); + LoginResponse handshakeResponse = call.getResponse(); + + if (handshakeResponse == null || !handshakeResponse.hasHandshakeResponse()) { + throw SpannerExceptionFactory.newSpannerException( + com.google.cloud.spanner.ErrorCode.UNAUTHENTICATED, + "Failed to receive handshake response from server."); + } + + AuthenticationMethod method = + handshakeResponse.getHandshakeResponse().getAuthenticationMethod(); + if (method != AuthenticationMethod.AUTHENTICATION_METHOD_OPAQUE) { + throw SpannerExceptionFactory.newSpannerException( + com.google.cloud.spanner.ErrorCode.UNAUTHENTICATED, + "Unsupported authentication method: " + method); + } + + // 2. Send Initial OPAQUE Request LoginRequest initialRequest = LoginRequest.newBuilder() .setUsername(username) @@ -86,13 +111,12 @@ public AccessToken login(String username, SecretBytes password) throws SpannerEx .setClientPublicKeyshare(ByteString.copyFrom(clientPublicKeyshare)))) .build(); - LoginStreamIOCall call = new LoginStreamIOCall(stub); call.send(initialRequest); LoginResponse initialResponse = call.getResponse(); InitialOpaqueLoginResponse initialOpaqueResponse = initialResponse.getOpaqueResponse().getInitialResponse(); - + byte[] clientMac = generateClientMac( username, @@ -140,7 +164,10 @@ private byte[] generateClientMac( byte[] stretchedOprf = OpaqueUtil.stretch(oprf); byte[] randomizedPassword = OpaqueUtil.extract(OpaqueUtil.concat(oprf, stretchedOprf)); byte[] maskingKey = - OpaqueUtil.expand(randomizedPassword, OpaqueUtil.MASKING_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8), 32); + OpaqueUtil.expand( + randomizedPassword, + OpaqueUtil.MASKING_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8), + 32); byte[] credentialResponsePad = OpaqueUtil.expand( maskingKey, @@ -159,23 +186,33 @@ private byte[] generateClientMac( byte[] authKey = OpaqueUtil.expand( randomizedPassword, - OpaqueUtil.concat(envelopeNonce.toByteArray(), OpaqueUtil.AUTH_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8)), + OpaqueUtil.concat( + envelopeNonce.toByteArray(), + OpaqueUtil.AUTH_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8)), 32); byte[] seed = OpaqueUtil.expand( randomizedPassword, - OpaqueUtil.concat(envelopeNonce.toByteArray(), OpaqueUtil.PRIVATE_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8)), + OpaqueUtil.concat( + envelopeNonce.toByteArray(), + OpaqueUtil.PRIVATE_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8)), 32); - byte[][] clientKeyPair = OpaqueUtil.generateKeyPair(OpaqueUtil.concat(seed, OpaqueUtil.DIFFIE_HELLMAN_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8))); + byte[][] clientKeyPair = + OpaqueUtil.generateKeyPair( + OpaqueUtil.concat( + seed, + OpaqueUtil.DIFFIE_HELLMAN_KEY_INFO.getBytes( + java.nio.charset.StandardCharsets.UTF_8))); byte[] clientPrivateKey = clientKeyPair[0]; byte[] clientPublicKey = clientKeyPair[1]; - byte[] expectedTag = OpaqueUtil.mac( authKey, OpaqueUtil.concat( - envelopeNonce.toByteArray(), serverPublicKey.toByteArray(), username.getBytes(java.nio.charset.StandardCharsets.UTF_8))); + envelopeNonce.toByteArray(), + serverPublicKey.toByteArray(), + username.getBytes(java.nio.charset.StandardCharsets.UTF_8))); if (!ByteString.copyFrom(expectedTag).equals(authTag)) { throw new GeneralSecurityException("Auth tag mismatch"); } @@ -203,9 +240,22 @@ private byte[] generateClientMac( byte[] prk = OpaqueUtil.extract(inputKeyMaterial); byte[] preambleHash = OpaqueUtil.sha256(preamble); byte[] handshakeSecret = - OpaqueUtil.expand(prk, OpaqueUtil.concat("OPAQUE-HandshakeSecret".getBytes(java.nio.charset.StandardCharsets.UTF_8), preambleHash), 32); - byte[] km2 = OpaqueUtil.expand(handshakeSecret, "OPAQUE-ServerMAC".getBytes(java.nio.charset.StandardCharsets.UTF_8), 32); - byte[] km3 = OpaqueUtil.expand(handshakeSecret, "OPAQUE-ClientMAC".getBytes(java.nio.charset.StandardCharsets.UTF_8), 32); + OpaqueUtil.expand( + prk, + OpaqueUtil.concat( + "OPAQUE-HandshakeSecret".getBytes(java.nio.charset.StandardCharsets.UTF_8), + preambleHash), + 32); + byte[] km2 = + OpaqueUtil.expand( + handshakeSecret, + "OPAQUE-ServerMAC".getBytes(java.nio.charset.StandardCharsets.UTF_8), + 32); + byte[] km3 = + OpaqueUtil.expand( + handshakeSecret, + "OPAQUE-ClientMAC".getBytes(java.nio.charset.StandardCharsets.UTF_8), + 32); byte[] expectedServerMac = OpaqueUtil.mac(km2, OpaqueUtil.sha256(preamble)); if (!ByteString.copyFrom(expectedServerMac).equals(initialOpaqueResponse.getServerMac())) { @@ -216,7 +266,8 @@ private byte[] generateClientMac( static class LoginStreamIOCall { private final LoginServiceGrpc.LoginServiceStub stub; - private final java.util.concurrent.BlockingQueue responseQueue = new java.util.concurrent.LinkedBlockingQueue<>(); + private final java.util.concurrent.BlockingQueue responseQueue = + new java.util.concurrent.LinkedBlockingQueue<>(); private StreamObserver requestObserver; private Throwable error; private boolean completed = false; @@ -257,7 +308,7 @@ LoginResponse getResponse() throws InterruptedException { throw SpannerExceptionFactory.newSpannerException(error); } if (response == LoginResponse.getDefaultInstance() && completed) { - return null; + return null; } return response; } @@ -267,4 +318,3 @@ void halfClose() { } } } - diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginServiceGrpc.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginServiceGrpc.java new file mode 100644 index 000000000000..34a41db3c4de --- /dev/null +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginServiceGrpc.java @@ -0,0 +1,345 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner.omni; + +import static io.grpc.MethodDescriptor.generateFullMethodName; + +/** + * + * + *
+ * The LoginService is used to authenticate users.
+ * 
+ */ +@javax.annotation.Generated( + value = "by gRPC proto compiler (version 1.64.0)", + comments = "Source: login.proto") +@io.grpc.stub.annotations.GrpcGenerated +public final class LoginServiceGrpc { + + private LoginServiceGrpc() {} + + public static final java.lang.String SERVICE_NAME = "google.spanner.auth.v1.LoginService"; + + // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor< + com.google.cloud.spanner.omni.Login.LoginRequest, + com.google.cloud.spanner.omni.Login.LoginResponse> + getLoginMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "Login", + requestType = com.google.cloud.spanner.omni.Login.LoginRequest.class, + responseType = com.google.cloud.spanner.omni.Login.LoginResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + public static io.grpc.MethodDescriptor< + com.google.cloud.spanner.omni.Login.LoginRequest, + com.google.cloud.spanner.omni.Login.LoginResponse> + getLoginMethod() { + io.grpc.MethodDescriptor< + com.google.cloud.spanner.omni.Login.LoginRequest, + com.google.cloud.spanner.omni.Login.LoginResponse> + getLoginMethod; + if ((getLoginMethod = LoginServiceGrpc.getLoginMethod) == null) { + synchronized (LoginServiceGrpc.class) { + if ((getLoginMethod = LoginServiceGrpc.getLoginMethod) == null) { + LoginServiceGrpc.getLoginMethod = + getLoginMethod = + io.grpc.MethodDescriptor + . + newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "Login")) + .setSampledToLocalTracing(true) + .setRequestMarshaller( + io.grpc.protobuf.ProtoUtils.marshaller( + com.google.cloud.spanner.omni.Login.LoginRequest + .getDefaultInstance())) + .setResponseMarshaller( + io.grpc.protobuf.ProtoUtils.marshaller( + com.google.cloud.spanner.omni.Login.LoginResponse + .getDefaultInstance())) + .setSchemaDescriptor(new LoginServiceMethodDescriptorSupplier("Login")) + .build(); + } + } + } + return getLoginMethod; + } + + /** Creates a new async stub that supports all call types for the service */ + public static LoginServiceStub newStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public LoginServiceStub newStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LoginServiceStub(channel, callOptions); + } + }; + return LoginServiceStub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static LoginServiceBlockingStub newBlockingStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public LoginServiceBlockingStub newStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LoginServiceBlockingStub(channel, callOptions); + } + }; + return LoginServiceBlockingStub.newStub(factory, channel); + } + + /** Creates a new ListenableFuture-style stub that supports unary calls on the service */ + public static LoginServiceFutureStub newFutureStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public LoginServiceFutureStub newStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LoginServiceFutureStub(channel, callOptions); + } + }; + return LoginServiceFutureStub.newStub(factory, channel); + } + + /** + * + * + *
+   * The LoginService is used to authenticate users.
+   * 
+ */ + public interface AsyncService { + + /** + * + * + *
+     * Performs the login for Spanner Omni.
+     * 
+ */ + default io.grpc.stub.StreamObserver login( + io.grpc.stub.StreamObserver + responseObserver) { + return io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall( + getLoginMethod(), responseObserver); + } + } + + /** + * Base class for the server implementation of the service LoginService. + * + *
+   * The LoginService is used to authenticate users.
+   * 
+ */ + public abstract static class LoginServiceImplBase + implements io.grpc.BindableService, AsyncService { + + @java.lang.Override + public final io.grpc.ServerServiceDefinition bindService() { + return LoginServiceGrpc.bindService(this); + } + } + + /** + * A stub to allow clients to do asynchronous rpc calls to service LoginService. + * + *
+   * The LoginService is used to authenticate users.
+   * 
+ */ + public static final class LoginServiceStub + extends io.grpc.stub.AbstractAsyncStub { + private LoginServiceStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected LoginServiceStub build(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LoginServiceStub(channel, callOptions); + } + + /** + * + * + *
+     * Performs the login for Spanner Omni.
+     * 
+ */ + public io.grpc.stub.StreamObserver login( + io.grpc.stub.StreamObserver + responseObserver) { + return io.grpc.stub.ClientCalls.asyncBidiStreamingCall( + getChannel().newCall(getLoginMethod(), getCallOptions()), responseObserver); + } + } + + /** + * A stub to allow clients to do synchronous rpc calls to service LoginService. + * + *
+   * The LoginService is used to authenticate users.
+   * 
+ */ + public static final class LoginServiceBlockingStub + extends io.grpc.stub.AbstractBlockingStub { + private LoginServiceBlockingStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected LoginServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LoginServiceBlockingStub(channel, callOptions); + } + } + + /** + * A stub to allow clients to do ListenableFuture-style rpc calls to service LoginService. + * + *
+   * The LoginService is used to authenticate users.
+   * 
+ */ + public static final class LoginServiceFutureStub + extends io.grpc.stub.AbstractFutureStub { + private LoginServiceFutureStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected LoginServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LoginServiceFutureStub(channel, callOptions); + } + } + + private static final int METHODID_LOGIN = 0; + + private static final class MethodHandlers + implements io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + private final AsyncService serviceImpl; + private final int methodId; + + MethodHandlers(AsyncService serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + default: + throw new AssertionError(); + } + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_LOGIN: + return (io.grpc.stub.StreamObserver) + serviceImpl.login( + (io.grpc.stub.StreamObserver) + responseObserver); + default: + throw new AssertionError(); + } + } + } + + public static final io.grpc.ServerServiceDefinition bindService(AsyncService service) { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getLoginMethod(), + io.grpc.stub.ServerCalls.asyncBidiStreamingCall( + new MethodHandlers< + com.google.cloud.spanner.omni.Login.LoginRequest, + com.google.cloud.spanner.omni.Login.LoginResponse>(service, METHODID_LOGIN))) + .build(); + } + + private abstract static class LoginServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoFileDescriptorSupplier, + io.grpc.protobuf.ProtoServiceDescriptorSupplier { + LoginServiceBaseDescriptorSupplier() {} + + @java.lang.Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return com.google.cloud.spanner.omni.Login.getDescriptor(); + } + + @java.lang.Override + public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { + return getFileDescriptor().findServiceByName("LoginService"); + } + } + + private static final class LoginServiceFileDescriptorSupplier + extends LoginServiceBaseDescriptorSupplier { + LoginServiceFileDescriptorSupplier() {} + } + + private static final class LoginServiceMethodDescriptorSupplier + extends LoginServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { + private final java.lang.String methodName; + + LoginServiceMethodDescriptorSupplier(java.lang.String methodName) { + this.methodName = methodName; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { + return getServiceDescriptor().findMethodByName(methodName); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (LoginServiceGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = + result = + io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new LoginServiceFileDescriptorSupplier()) + .addMethod(getLoginMethod()) + .build(); + } + } + } + return result; + } +} diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java index 4a7daada507c..fdf0721d7d20 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java @@ -16,13 +16,16 @@ package com.google.cloud.spanner.omni; -import com.google.auth.oauth2.GoogleCredentials; +import com.google.api.core.InternalApi; import com.google.auth.oauth2.AccessToken; +import com.google.auth.oauth2.GoogleCredentials; +import com.google.crypto.tink.util.SecretBytes; import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; +import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder; +import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext; import java.io.IOException; -import java.util.Date; import java.util.Base64; +import java.util.Date; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; @@ -30,112 +33,133 @@ import java.util.logging.Level; import java.util.logging.Logger; -import com.google.crypto.tink.util.SecretBytes; - /** - * Credentials implementation for Spanner Omni. Uses the OPAQUE protocol to - * authenticate and fetches short-lived access tokens. Supports optional - * background auto-refreshing before token expiry. + * Credentials implementation for Spanner Omni. Uses the OPAQUE protocol to authenticate and fetches + * short-lived access tokens. Supports optional background auto-refreshing before token expiry. */ public class SpannerOmniCredentials extends GoogleCredentials { - private static final Logger logger = Logger.getLogger(SpannerOmniCredentials.class.getName()); - - private static final ScheduledExecutorService SHARED_EXECUTOR = Executors.newScheduledThreadPool(1, r -> { - Thread t = new Thread(r, "spanner-omni-refresh"); - t.setDaemon(true); - return t; - }); - - private final String username; - private final SecretBytes password; - private final String target; - private final boolean backgroundRefresh; - private final ManagedChannel loginChannel; - - private ScheduledFuture refreshTask; - - public SpannerOmniCredentials(String username, SecretBytes password, String target) { - this(username, password, target, true); + private static final Logger logger = Logger.getLogger(SpannerOmniCredentials.class.getName()); + + private static final ScheduledExecutorService SHARED_EXECUTOR = + Executors.newScheduledThreadPool( + 1, + r -> { + Thread t = new Thread(r, "spanner-omni-refresh"); + t.setDaemon(true); + return t; + }); + + private final String username; + private final SecretBytes password; + private String target; + private ManagedChannel loginChannel; + + private ScheduledFuture refreshTask; + + public SpannerOmniCredentials(String username, SecretBytes password, String target) { + this.username = username; + this.password = password; + + // Parse target and initialize channel. If target starts with http://, use plaintext. + if (target.startsWith("http://")) { + this.target = target.substring(7); + this.loginChannel = NettyChannelBuilder.forTarget(this.target).usePlaintext().build(); + } else if (target.startsWith("https://")) { + this.target = target.substring(8); + this.loginChannel = NettyChannelBuilder.forTarget(this.target).build(); + } else { + this.target = target; + this.loginChannel = NettyChannelBuilder.forTarget(this.target).build(); } + } - public SpannerOmniCredentials(String username, SecretBytes password, String target, boolean backgroundRefresh) { - this.username = username; - this.password = password; - this.target = target; - this.backgroundRefresh = backgroundRefresh; - this.loginChannel = ManagedChannelBuilder.forTarget(target).build(); + @InternalApi + public void initChannel(boolean usePlainText, SslContext sslContext) { + logger.info( + "initChannel called: usePlainText=" + + usePlainText + + ", sslContext=" + + (sslContext != null ? "non-null" : "null") + + ", target=" + + target); + if (this.loginChannel != null) { + this.loginChannel.shutdown(); + } + NettyChannelBuilder builder = NettyChannelBuilder.forTarget(this.target); + if (usePlainText) { + builder.usePlaintext(); + } else if (sslContext != null) { + builder.sslContext(sslContext); } + this.loginChannel = builder.build(); + } - @Override - public AccessToken refreshAccessToken() throws IOException { - try { - LoginClient loginClient = new LoginClient(this.loginChannel); - google.spanner.omni.v1.AccessToken protoToken = loginClient.login(username, password); - String tokenValue = Base64.getEncoder().encodeToString(protoToken.toByteArray()); - - long createTimeMillis = protoToken.getCreationTime().getSeconds() * 1000 + - protoToken.getCreationTime().getNanos() / 1000000; - long expireTimeMillis = protoToken.getExpirationTime().getSeconds() * 1000 + - protoToken.getExpirationTime().getNanos() / 1000000; - - long tokenLifetimeMillis = expireTimeMillis - createTimeMillis; - if (tokenLifetimeMillis <= 0) { - tokenLifetimeMillis = TimeUnit.MINUTES.toMillis(60); - } - - AccessToken newAccessToken = new AccessToken(tokenValue, new Date(System.currentTimeMillis() + tokenLifetimeMillis)); - - if (backgroundRefresh && !SHARED_EXECUTOR.isShutdown()) { - scheduleRefresh(tokenLifetimeMillis); - } - - return newAccessToken; - } catch (Exception e) { - logger.log(Level.SEVERE, "Failed to login to Spanner Omni. Username: " + username + ", Target: " + target, e); - throw new IOException("Failed to login to Spanner Omni", e); - } + @Override + public AccessToken refreshAccessToken() throws IOException { + try { + LoginClient loginClient = new LoginClient(this.loginChannel); + com.google.cloud.spanner.omni.Login.AccessToken protoToken = + loginClient.login(username, password); + String tokenValue = Base64.getEncoder().encodeToString(protoToken.toByteArray()); + + long createTimeMillis = + protoToken.getCreationTime().getSeconds() * 1000 + + protoToken.getCreationTime().getNanos() / 1000000; + long expireTimeMillis = + protoToken.getExpirationTime().getSeconds() * 1000 + + protoToken.getExpirationTime().getNanos() / 1000000; + + long tokenLifetimeMillis = expireTimeMillis - createTimeMillis; + if (tokenLifetimeMillis <= 0) { + tokenLifetimeMillis = TimeUnit.MINUTES.toMillis(60); + } + + AccessToken newAccessToken = + new AccessToken(tokenValue, new Date(System.currentTimeMillis() + tokenLifetimeMillis)); + + if (!SHARED_EXECUTOR.isShutdown()) { + scheduleRefresh(tokenLifetimeMillis); + } + return newAccessToken; + } catch (Exception e) { + throw new IOException("Failed to login to Spanner Omni", e); + } + } + + private void scheduleRefresh(long tokenLifetimeMillis) { + if (refreshTask != null && !refreshTask.isDone()) { + refreshTask.cancel(false); } - private void scheduleRefresh(long tokenLifetimeMillis) { - if (refreshTask != null && !refreshTask.isDone()) { - refreshTask.cancel(false); - } - - long delayMillis; - if (tokenLifetimeMillis <= TimeUnit.MINUTES.toMillis(5)) { - // For very short-lived tokens (e.g. 15s), refresh at half their lifetime - delayMillis = tokenLifetimeMillis / 2; - } else { - // For long-lived tokens, refresh 5 minutes before expiry - delayMillis = tokenLifetimeMillis - TimeUnit.MINUTES.toMillis(5); - } - - if (delayMillis < 0) { - delayMillis = 0; - } - - java.lang.ref.WeakReference weakThis = new java.lang.ref.WeakReference<>(this); - - Runnable refreshAction = new Runnable() { - @Override - public void run() { - SpannerOmniCredentials creds = weakThis.get(); - if (creds == null) { - // The credentials instance was garbage collected. Stop the background refresh loop. - return; - } - try { - creds.refresh(); - } catch (IOException e) { - logger.log(Level.WARNING, "Failed to auto-refresh Spanner Omni credentials", e); - // Retry in a short interval on failure - long retryDelay = Math.min(TimeUnit.SECONDS.toMillis(5), tokenLifetimeMillis / 4); - if (retryDelay <= 0) retryDelay = 1000; - creds.refreshTask = SHARED_EXECUTOR.schedule(this, retryDelay, TimeUnit.MILLISECONDS); - } + // Refresh proactively at 3/4th of the token's lifetime! + long delayMillis = tokenLifetimeMillis * 3 / 4; + + if (delayMillis < 0) { + delayMillis = 0; + } + + java.lang.ref.WeakReference weakThis = + new java.lang.ref.WeakReference<>(this); + + Runnable refreshAction = + new Runnable() { + @Override + public void run() { + SpannerOmniCredentials creds = weakThis.get(); + if (creds == null) { + return; } + try { + creds.refresh(); + } catch (IOException e) { + logger.log(Level.WARNING, "Failed to auto-refresh Spanner Omni credentials", e); + long retryDelay = Math.min(TimeUnit.SECONDS.toMillis(5), tokenLifetimeMillis / 4); + if (retryDelay <= 0) retryDelay = 1000; + creds.refreshTask = SHARED_EXECUTOR.schedule(this, retryDelay, TimeUnit.MILLISECONDS); + } + } }; - - refreshTask = SHARED_EXECUTOR.schedule(refreshAction, delayMillis, TimeUnit.MILLISECONDS); - } + + refreshTask = SHARED_EXECUTOR.schedule(refreshAction, delayMillis, TimeUnit.MILLISECONDS); + } } diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java index 460727403cce..a19f710e6783 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java @@ -18,6 +18,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; +import com.google.crypto.tink.subtle.Hkdf; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigInteger; @@ -27,13 +28,12 @@ import java.security.SecureRandom; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; -import com.google.crypto.tink.subtle.Hkdf; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.crypto.ec.CustomNamedCurves; -import org.bouncycastle.math.ec.ECCurve; -import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.crypto.generators.Argon2BytesGenerator; import org.bouncycastle.crypto.params.Argon2Parameters; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; public class OpaqueUtil { @@ -76,39 +76,43 @@ public static byte[] sha256(byte[] message) throws NoSuchAlgorithmException { return digest.digest(message); } - private static final BigInteger p = new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951"); + private static final BigInteger p = + new BigInteger( + "115792089210356248762697446949407573530086143415290314195533631308867097853951"); private static final BigInteger A = p.subtract(new BigInteger("3")); - private static final BigInteger B = new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16); + private static final BigInteger B = + new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16); private static final BigInteger Z = p.subtract(BigInteger.valueOf(10)); - private static byte[] expandMessageXmd(byte[] msg, byte[] DST, int lenInBytes) throws GeneralSecurityException { + private static byte[] expandMessageXmd(byte[] msg, byte[] DST, int lenInBytes) + throws GeneralSecurityException { try { MessageDigest md = MessageDigest.getInstance("SHA-256"); int bInBytes = 32; int ell = (lenInBytes + bInBytes - 1) / bInBytes; - + byte[] dstPrime = new byte[DST.length + 1]; System.arraycopy(DST, 0, dstPrime, 0, DST.length); dstPrime[DST.length] = (byte) DST.length; - + byte[] zPad = new byte[64]; - byte[] libStr = new byte[] { (byte) (lenInBytes >> 8), (byte) (lenInBytes & 0xFF) }; - + byte[] libStr = new byte[] {(byte) (lenInBytes >> 8), (byte) (lenInBytes & 0xFF)}; + md.update(zPad); md.update(msg); md.update(libStr); md.update((byte) 0); md.update(dstPrime); byte[] b0 = md.digest(); - + byte[] bOut = new byte[ell * bInBytes]; - + md.update(b0); md.update((byte) 1); md.update(dstPrime); byte[] b1 = md.digest(); System.arraycopy(b1, 0, bOut, 0, bInBytes); - + byte[] bi = b1; for (int i = 2; i <= ell; i++) { byte[] bXor = new byte[bInBytes]; @@ -121,7 +125,7 @@ private static byte[] expandMessageXmd(byte[] msg, byte[] DST, int lenInBytes) t bi = md.digest(); System.arraycopy(bi, 0, bOut, (i - 1) * bInBytes, bInBytes); } - + byte[] res = new byte[lenInBytes]; System.arraycopy(bOut, 0, res, 0, lenInBytes); return res; @@ -139,14 +143,14 @@ private static ECPoint mapToCurveSSWU(BigInteger u, ECCurve curve) { BigInteger z_u2 = Z.multiply(u2).mod(p); BigInteger z2_u4 = z_u2.multiply(z_u2).mod(p); BigInteger den = z2_u4.add(z_u2).mod(p); - + BigInteger tv1; if (den.equals(BigInteger.ZERO)) { tv1 = BigInteger.ZERO; } else { tv1 = den.modInverse(p); } - + BigInteger x1; if (tv1.equals(BigInteger.ZERO)) { BigInteger za = Z.multiply(A).mod(p); @@ -156,15 +160,15 @@ private static ECPoint mapToCurveSSWU(BigInteger u, ECCurve curve) { BigInteger one_plus_tv1 = BigInteger.ONE.add(tv1).mod(p); x1 = negB_div_A.multiply(one_plus_tv1).mod(p); } - + BigInteger gx1 = x1.pow(3).add(A.multiply(x1)).add(B).mod(p); BigInteger x2 = z_u2.multiply(x1).mod(p); BigInteger gx2 = x2.pow(3).add(A.multiply(x2)).add(B).mod(p); - + BigInteger c1 = p.add(BigInteger.ONE).divide(BigInteger.valueOf(4)); BigInteger root1 = gx1.modPow(c1, p); boolean isSquare = root1.multiply(root1).mod(p).equals(gx1); - + BigInteger x, y; if (isSquare) { x = x1; @@ -173,43 +177,44 @@ private static ECPoint mapToCurveSSWU(BigInteger u, ECCurve curve) { x = x2; y = gx2.modPow(c1, p); } - + if (sgn0(u) != sgn0(y)) { y = y.negate().mod(p); } - + return curve.createPoint(x, y); } - public static byte[] getHashToCurve(byte[] message, byte[] domain) throws GeneralSecurityException { + public static byte[] getHashToCurve(byte[] message, byte[] domain) + throws GeneralSecurityException { byte[] uniformBytes = expandMessageXmd(message, domain, 96); byte[] u0Bytes = new byte[48]; byte[] u1Bytes = new byte[48]; System.arraycopy(uniformBytes, 0, u0Bytes, 0, 48); System.arraycopy(uniformBytes, 48, u1Bytes, 0, 48); - + BigInteger u0 = new BigInteger(1, u0Bytes).mod(p); BigInteger u1 = new BigInteger(1, u1Bytes).mod(p); - + X9ECParameters params = CustomNamedCurves.getByName(CURVE_NAME); ECCurve curve = params.getCurve(); - + ECPoint q0 = mapToCurveSSWU(u0, curve); ECPoint q1 = mapToCurveSSWU(u1, curve); - + ECPoint r = q0.add(q1).normalize(); return r.getEncoded(true); } public static byte[] blind(byte[] password, byte[] blindScalar) throws GeneralSecurityException { byte[] hashedPoint = getHashToCurve(password, LOGIN_DOMAIN_SEPARATION_TAG.getBytes(UTF_8)); - + X9ECParameters params = CustomNamedCurves.getByName(CURVE_NAME); ECCurve curve = params.getCurve(); - + ECPoint point = curve.decodePoint(hashedPoint); BigInteger scalar = new BigInteger(1, blindScalar); - + return point.multiply(scalar).getEncoded(true); } @@ -286,7 +291,8 @@ public static byte[] diffieHellman(byte[] privateKey, byte[] peerPublicKey) return peerPublicPoint.multiply(priv).getEncoded(true); } - public static byte[] randomOracleSha256(byte[] x, BigInteger max) throws GeneralSecurityException { + public static byte[] randomOracleSha256(byte[] x, BigInteger max) + throws GeneralSecurityException { int hashOutputLength = 256; int outputBitLength = max.bitLength() + hashOutputLength; int iterCount = (int) Math.ceil((double) outputBitLength / hashOutputLength); @@ -295,7 +301,7 @@ public static byte[] randomOracleSha256(byte[] x, BigInteger max) throws General } int excessBitCount = (iterCount * hashOutputLength) - outputBitLength; BigInteger hashOutput = BigInteger.ZERO; - + for (int i = 1; i <= iterCount; i++) { hashOutput = hashOutput.shiftLeft(hashOutputLength); byte[] iBytes = BigInteger.valueOf(i).toByteArray(); @@ -305,7 +311,7 @@ public static byte[] randomOracleSha256(byte[] x, BigInteger max) throws General System.arraycopy(iBytes, 1, tmp, 0, tmp.length); iBytes = tmp; } - + byte[] bignumBytes; try { bignumBytes = concat(iBytes, x); @@ -313,27 +319,37 @@ public static byte[] randomOracleSha256(byte[] x, BigInteger max) throws General throw new GeneralSecurityException(e); } byte[] hashedString = sha256(bignumBytes); - + // Ensure hashedString is treated as a positive integer (prepend 0x00) byte[] positiveHashedString = new byte[hashedString.length + 1]; System.arraycopy(hashedString, 0, positiveHashedString, 1, hashedString.length); BigInteger newBigNum = new BigInteger(positiveHashedString); - + hashOutput = hashOutput.add(newBigNum); } - + hashOutput = hashOutput.shiftRight(excessBitCount); hashOutput = hashOutput.mod(max); - + byte[] scalarBytes = new byte[hashOutputLength / 8]; byte[] hashOutputBytes = hashOutput.toByteArray(); - + // Copy into 32 byte array if (hashOutputBytes.length <= scalarBytes.length) { - System.arraycopy(hashOutputBytes, 0, scalarBytes, scalarBytes.length - hashOutputBytes.length, hashOutputBytes.length); + System.arraycopy( + hashOutputBytes, + 0, + scalarBytes, + scalarBytes.length - hashOutputBytes.length, + hashOutputBytes.length); } else { // If hashOutputBytes is 33 bytes due to sign bit - System.arraycopy(hashOutputBytes, hashOutputBytes.length - scalarBytes.length, scalarBytes, 0, scalarBytes.length); + System.arraycopy( + hashOutputBytes, + hashOutputBytes.length - scalarBytes.length, + scalarBytes, + 0, + scalarBytes.length); } return scalarBytes; } @@ -343,7 +359,7 @@ public static byte[][] generateKeyPair(byte[] deriveInput) throws GeneralSecurit BigInteger order = params.getN(); byte[] privateKeyBytes = randomOracleSha256(deriveInput, order); BigInteger privateKey = new BigInteger(1, privateKeyBytes); - + if (privateKey.equals(BigInteger.ZERO)) { privateKey = BigInteger.ONE; privateKeyBytes = new byte[32]; @@ -352,4 +368,4 @@ public static byte[][] generateKeyPair(byte[] deriveInput) throws GeneralSecurit ECPoint publicKey = params.getG().multiply(privateKey); return new byte[][] {privateKeyBytes, publicKey.getEncoded(true)}; } -} \ No newline at end of file +} diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/ExperimentalHostHelper.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/ExperimentalHostHelper.java index 1fd182bbdefa..4b0d68c29e84 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/ExperimentalHostHelper.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/ExperimentalHostHelper.java @@ -26,7 +26,7 @@ public class ExperimentalHostHelper { private static final String CLIENT_CERT_PATH = "spanner.client_cert_path"; private static final String CLIENT_CERT_KEY_PATH = "spanner.client_cert_key_path"; private static final String USERNAME = "spanner.username"; - private static final String PASSWORD_FILE = "spanner.password_file"; + private static final String PASSWORD = "spanner.password"; /** * Checks whether the emulator is being used. This is done by checking if the @@ -40,6 +40,14 @@ public static boolean isExperimentalHost() { public static void appendExperimentalHost(StringBuilder uri) { uri.append(";isExperimentalHost=true"); + String username = System.getProperty(USERNAME, ""); + String password = System.getProperty(PASSWORD, ""); + if (!com.google.common.base.Strings.isNullOrEmpty(username)) { + uri.append(";username=").append(username); + } + if (!com.google.common.base.Strings.isNullOrEmpty(password)) { + uri.append(";password=").append(password); + } if (isMtlsSetup()) { String clientCertificate = System.getProperty(CLIENT_CERT_PATH, ""); String clientKey = System.getProperty(CLIENT_CERT_KEY_PATH, ""); @@ -57,10 +65,10 @@ public static void setExperimentalHostSpannerOptions(SpannerOptions.Builder buil boolean usePlainText = Boolean.getBoolean(USE_PLAIN_TEXT); builder.setExperimentalHost(experimentalHost); builder.setBuiltInMetricsEnabled(false); - String username = System.getProperty(USERNAME,""); - String passwordFile = System.getProperty(PASSWORD_FILE,""); - if(!Strings.isNullOrEmpty(username)){ - builder.login(username,passwordFile,true); + String username = System.getProperty(USERNAME, ""); + String password = System.getProperty(PASSWORD, ""); + if (!Strings.isNullOrEmpty(username)) { + builder.login(username, password); } if (usePlainText) { builder.usePlainText(); diff --git a/java-spanner/google-cloud-spanner/src/main/proto/login.proto b/java-spanner/google-cloud-spanner/src/main/proto/login.proto deleted file mode 100644 index cb283debd99d..000000000000 --- a/java-spanner/google-cloud-spanner/src/main/proto/login.proto +++ /dev/null @@ -1,180 +0,0 @@ -syntax = "proto3"; - -package google.spanner.omni.v1; - -import "google/protobuf/timestamp.proto"; - -option java_multiple_files = true; - -// AccessToken is returned by the LoginService after a successful login. -message AccessToken { - // The username of the logged in user. - string username = 1; - // The creation time of the access token. - google.protobuf.Timestamp creation_time = 2; - // The expiration time of the access token, this will be checked by the - // server. - google.protobuf.Timestamp expiration_time = 3; - // The signature of the access token, this will be verified by the server. - bytes signature = 4; - // The ID of the key used to sign/verify the access token. - int64 key_id = 5; - enum AccessTokenType { - ACCESS_TOKEN_TYPE_UNSPECIFIED = 0; - ACCESS_TOKEN_TYPE_API = 1; - ACCESS_TOKEN_TYPE_UI = 2; - } - // The type of the access token, this will be checked by the server. - AccessTokenType access_token_type = 6; -} - -// InitialOpaqueLoginRequest is used to start the OPAQUE handshake, it will -// contain the blinded message provided by the client. -message InitialOpaqueLoginRequest { - // The blinded message is used to fetch the user's credentials from the - // server. - bytes blinded_message = 1; - - // The AuthRequest fields as defined in rfc9807. - bytes client_nonce = 2; - bytes client_public_keyshare = 3; -} - -message FinalOpaqueLoginRequest { - // The client calculated MAC, this is used to authenticate the client. - bytes client_mac = 1; -} - -// The initial response from the server when using OPAQUE authentication. -// This is referred to as the `K2` message in rfc9807. -message InitialOpaqueLoginResponse { - // The fields that make up the `AuthResponse` message as defined in - // rfc9807. - bytes server_nonce = 1; - bytes server_public_keyshare = 2; - bytes server_mac = 3; - - // The fields that make up the `CredentialResponse` message as defined in - // rfc9807. - bytes evaluated_message = 4; - // The masking_nonce is used to protect the confidential masked response. - bytes masking_nonce = 5; - // The masked_response is the ciphertext containing the user's envelope. - bytes masked_response = 6; -} - -// OpaqueLoginRequest is used to authenticate the user using OPAQUE -// authentication. -message OpaqueLoginRequest { - oneof request { - InitialOpaqueLoginRequest initial_request = 1; - FinalOpaqueLoginRequest final_request = 2; - } -} - -// OpaqueLoginResponse is returned by the server when the user is using OPAQUE -// authentication. -message OpaqueLoginResponse { - message FinalResponse {} - oneof response { - InitialOpaqueLoginResponse initial_response = 1; - FinalResponse final_response = 2; - } -} - -// LoginRequest is used to authenticate the user, and if successful, return an -// access token. -message LoginRequest { - // The username of the user to log in. - string username = 1; - - oneof request { - // OPAQUE authentication as defined in rfc9807. - OpaqueLoginRequest opaque_request = 4; - } -} - -// LoginResponse contains the information the client needs to call the -// Spanner API. -message LoginResponse { - // The access token for the logged in user. This should be included in - // requests to the Spanner API. - AccessToken access_token = 1; - oneof response { - // The response from the server when the user is using OPAQUE - // authentication. - OpaqueLoginResponse opaque_response = 4; - } -} - -// OpaqueUpdatePasswordRequest is used to authenticate the user using OPAQUE -// authentication for password updates. -message OpaqueUpdatePasswordRequest { - message InitialRequest { - InitialOpaqueLoginRequest opaque_request = 1; - - // The blinded message based on the new password. - bytes new_password_blinded_message = 4; - } - message FinalRequest { - FinalOpaqueLoginRequest opaque_request = 1; - - // The new credential provided by the client. - bytes new_credential = 2; - } - oneof request { - InitialRequest initial_request = 1; - FinalRequest final_request = 2; - } -} - -// OpaqueUpdatePasswordResponse is returned by the server when the user is using -// OPAQUE authentication for password updates. -message OpaqueUpdatePasswordResponse { - message InitialResponse { - InitialOpaqueLoginResponse opaque_response = 1; - - // The fields used to create a new envelope for the user. - bytes server_public_key = 7; - bytes new_credential_evaluated_message = 8; - } - message FinalResponse {} - oneof response { - InitialResponse initial_response = 1; - FinalResponse final_response = 2; - } -} - -// UpdatePasswordRequest is used to update the password for a user. -message UpdatePasswordRequest { - // The username of the user to update the password for. - string username = 1; - - oneof request { - // The request to the server when the user is using OPAQUE authentication. - OpaqueUpdatePasswordRequest opaque_request = 4; - } -} - -// UpdatePasswordResponse is returned after a successful password update. -message UpdatePasswordResponse { - // The access token for the logged in user. This should be included in - // requests to the Spanner API. - AccessToken access_token = 1; - - oneof response { - OpaqueUpdatePasswordResponse opaque_response = 4; - } -} - -service LoginService { - // Performs the login for Spanner Omni. - rpc Login(stream LoginRequest) returns (stream LoginResponse) { - } - - // Updates the password for a user. - rpc UpdatePassword(stream UpdatePasswordRequest) - returns (stream UpdatePasswordResponse) { - - } -} \ No newline at end of file From 0b74bd9f29cbfd4aaa76807afdb56064c7d19af8 Mon Sep 17 00:00:00 2001 From: sagnghos Date: Mon, 8 Jun 2026 19:09:37 +0000 Subject: [PATCH 03/15] cleanup pom file --- java-spanner/google-cloud-spanner/pom.xml | 27 ++++++++----------- .../google/cloud/spanner/SpannerOptions.java | 3 +-- .../spanner/connection/ConnectionOptions.java | 3 +-- 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/java-spanner/google-cloud-spanner/pom.xml b/java-spanner/google-cloud-spanner/pom.xml index 2b4590be1c3b..86a8f090eabc 100644 --- a/java-spanner/google-cloud-spanner/pom.xml +++ b/java-spanner/google-cloud-spanner/pom.xml @@ -159,19 +159,14 @@ 0.6.1 com.google.protobuf:protoc:4.33.2:exe:${os.detected.classifier} - grpc-java - io.grpc:protoc-gen-grpc-java:1.64.0:exe:${os.detected.classifier} ${project.basedir}/../proto-google-cloud-spanner-v1/src/main/proto - ${project.basedir}/../google-cloud-spanner/src/main/proto - compile + test-compile - compile - compile-custom test-compile @@ -537,6 +532,16 @@ 2.91.0 test + + org.bouncycastle + bcprov-jdk18on + 1.78 + + + com.google.crypto.tink + tink + 1.13.0 + @@ -549,16 +554,6 @@ javax.annotation javax.annotation-api - - org.bouncycastle - bcprov-jdk18on - 1.78 - - - com.google.crypto.tink - tink - 1.13.0 - diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java index 7dd59cf882c4..8a274ea972d9 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java @@ -1837,8 +1837,7 @@ public Builder login(String username, String password) { passwordBytes, com.google.crypto.tink.InsecureSecretKeyAccess.get()); java.util.Arrays.fill(passwordBytes, (byte) 0); super.setCredentials( - new com.google.cloud.spanner.omni.SpannerOmniCredentials( - username, secretBytes, target)); + new com.google.cloud.spanner.omni.SpannerOmniCredentials(username, secretBytes, target)); return this; } diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java index dd5564eeb8ea..4b42c4d5a4e1 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java @@ -767,8 +767,7 @@ && getInitialConnectionPropertyValue(OAUTH_TOKEN) == null passwordBytes, com.google.crypto.tink.InsecureSecretKeyAccess.get()); java.util.Arrays.fill(passwordBytes, (byte) 0); this.credentials = - new com.google.cloud.spanner.omni.SpannerOmniCredentials( - username, secretBytes, target); + new com.google.cloud.spanner.omni.SpannerOmniCredentials(username, secretBytes, target); } else if ((isExperimentalHostPattern || isExperimentalHost()) && defaultExperimentalHostCredentials != null) { this.credentials = defaultExperimentalHostCredentials; From e8325998a7dd2d2c115b61836658f195d43174a8 Mon Sep 17 00:00:00 2001 From: sagnghos Date: Tue, 9 Jun 2026 07:02:05 +0000 Subject: [PATCH 04/15] refactored autoRefresh logic --- .../google/cloud/spanner/SpannerOptions.java | 8 ++- .../spanner/connection/ConnectionOptions.java | 4 +- .../cloud/spanner/omni/LoginClient.java | 3 + .../spanner/omni/SpannerOmniCredentials.java | 71 +++---------------- .../cloud/spanner/omni/opaque/OpaqueUtil.java | 23 +++--- .../connection/it/ITAutoRefreshTest.java | 45 ++++++++++++ 6 files changed, 76 insertions(+), 78 deletions(-) create mode 100644 java-spanner/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITAutoRefreshTest.java diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java index 8a274ea972d9..314c5ed74c24 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java @@ -1830,14 +1830,18 @@ public Builder login(String username, String password) { if (this.experimentalHost == null) { throw new IllegalStateException("Endpoint must be set before calling login."); } - String target = this.experimentalHost.replaceFirst("^https?://", ""); + Preconditions.checkArgument( + username != null && !username.isEmpty(), "username cannot be null or empty"); + Preconditions.checkArgument( + password != null && !password.isEmpty(), "password cannot be null or empty"); byte[] passwordBytes = password.getBytes(java.nio.charset.StandardCharsets.UTF_8); com.google.crypto.tink.util.SecretBytes secretBytes = com.google.crypto.tink.util.SecretBytes.copyFrom( passwordBytes, com.google.crypto.tink.InsecureSecretKeyAccess.get()); java.util.Arrays.fill(passwordBytes, (byte) 0); super.setCredentials( - new com.google.cloud.spanner.omni.SpannerOmniCredentials(username, secretBytes, target)); + new com.google.cloud.spanner.omni.SpannerOmniCredentials( + username, secretBytes, this.experimentalHost)); return this; } diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java index 4b42c4d5a4e1..334f3da2ca61 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java @@ -760,14 +760,14 @@ && getInitialConnectionPropertyValue(OAUTH_TOKEN) == null } else if ((isExperimentalHostPattern || isExperimentalHost()) && !com.google.common.base.Strings.isNullOrEmpty(username) && !com.google.common.base.Strings.isNullOrEmpty(password)) { - String target = this.host.replaceFirst("^https?://", ""); byte[] passwordBytes = password.getBytes(java.nio.charset.StandardCharsets.UTF_8); com.google.crypto.tink.util.SecretBytes secretBytes = com.google.crypto.tink.util.SecretBytes.copyFrom( passwordBytes, com.google.crypto.tink.InsecureSecretKeyAccess.get()); java.util.Arrays.fill(passwordBytes, (byte) 0); this.credentials = - new com.google.cloud.spanner.omni.SpannerOmniCredentials(username, secretBytes, target); + new com.google.cloud.spanner.omni.SpannerOmniCredentials( + username, secretBytes, this.host); } else if ((isExperimentalHostPattern || isExperimentalHost()) && defaultExperimentalHostCredentials != null) { this.credentials = defaultExperimentalHostCredentials; diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java index 48a19bef4481..23a3ab848615 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java @@ -142,6 +142,9 @@ public AccessToken login(String username, SecretBytes password) throws SpannerEx LoginResponse finalResponse = call.getResponse(); return finalResponse.getAccessToken(); } catch (GeneralSecurityException | IOException | InterruptedException e) { + if (e instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } throw SpannerExceptionFactory.newSpannerException(e); } finally { if (passwordBytes != null) { diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java index fdf0721d7d20..43f0e860a0ac 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java @@ -26,39 +26,25 @@ import java.io.IOException; import java.util.Base64; import java.util.Date; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import java.util.logging.Level; import java.util.logging.Logger; /** * Credentials implementation for Spanner Omni. Uses the OPAQUE protocol to authenticate and fetches - * short-lived access tokens. Supports optional background auto-refreshing before token expiry. + * short-lived access tokens. */ public class SpannerOmniCredentials extends GoogleCredentials { private static final Logger logger = Logger.getLogger(SpannerOmniCredentials.class.getName()); - private static final ScheduledExecutorService SHARED_EXECUTOR = - Executors.newScheduledThreadPool( - 1, - r -> { - Thread t = new Thread(r, "spanner-omni-refresh"); - t.setDaemon(true); - return t; - }); - private final String username; private final SecretBytes password; private String target; private ManagedChannel loginChannel; - private ScheduledFuture refreshTask; - public SpannerOmniCredentials(String username, SecretBytes password, String target) { - this.username = username; - this.password = password; + this.username = com.google.common.base.Preconditions.checkNotNull(username); + this.password = com.google.common.base.Preconditions.checkNotNull(password); + com.google.common.base.Preconditions.checkNotNull(target); // Parse target and initialize channel. If target starts with http://, use plaintext. if (target.startsWith("http://")) { @@ -114,52 +100,13 @@ public AccessToken refreshAccessToken() throws IOException { tokenLifetimeMillis = TimeUnit.MINUTES.toMillis(60); } - AccessToken newAccessToken = - new AccessToken(tokenValue, new Date(System.currentTimeMillis() + tokenLifetimeMillis)); - - if (!SHARED_EXECUTOR.isShutdown()) { - scheduleRefresh(tokenLifetimeMillis); - } - return newAccessToken; + return new AccessToken( + tokenValue, new Date(System.currentTimeMillis() + tokenLifetimeMillis)); } catch (Exception e) { + if (e instanceof InterruptedException || e.getCause() instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } throw new IOException("Failed to login to Spanner Omni", e); } } - - private void scheduleRefresh(long tokenLifetimeMillis) { - if (refreshTask != null && !refreshTask.isDone()) { - refreshTask.cancel(false); - } - - // Refresh proactively at 3/4th of the token's lifetime! - long delayMillis = tokenLifetimeMillis * 3 / 4; - - if (delayMillis < 0) { - delayMillis = 0; - } - - java.lang.ref.WeakReference weakThis = - new java.lang.ref.WeakReference<>(this); - - Runnable refreshAction = - new Runnable() { - @Override - public void run() { - SpannerOmniCredentials creds = weakThis.get(); - if (creds == null) { - return; - } - try { - creds.refresh(); - } catch (IOException e) { - logger.log(Level.WARNING, "Failed to auto-refresh Spanner Omni credentials", e); - long retryDelay = Math.min(TimeUnit.SECONDS.toMillis(5), tokenLifetimeMillis / 4); - if (retryDelay <= 0) retryDelay = 1000; - creds.refreshTask = SHARED_EXECUTOR.schedule(this, retryDelay, TimeUnit.MILLISECONDS); - } - } - }; - - refreshTask = SHARED_EXECUTOR.schedule(refreshAction, delayMillis, TimeUnit.MILLISECONDS); - } } diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java index a19f710e6783..ce734716f187 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java @@ -19,8 +19,6 @@ import static java.nio.charset.StandardCharsets.UTF_8; import com.google.crypto.tink.subtle.Hkdf; -import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.math.BigInteger; import java.security.GeneralSecurityException; import java.security.MessageDigest; @@ -254,12 +252,18 @@ public static byte[] xorBytes(byte[] a, byte[] b) { return result; } - public static byte[] concat(byte[]... arrays) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); + public static byte[] concat(byte[]... arrays) { + int totalLength = 0; for (byte[] array : arrays) { - out.write(array); + totalLength += array.length; } - return out.toByteArray(); + byte[] result = new byte[totalLength]; + int currentIndex = 0; + for (byte[] array : arrays) { + System.arraycopy(array, 0, result, currentIndex, array.length); + currentIndex += array.length; + } + return result; } public static byte[] mac(byte[] key, byte[] data) throws GeneralSecurityException { @@ -312,12 +316,7 @@ public static byte[] randomOracleSha256(byte[] x, BigInteger max) iBytes = tmp; } - byte[] bignumBytes; - try { - bignumBytes = concat(iBytes, x); - } catch (IOException e) { - throw new GeneralSecurityException(e); - } + byte[] bignumBytes = concat(iBytes, x); byte[] hashedString = sha256(bignumBytes); // Ensure hashedString is treated as a positive integer (prepend 0x00) diff --git a/java-spanner/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITAutoRefreshTest.java b/java-spanner/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITAutoRefreshTest.java new file mode 100644 index 000000000000..2388f45b3062 --- /dev/null +++ b/java-spanner/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITAutoRefreshTest.java @@ -0,0 +1,45 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner.connection.it; + +import com.google.cloud.spanner.ParallelIntegrationTest; +import com.google.cloud.spanner.Statement; +import com.google.cloud.spanner.connection.ITAbstractSpannerTest; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@Category(ParallelIntegrationTest.class) +@RunWith(JUnit4.class) +public class ITAutoRefreshTest extends ITAbstractSpannerTest { + + @Test + public void testAutoRefresh() throws Exception { + try (ITConnection connection = createConnection()) { + System.out.println("Executing first query..."); + connection.execute(Statement.of("SELECT 1")); + + System.out.println("Sleeping for 5.5 minutes (330 seconds)..."); + Thread.sleep(330_000); + + System.out.println("Executing second query..."); + connection.execute(Statement.of("SELECT 1")); + System.out.println("Success! The query succeeded after token expiration."); + } + } +} From 7dfa5df681649f3daa97353cb6212429e4570ad3 Mon Sep 17 00:00:00 2001 From: sagnghos Date: Tue, 9 Jun 2026 08:54:14 +0000 Subject: [PATCH 05/15] addressed resource leaks --- .../cloud/spanner/omni/LoginClient.java | 4 +- .../spanner/omni/SpannerOmniCredentials.java | 41 +++++++++++-------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java index 23a3ab848615..b23c4bc62450 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java @@ -272,8 +272,8 @@ static class LoginStreamIOCall { private final java.util.concurrent.BlockingQueue responseQueue = new java.util.concurrent.LinkedBlockingQueue<>(); private StreamObserver requestObserver; - private Throwable error; - private boolean completed = false; + private volatile Throwable error; + private volatile boolean completed = false; LoginStreamIOCall(LoginServiceGrpc.LoginServiceStub stub) { this.stub = stub; diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java index 43f0e860a0ac..ab68d8a695d9 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java @@ -39,23 +39,22 @@ public class SpannerOmniCredentials extends GoogleCredentials { private final String username; private final SecretBytes password; private String target; - private ManagedChannel loginChannel; + private boolean usePlainText = false; + private SslContext sslContext = null; public SpannerOmniCredentials(String username, SecretBytes password, String target) { this.username = com.google.common.base.Preconditions.checkNotNull(username); this.password = com.google.common.base.Preconditions.checkNotNull(password); com.google.common.base.Preconditions.checkNotNull(target); - // Parse target and initialize channel. If target starts with http://, use plaintext. + // Parse target and initialize settings. If target starts with http://, use plaintext. if (target.startsWith("http://")) { this.target = target.substring(7); - this.loginChannel = NettyChannelBuilder.forTarget(this.target).usePlaintext().build(); + this.usePlainText = true; } else if (target.startsWith("https://")) { this.target = target.substring(8); - this.loginChannel = NettyChannelBuilder.forTarget(this.target).build(); } else { this.target = target; - this.loginChannel = NettyChannelBuilder.forTarget(this.target).build(); } } @@ -68,22 +67,23 @@ public void initChannel(boolean usePlainText, SslContext sslContext) { + (sslContext != null ? "non-null" : "null") + ", target=" + target); - if (this.loginChannel != null) { - this.loginChannel.shutdown(); - } - NettyChannelBuilder builder = NettyChannelBuilder.forTarget(this.target); - if (usePlainText) { - builder.usePlaintext(); - } else if (sslContext != null) { - builder.sslContext(sslContext); - } - this.loginChannel = builder.build(); + this.usePlainText = usePlainText; + this.sslContext = sslContext; } @Override public AccessToken refreshAccessToken() throws IOException { + ManagedChannel loginChannel = null; try { - LoginClient loginClient = new LoginClient(this.loginChannel); + NettyChannelBuilder builder = NettyChannelBuilder.forTarget(this.target); + if (this.usePlainText) { + builder.usePlaintext(); + } else if (this.sslContext != null) { + builder.sslContext(this.sslContext); + } + loginChannel = builder.build(); + + LoginClient loginClient = new LoginClient(loginChannel); com.google.cloud.spanner.omni.Login.AccessToken protoToken = loginClient.login(username, password); String tokenValue = Base64.getEncoder().encodeToString(protoToken.toByteArray()); @@ -107,6 +107,15 @@ public AccessToken refreshAccessToken() throws IOException { Thread.currentThread().interrupt(); } throw new IOException("Failed to login to Spanner Omni", e); + } finally { + if (loginChannel != null) { + loginChannel.shutdownNow(); + try { + loginChannel.awaitTermination(5, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } } } } From e46de4f3345d04241a450337f037559cccc260d0 Mon Sep 17 00:00:00 2001 From: sagnghos Date: Tue, 9 Jun 2026 09:32:10 +0000 Subject: [PATCH 06/15] addressed security risks --- .../google/cloud/spanner/SpannerOptions.java | 17 ++++++++++++++--- .../google/cloud/spanner/omni/LoginClient.java | 14 +++++++------- .../spanner/omni/SpannerOmniCredentials.java | 11 +++-------- .../spanner/testing/ExperimentalHostHelper.java | 2 +- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java index 314c5ed74c24..eb7fbfd93532 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java @@ -1826,19 +1826,30 @@ public Builder setExperimentalHost(String host) { * @param password The password for login. * @return this builder */ - public Builder login(String username, String password) { + public Builder login(String username, char[] password) { if (this.experimentalHost == null) { throw new IllegalStateException("Endpoint must be set before calling login."); } Preconditions.checkArgument( username != null && !username.isEmpty(), "username cannot be null or empty"); Preconditions.checkArgument( - password != null && !password.isEmpty(), "password cannot be null or empty"); - byte[] passwordBytes = password.getBytes(java.nio.charset.StandardCharsets.UTF_8); + password != null && password.length > 0, "password cannot be null or empty"); + + java.nio.ByteBuffer byteBuffer = + java.nio.charset.StandardCharsets.UTF_8.encode(java.nio.CharBuffer.wrap(password)); + byte[] passwordBytes = new byte[byteBuffer.remaining()]; + byteBuffer.get(passwordBytes); + if (byteBuffer.hasArray()) { + java.util.Arrays.fill(byteBuffer.array(), (byte) 0); + } + com.google.crypto.tink.util.SecretBytes secretBytes = com.google.crypto.tink.util.SecretBytes.copyFrom( passwordBytes, com.google.crypto.tink.InsecureSecretKeyAccess.get()); + java.util.Arrays.fill(passwordBytes, (byte) 0); + java.util.Arrays.fill(password, '\0'); + super.setCredentials( new com.google.cloud.spanner.omni.SpannerOmniCredentials( username, secretBytes, this.experimentalHost)); diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java index b23c4bc62450..96cb197e301d 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java @@ -120,7 +120,6 @@ public AccessToken login(String username, SecretBytes password) throws SpannerEx byte[] clientMac = generateClientMac( username, - passwordBytes, blind, clientNonce, clientPublicKeyshare, @@ -155,7 +154,6 @@ public AccessToken login(String username, SecretBytes password) throws SpannerEx private byte[] generateClientMac( String username, - byte[] password, byte[] blind, byte[] clientNonce, byte[] clientPublicKeyshare, @@ -307,11 +305,13 @@ void send(LoginRequest request) { LoginResponse getResponse() throws InterruptedException { LoginResponse response = responseQueue.take(); - if (error != null) { - throw SpannerExceptionFactory.newSpannerException(error); - } - if (response == LoginResponse.getDefaultInstance() && completed) { - return null; + if (response == LoginResponse.getDefaultInstance()) { + if (error != null) { + throw SpannerExceptionFactory.newSpannerException(error); + } + if (completed) { + return null; + } } return response; } diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java index ab68d8a695d9..0489862e28bd 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java @@ -88,20 +88,15 @@ public AccessToken refreshAccessToken() throws IOException { loginClient.login(username, password); String tokenValue = Base64.getEncoder().encodeToString(protoToken.toByteArray()); - long createTimeMillis = - protoToken.getCreationTime().getSeconds() * 1000 - + protoToken.getCreationTime().getNanos() / 1000000; long expireTimeMillis = protoToken.getExpirationTime().getSeconds() * 1000 + protoToken.getExpirationTime().getNanos() / 1000000; - long tokenLifetimeMillis = expireTimeMillis - createTimeMillis; - if (tokenLifetimeMillis <= 0) { - tokenLifetimeMillis = TimeUnit.MINUTES.toMillis(60); + if (expireTimeMillis <= System.currentTimeMillis()) { + expireTimeMillis = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(60); } - return new AccessToken( - tokenValue, new Date(System.currentTimeMillis() + tokenLifetimeMillis)); + return new AccessToken(tokenValue, new Date(expireTimeMillis)); } catch (Exception e) { if (e instanceof InterruptedException || e.getCause() instanceof InterruptedException) { Thread.currentThread().interrupt(); diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/ExperimentalHostHelper.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/ExperimentalHostHelper.java index 4b0d68c29e84..e2e66a0403ad 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/ExperimentalHostHelper.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/ExperimentalHostHelper.java @@ -68,7 +68,7 @@ public static void setExperimentalHostSpannerOptions(SpannerOptions.Builder buil String username = System.getProperty(USERNAME, ""); String password = System.getProperty(PASSWORD, ""); if (!Strings.isNullOrEmpty(username)) { - builder.login(username, password); + builder.login(username, password.toCharArray()); } if (usePlainText) { builder.usePlainText(); From 40b91833b287da4b1cbcbee45e03825f784a8ee1 Mon Sep 17 00:00:00 2001 From: sagnghos Date: Tue, 9 Jun 2026 10:01:32 +0000 Subject: [PATCH 07/15] address gemini comments - 1 --- .../google/cloud/spanner/SpannerOptions.java | 12 +- .../cloud/spanner/omni/LoginClient.java | 240 ++++++++++-------- 2 files changed, 146 insertions(+), 106 deletions(-) diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java index eb7fbfd93532..e8b8f209502c 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java @@ -1835,13 +1835,17 @@ public Builder login(String username, char[] password) { Preconditions.checkArgument( password != null && password.length > 0, "password cannot be null or empty"); + java.nio.charset.CharsetEncoder encoder = + java.nio.charset.StandardCharsets.UTF_8.newEncoder(); + java.nio.CharBuffer charBuffer = java.nio.CharBuffer.wrap(password); java.nio.ByteBuffer byteBuffer = - java.nio.charset.StandardCharsets.UTF_8.encode(java.nio.CharBuffer.wrap(password)); + java.nio.ByteBuffer.allocate((int) (encoder.maxBytesPerChar() * charBuffer.remaining())); + encoder.encode(charBuffer, byteBuffer, true); + encoder.flush(byteBuffer); + byteBuffer.flip(); byte[] passwordBytes = new byte[byteBuffer.remaining()]; byteBuffer.get(passwordBytes); - if (byteBuffer.hasArray()) { - java.util.Arrays.fill(byteBuffer.array(), (byte) 0); - } + java.util.Arrays.fill(byteBuffer.array(), (byte) 0); com.google.crypto.tink.util.SecretBytes secretBytes = com.google.crypto.tink.util.SecretBytes.copyFrom( diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java index 96cb197e301d..8f2e67078287 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java @@ -56,6 +56,7 @@ public AccessToken login(String username, SecretBytes password) throws SpannerEx Preconditions.checkNotNull(username); Preconditions.checkNotNull(password); byte[] passwordBytes = null; + byte[] clientPrivateKeyshare = null; try { passwordBytes = password.toByteArray(InsecureSecretKeyAccess.get()); byte[] randomNonce = OpaqueUtil.nonce(); @@ -65,7 +66,7 @@ public AccessToken login(String username, SecretBytes password) throws SpannerEx randomNonce, OpaqueUtil.DIFFIE_HELLMAN_KEY_INFO.getBytes( java.nio.charset.StandardCharsets.UTF_8))); - byte[] clientPrivateKeyshare = keyPair[0]; + clientPrivateKeyshare = keyPair[0]; byte[] clientPublicKeyshare = keyPair[1]; byte[] clientNonce = OpaqueUtil.nonce(); byte[] blind = new byte[32]; @@ -149,6 +150,9 @@ public AccessToken login(String username, SecretBytes password) throws SpannerEx if (passwordBytes != null) { java.util.Arrays.fill(passwordBytes, (byte) 0); } + if (clientPrivateKeyshare != null) { + java.util.Arrays.fill(clientPrivateKeyshare, (byte) 0); + } } } @@ -160,109 +164,141 @@ private byte[] generateClientMac( byte[] clientPrivateKeyshare, InitialOpaqueLoginResponse initialOpaqueResponse) throws GeneralSecurityException, IOException { - byte[] oprf = - OpaqueUtil.finalize(blind, initialOpaqueResponse.getEvaluatedMessage().toByteArray()); - byte[] stretchedOprf = OpaqueUtil.stretch(oprf); - byte[] randomizedPassword = OpaqueUtil.extract(OpaqueUtil.concat(oprf, stretchedOprf)); - byte[] maskingKey = - OpaqueUtil.expand( - randomizedPassword, - OpaqueUtil.MASKING_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8), - 32); - byte[] credentialResponsePad = - OpaqueUtil.expand( - maskingKey, - OpaqueUtil.concat( - initialOpaqueResponse.getMaskingNonce().toByteArray(), - "CredentialResponsePad".getBytes(java.nio.charset.StandardCharsets.UTF_8)), - 16 + 33 + 16); - byte[] serializedEnvelope = - OpaqueUtil.xorBytes( - initialOpaqueResponse.getMaskedResponse().toByteArray(), credentialResponsePad); - ByteString envelope = ByteString.copyFrom(serializedEnvelope); - ByteString serverPublicKey = envelope.substring(0, 33); - ByteString envelopeNonce = envelope.substring(33, 33 + 16); - ByteString authTag = envelope.substring(33 + 16, 33 + 16 + 16); - - byte[] authKey = - OpaqueUtil.expand( - randomizedPassword, - OpaqueUtil.concat( - envelopeNonce.toByteArray(), - OpaqueUtil.AUTH_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8)), - 32); - byte[] seed = - OpaqueUtil.expand( - randomizedPassword, - OpaqueUtil.concat( - envelopeNonce.toByteArray(), - OpaqueUtil.PRIVATE_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8)), - 32); - byte[][] clientKeyPair = - OpaqueUtil.generateKeyPair( - OpaqueUtil.concat( - seed, - OpaqueUtil.DIFFIE_HELLMAN_KEY_INFO.getBytes( - java.nio.charset.StandardCharsets.UTF_8))); - byte[] clientPrivateKey = clientKeyPair[0]; - byte[] clientPublicKey = clientKeyPair[1]; - - byte[] expectedTag = - OpaqueUtil.mac( - authKey, - OpaqueUtil.concat( - envelopeNonce.toByteArray(), - serverPublicKey.toByteArray(), - username.getBytes(java.nio.charset.StandardCharsets.UTF_8))); - if (!ByteString.copyFrom(expectedTag).equals(authTag)) { - throw new GeneralSecurityException("Auth tag mismatch"); - } + byte[] oprf = null; + byte[] stretchedOprf = null; + byte[] randomizedPassword = null; + byte[] maskingKey = null; + byte[] authKey = null; + byte[] seed = null; + byte[] dh1 = null; + byte[] dh2 = null; + byte[] dh3 = null; + byte[] inputKeyMaterial = null; + byte[] handshakeSecret = null; + byte[] km2 = null; + byte[] km3 = null; + byte[] clientPrivateKey = null; + + try { + oprf = OpaqueUtil.finalize(blind, initialOpaqueResponse.getEvaluatedMessage().toByteArray()); + stretchedOprf = OpaqueUtil.stretch(oprf); + randomizedPassword = OpaqueUtil.extract(OpaqueUtil.concat(oprf, stretchedOprf)); + maskingKey = + OpaqueUtil.expand( + randomizedPassword, + OpaqueUtil.MASKING_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8), + 32); + byte[] credentialResponsePad = + OpaqueUtil.expand( + maskingKey, + OpaqueUtil.concat( + initialOpaqueResponse.getMaskingNonce().toByteArray(), + "CredentialResponsePad".getBytes(java.nio.charset.StandardCharsets.UTF_8)), + 16 + 33 + 16); + byte[] serializedEnvelope = + OpaqueUtil.xorBytes( + initialOpaqueResponse.getMaskedResponse().toByteArray(), credentialResponsePad); + ByteString envelope = ByteString.copyFrom(serializedEnvelope); + ByteString serverPublicKey = envelope.substring(0, 33); + ByteString envelopeNonce = envelope.substring(33, 33 + 16); + ByteString authTag = envelope.substring(33 + 16, 33 + 16 + 16); + + authKey = + OpaqueUtil.expand( + randomizedPassword, + OpaqueUtil.concat( + envelopeNonce.toByteArray(), + OpaqueUtil.AUTH_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8)), + 32); + seed = + OpaqueUtil.expand( + randomizedPassword, + OpaqueUtil.concat( + envelopeNonce.toByteArray(), + OpaqueUtil.PRIVATE_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8)), + 32); + byte[][] clientKeyPair = + OpaqueUtil.generateKeyPair( + OpaqueUtil.concat( + seed, + OpaqueUtil.DIFFIE_HELLMAN_KEY_INFO.getBytes( + java.nio.charset.StandardCharsets.UTF_8))); + clientPrivateKey = clientKeyPair[0]; + byte[] clientPublicKey = clientKeyPair[1]; - byte[] dh1 = - OpaqueUtil.diffieHellman( - clientPrivateKeyshare, initialOpaqueResponse.getServerPublicKeyshare().toByteArray()); - byte[] dh2 = OpaqueUtil.diffieHellman(clientPrivateKeyshare, serverPublicKey.toByteArray()); - byte[] dh3 = - OpaqueUtil.diffieHellman( - clientPrivateKey, initialOpaqueResponse.getServerPublicKeyshare().toByteArray()); - - byte[] inputKeyMaterial = OpaqueUtil.concat(dh1, dh2, dh3); - - byte[] preamble = - OpaqueUtil.concat( - "OPAQUEv1-".getBytes(java.nio.charset.StandardCharsets.UTF_8), - username.getBytes(java.nio.charset.StandardCharsets.UTF_8), - clientNonce, - clientPublicKeyshare, - serverPublicKey.toByteArray(), - initialOpaqueResponse.getEvaluatedMessage().toByteArray(), - initialOpaqueResponse.getServerNonce().toByteArray(), - initialOpaqueResponse.getServerPublicKeyshare().toByteArray()); - byte[] prk = OpaqueUtil.extract(inputKeyMaterial); - byte[] preambleHash = OpaqueUtil.sha256(preamble); - byte[] handshakeSecret = - OpaqueUtil.expand( - prk, - OpaqueUtil.concat( - "OPAQUE-HandshakeSecret".getBytes(java.nio.charset.StandardCharsets.UTF_8), - preambleHash), - 32); - byte[] km2 = - OpaqueUtil.expand( - handshakeSecret, - "OPAQUE-ServerMAC".getBytes(java.nio.charset.StandardCharsets.UTF_8), - 32); - byte[] km3 = - OpaqueUtil.expand( - handshakeSecret, - "OPAQUE-ClientMAC".getBytes(java.nio.charset.StandardCharsets.UTF_8), - 32); - - byte[] expectedServerMac = OpaqueUtil.mac(km2, OpaqueUtil.sha256(preamble)); - if (!ByteString.copyFrom(expectedServerMac).equals(initialOpaqueResponse.getServerMac())) { - throw new GeneralSecurityException("Server MAC mismatch"); + byte[] expectedTag = + OpaqueUtil.mac( + authKey, + OpaqueUtil.concat( + envelopeNonce.toByteArray(), + serverPublicKey.toByteArray(), + username.getBytes(java.nio.charset.StandardCharsets.UTF_8))); + if (!java.security.MessageDigest.isEqual(expectedTag, authTag.toByteArray())) { + throw new GeneralSecurityException("Auth tag mismatch"); + } + + dh1 = + OpaqueUtil.diffieHellman( + clientPrivateKeyshare, initialOpaqueResponse.getServerPublicKeyshare().toByteArray()); + dh2 = OpaqueUtil.diffieHellman(clientPrivateKeyshare, serverPublicKey.toByteArray()); + dh3 = + OpaqueUtil.diffieHellman( + clientPrivateKey, initialOpaqueResponse.getServerPublicKeyshare().toByteArray()); + + inputKeyMaterial = OpaqueUtil.concat(dh1, dh2, dh3); + + byte[] preamble = + OpaqueUtil.concat( + "OPAQUEv1-".getBytes(java.nio.charset.StandardCharsets.UTF_8), + username.getBytes(java.nio.charset.StandardCharsets.UTF_8), + clientNonce, + clientPublicKeyshare, + serverPublicKey.toByteArray(), + initialOpaqueResponse.getEvaluatedMessage().toByteArray(), + initialOpaqueResponse.getServerNonce().toByteArray(), + initialOpaqueResponse.getServerPublicKeyshare().toByteArray()); + byte[] prk = OpaqueUtil.extract(inputKeyMaterial); + byte[] preambleHash = OpaqueUtil.sha256(preamble); + handshakeSecret = + OpaqueUtil.expand( + prk, + OpaqueUtil.concat( + "OPAQUE-HandshakeSecret".getBytes(java.nio.charset.StandardCharsets.UTF_8), + preambleHash), + 32); + km2 = + OpaqueUtil.expand( + handshakeSecret, + "OPAQUE-ServerMAC".getBytes(java.nio.charset.StandardCharsets.UTF_8), + 32); + km3 = + OpaqueUtil.expand( + handshakeSecret, + "OPAQUE-ClientMAC".getBytes(java.nio.charset.StandardCharsets.UTF_8), + 32); + + byte[] expectedServerMac = OpaqueUtil.mac(km2, OpaqueUtil.sha256(preamble)); + if (!java.security.MessageDigest.isEqual( + expectedServerMac, initialOpaqueResponse.getServerMac().toByteArray())) { + throw new GeneralSecurityException("Server MAC mismatch"); + } + return OpaqueUtil.mac(km3, OpaqueUtil.sha256(OpaqueUtil.concat(preamble, expectedServerMac))); + } finally { + if (oprf != null) java.util.Arrays.fill(oprf, (byte) 0); + if (stretchedOprf != null) java.util.Arrays.fill(stretchedOprf, (byte) 0); + if (randomizedPassword != null) java.util.Arrays.fill(randomizedPassword, (byte) 0); + if (maskingKey != null) java.util.Arrays.fill(maskingKey, (byte) 0); + if (authKey != null) java.util.Arrays.fill(authKey, (byte) 0); + if (seed != null) java.util.Arrays.fill(seed, (byte) 0); + if (dh1 != null) java.util.Arrays.fill(dh1, (byte) 0); + if (dh2 != null) java.util.Arrays.fill(dh2, (byte) 0); + if (dh3 != null) java.util.Arrays.fill(dh3, (byte) 0); + if (inputKeyMaterial != null) java.util.Arrays.fill(inputKeyMaterial, (byte) 0); + if (handshakeSecret != null) java.util.Arrays.fill(handshakeSecret, (byte) 0); + if (km2 != null) java.util.Arrays.fill(km2, (byte) 0); + if (km3 != null) java.util.Arrays.fill(km3, (byte) 0); + if (clientPrivateKey != null) java.util.Arrays.fill(clientPrivateKey, (byte) 0); } - return OpaqueUtil.mac(km3, OpaqueUtil.sha256(OpaqueUtil.concat(preamble, expectedServerMac))); } static class LoginStreamIOCall { From 55f231a23089ed6516049c06540be3c71de58b05 Mon Sep 17 00:00:00 2001 From: sagnghos Date: Tue, 9 Jun 2026 10:01:41 +0000 Subject: [PATCH 08/15] address gemini comments - 2 --- .../cloud/spanner/omni/opaque/OpaqueUtil.java | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java index ce734716f187..fdcb3dfbb8d5 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java @@ -308,21 +308,13 @@ public static byte[] randomOracleSha256(byte[] x, BigInteger max) for (int i = 1; i <= iterCount; i++) { hashOutput = hashOutput.shiftLeft(hashOutputLength); - byte[] iBytes = BigInteger.valueOf(i).toByteArray(); - // Remove leading zero byte if present from two's complement representation - if (iBytes.length > 1 && iBytes[0] == 0) { - byte[] tmp = new byte[iBytes.length - 1]; - System.arraycopy(iBytes, 1, tmp, 0, tmp.length); - iBytes = tmp; - } + byte[] iBytes = new byte[] {(byte) i}; byte[] bignumBytes = concat(iBytes, x); byte[] hashedString = sha256(bignumBytes); - // Ensure hashedString is treated as a positive integer (prepend 0x00) - byte[] positiveHashedString = new byte[hashedString.length + 1]; - System.arraycopy(hashedString, 0, positiveHashedString, 1, hashedString.length); - BigInteger newBigNum = new BigInteger(positiveHashedString); + // Ensure hashedString is treated as a positive integer + BigInteger newBigNum = new BigInteger(1, hashedString); hashOutput = hashOutput.add(newBigNum); } From 85dd3ca9dc8b898492eaaf690f2a75c218cb5d6c Mon Sep 17 00:00:00 2001 From: sagnghos Date: Tue, 9 Jun 2026 10:30:03 +0000 Subject: [PATCH 09/15] address lint issues --- .../google/cloud/spanner/SpannerOptions.java | 50 ++++++---- .../spanner/connection/ConnectionOptions.java | 25 +++-- .../cloud/spanner/omni/LoginClient.java | 92 +++++++++---------- .../spanner/omni/SpannerOmniCredentials.java | 10 +- .../cloud/spanner/omni/opaque/OpaqueUtil.java | 36 +++++--- .../testing/ExperimentalHostHelper.java | 4 +- .../connection/it/ITAutoRefreshTest.java | 2 +- 7 files changed, 119 insertions(+), 100 deletions(-) diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java index e8b8f209502c..94958e02ff79 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java @@ -53,6 +53,7 @@ import com.google.cloud.spanner.admin.database.v1.stub.DatabaseAdminStubSettings; import com.google.cloud.spanner.admin.instance.v1.InstanceAdminSettings; import com.google.cloud.spanner.admin.instance.v1.stub.InstanceAdminStubSettings; +import com.google.cloud.spanner.omni.SpannerOmniCredentials; import com.google.cloud.spanner.spi.SpannerRpcFactory; import com.google.cloud.spanner.spi.v1.ChannelEndpointCacheFactory; import com.google.cloud.spanner.spi.v1.GapicSpannerRpc; @@ -66,6 +67,8 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.ThreadFactoryBuilder; +import com.google.crypto.tink.InsecureSecretKeyAccess; +import com.google.crypto.tink.util.SecretBytes; import com.google.spanner.v1.DirectedReadOptions; import com.google.spanner.v1.ExecuteSqlRequest; import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions; @@ -91,10 +94,15 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.time.Duration; import java.util.ArrayList; +import java.util.Arrays; import java.util.Base64; import java.util.HashMap; import java.util.List; @@ -1835,28 +1843,30 @@ public Builder login(String username, char[] password) { Preconditions.checkArgument( password != null && password.length > 0, "password cannot be null or empty"); - java.nio.charset.CharsetEncoder encoder = - java.nio.charset.StandardCharsets.UTF_8.newEncoder(); - java.nio.CharBuffer charBuffer = java.nio.CharBuffer.wrap(password); - java.nio.ByteBuffer byteBuffer = - java.nio.ByteBuffer.allocate((int) (encoder.maxBytesPerChar() * charBuffer.remaining())); - encoder.encode(charBuffer, byteBuffer, true); - encoder.flush(byteBuffer); - byteBuffer.flip(); - byte[] passwordBytes = new byte[byteBuffer.remaining()]; - byteBuffer.get(passwordBytes); - java.util.Arrays.fill(byteBuffer.array(), (byte) 0); - - com.google.crypto.tink.util.SecretBytes secretBytes = - com.google.crypto.tink.util.SecretBytes.copyFrom( - passwordBytes, com.google.crypto.tink.InsecureSecretKeyAccess.get()); - - java.util.Arrays.fill(passwordBytes, (byte) 0); - java.util.Arrays.fill(password, '\0'); + byte[] passwordBytes = null; + SecretBytes secretBytes; + try { + CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder(); + CharBuffer charBuffer = CharBuffer.wrap(password); + ByteBuffer byteBuffer = + ByteBuffer.allocate((int) (encoder.maxBytesPerChar() * charBuffer.remaining())); + encoder.encode(charBuffer, byteBuffer, true); + encoder.flush(byteBuffer); + byteBuffer.flip(); + passwordBytes = new byte[byteBuffer.remaining()]; + byteBuffer.get(passwordBytes); + Arrays.fill(byteBuffer.array(), (byte) 0); + + secretBytes = SecretBytes.copyFrom(passwordBytes, InsecureSecretKeyAccess.get()); + } finally { + if (passwordBytes != null) { + Arrays.fill(passwordBytes, (byte) 0); + } + Arrays.fill(password, '\0'); + } super.setCredentials( - new com.google.cloud.spanner.omni.SpannerOmniCredentials( - username, secretBytes, this.experimentalHost)); + new SpannerOmniCredentials(username, secretBytes, this.experimentalHost)); return this; } diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java index 334f3da2ca61..422a121444b7 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java @@ -84,19 +84,24 @@ import com.google.cloud.spanner.SpannerOptions; import com.google.cloud.spanner.connection.ClientSideStatementValueConverters.GrpcInterceptorProviderConverter; import com.google.cloud.spanner.connection.StatementExecutor.StatementExecutorType; +import com.google.cloud.spanner.omni.SpannerOmniCredentials; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableMap; +import com.google.crypto.tink.InsecureSecretKeyAccess; +import com.google.crypto.tink.util.SecretBytes; import io.grpc.Deadline; import io.grpc.Deadline.Ticker; import io.opentelemetry.api.OpenTelemetry; import java.io.IOException; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -758,16 +763,16 @@ && getInitialConnectionPropertyValue(OAUTH_TOKEN) == null new GoogleCredentials( new AccessToken(getInitialConnectionPropertyValue(OAUTH_TOKEN), null)); } else if ((isExperimentalHostPattern || isExperimentalHost()) - && !com.google.common.base.Strings.isNullOrEmpty(username) - && !com.google.common.base.Strings.isNullOrEmpty(password)) { - byte[] passwordBytes = password.getBytes(java.nio.charset.StandardCharsets.UTF_8); - com.google.crypto.tink.util.SecretBytes secretBytes = - com.google.crypto.tink.util.SecretBytes.copyFrom( - passwordBytes, com.google.crypto.tink.InsecureSecretKeyAccess.get()); - java.util.Arrays.fill(passwordBytes, (byte) 0); - this.credentials = - new com.google.cloud.spanner.omni.SpannerOmniCredentials( - username, secretBytes, this.host); + && !Strings.isNullOrEmpty(username) + && !Strings.isNullOrEmpty(password)) { + byte[] passwordBytes = password.getBytes(StandardCharsets.UTF_8); + SecretBytes secretBytes; + try { + secretBytes = SecretBytes.copyFrom(passwordBytes, InsecureSecretKeyAccess.get()); + } finally { + Arrays.fill(passwordBytes, (byte) 0); + } + this.credentials = new SpannerOmniCredentials(username, secretBytes, this.host); } else if ((isExperimentalHostPattern || isExperimentalHost()) && defaultExperimentalHostCredentials != null) { this.credentials = defaultExperimentalHostCredentials; diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java index 8f2e67078287..ddced4827799 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2026 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,21 +27,26 @@ import io.grpc.ManagedChannel; import io.grpc.stub.StreamObserver; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; +import java.security.MessageDigest; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; /** * Client for {@link google.spanner.omni.v1.LoginServiceGrpc}. This class is used to authenticate to * Spanner Omni using username/password. */ public class LoginClient { - private static final java.security.SecureRandom SECURE_RANDOM = new java.security.SecureRandom(); + private static final SecureRandom SECURE_RANDOM = new SecureRandom(); private final LoginServiceGrpc.LoginServiceStub stub; public LoginClient(ManagedChannel channel) { - this.stub = - LoginServiceGrpc.newStub(channel) - .withDeadlineAfter(60, java.util.concurrent.TimeUnit.SECONDS); + this.stub = LoginServiceGrpc.newStub(channel).withDeadlineAfter(60, TimeUnit.SECONDS); } /** @@ -64,8 +69,7 @@ public AccessToken login(String username, SecretBytes password) throws SpannerEx OpaqueUtil.generateKeyPair( OpaqueUtil.concat( randomNonce, - OpaqueUtil.DIFFIE_HELLMAN_KEY_INFO.getBytes( - java.nio.charset.StandardCharsets.UTF_8))); + OpaqueUtil.DIFFIE_HELLMAN_KEY_INFO.getBytes(StandardCharsets.UTF_8))); clientPrivateKeyshare = keyPair[0]; byte[] clientPublicKeyshare = keyPair[1]; byte[] clientNonce = OpaqueUtil.nonce(); @@ -141,17 +145,17 @@ public AccessToken login(String username, SecretBytes password) throws SpannerEx call.halfClose(); LoginResponse finalResponse = call.getResponse(); return finalResponse.getAccessToken(); - } catch (GeneralSecurityException | IOException | InterruptedException e) { + } catch (Exception e) { if (e instanceof InterruptedException) { Thread.currentThread().interrupt(); } throw SpannerExceptionFactory.newSpannerException(e); } finally { if (passwordBytes != null) { - java.util.Arrays.fill(passwordBytes, (byte) 0); + Arrays.fill(passwordBytes, (byte) 0); } if (clientPrivateKeyshare != null) { - java.util.Arrays.fill(clientPrivateKeyshare, (byte) 0); + Arrays.fill(clientPrivateKeyshare, (byte) 0); } } } @@ -178,6 +182,7 @@ private byte[] generateClientMac( byte[] km2 = null; byte[] km3 = null; byte[] clientPrivateKey = null; + byte[] prk = null; try { oprf = OpaqueUtil.finalize(blind, initialOpaqueResponse.getEvaluatedMessage().toByteArray()); @@ -185,9 +190,7 @@ private byte[] generateClientMac( randomizedPassword = OpaqueUtil.extract(OpaqueUtil.concat(oprf, stretchedOprf)); maskingKey = OpaqueUtil.expand( - randomizedPassword, - OpaqueUtil.MASKING_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8), - 32); + randomizedPassword, OpaqueUtil.MASKING_KEY_INFO.getBytes(StandardCharsets.UTF_8), 32); byte[] credentialResponsePad = OpaqueUtil.expand( maskingKey, @@ -208,21 +211,19 @@ private byte[] generateClientMac( randomizedPassword, OpaqueUtil.concat( envelopeNonce.toByteArray(), - OpaqueUtil.AUTH_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8)), + OpaqueUtil.AUTH_KEY_INFO.getBytes(StandardCharsets.UTF_8)), 32); seed = OpaqueUtil.expand( randomizedPassword, OpaqueUtil.concat( envelopeNonce.toByteArray(), - OpaqueUtil.PRIVATE_KEY_INFO.getBytes(java.nio.charset.StandardCharsets.UTF_8)), + OpaqueUtil.PRIVATE_KEY_INFO.getBytes(StandardCharsets.UTF_8)), 32); byte[][] clientKeyPair = OpaqueUtil.generateKeyPair( OpaqueUtil.concat( - seed, - OpaqueUtil.DIFFIE_HELLMAN_KEY_INFO.getBytes( - java.nio.charset.StandardCharsets.UTF_8))); + seed, OpaqueUtil.DIFFIE_HELLMAN_KEY_INFO.getBytes(StandardCharsets.UTF_8))); clientPrivateKey = clientKeyPair[0]; byte[] clientPublicKey = clientKeyPair[1]; @@ -232,8 +233,8 @@ private byte[] generateClientMac( OpaqueUtil.concat( envelopeNonce.toByteArray(), serverPublicKey.toByteArray(), - username.getBytes(java.nio.charset.StandardCharsets.UTF_8))); - if (!java.security.MessageDigest.isEqual(expectedTag, authTag.toByteArray())) { + username.getBytes(StandardCharsets.UTF_8))); + if (!MessageDigest.isEqual(expectedTag, authTag.toByteArray())) { throw new GeneralSecurityException("Auth tag mismatch"); } @@ -249,62 +250,57 @@ private byte[] generateClientMac( byte[] preamble = OpaqueUtil.concat( - "OPAQUEv1-".getBytes(java.nio.charset.StandardCharsets.UTF_8), - username.getBytes(java.nio.charset.StandardCharsets.UTF_8), + "OPAQUEv1-".getBytes(StandardCharsets.UTF_8), + username.getBytes(StandardCharsets.UTF_8), clientNonce, clientPublicKeyshare, serverPublicKey.toByteArray(), initialOpaqueResponse.getEvaluatedMessage().toByteArray(), initialOpaqueResponse.getServerNonce().toByteArray(), initialOpaqueResponse.getServerPublicKeyshare().toByteArray()); - byte[] prk = OpaqueUtil.extract(inputKeyMaterial); + prk = OpaqueUtil.extract(inputKeyMaterial); byte[] preambleHash = OpaqueUtil.sha256(preamble); handshakeSecret = OpaqueUtil.expand( prk, OpaqueUtil.concat( - "OPAQUE-HandshakeSecret".getBytes(java.nio.charset.StandardCharsets.UTF_8), - preambleHash), + "OPAQUE-HandshakeSecret".getBytes(StandardCharsets.UTF_8), preambleHash), 32); km2 = OpaqueUtil.expand( - handshakeSecret, - "OPAQUE-ServerMAC".getBytes(java.nio.charset.StandardCharsets.UTF_8), - 32); + handshakeSecret, "OPAQUE-ServerMAC".getBytes(StandardCharsets.UTF_8), 32); km3 = OpaqueUtil.expand( - handshakeSecret, - "OPAQUE-ClientMAC".getBytes(java.nio.charset.StandardCharsets.UTF_8), - 32); + handshakeSecret, "OPAQUE-ClientMAC".getBytes(StandardCharsets.UTF_8), 32); byte[] expectedServerMac = OpaqueUtil.mac(km2, OpaqueUtil.sha256(preamble)); - if (!java.security.MessageDigest.isEqual( + if (!MessageDigest.isEqual( expectedServerMac, initialOpaqueResponse.getServerMac().toByteArray())) { throw new GeneralSecurityException("Server MAC mismatch"); } return OpaqueUtil.mac(km3, OpaqueUtil.sha256(OpaqueUtil.concat(preamble, expectedServerMac))); } finally { - if (oprf != null) java.util.Arrays.fill(oprf, (byte) 0); - if (stretchedOprf != null) java.util.Arrays.fill(stretchedOprf, (byte) 0); - if (randomizedPassword != null) java.util.Arrays.fill(randomizedPassword, (byte) 0); - if (maskingKey != null) java.util.Arrays.fill(maskingKey, (byte) 0); - if (authKey != null) java.util.Arrays.fill(authKey, (byte) 0); - if (seed != null) java.util.Arrays.fill(seed, (byte) 0); - if (dh1 != null) java.util.Arrays.fill(dh1, (byte) 0); - if (dh2 != null) java.util.Arrays.fill(dh2, (byte) 0); - if (dh3 != null) java.util.Arrays.fill(dh3, (byte) 0); - if (inputKeyMaterial != null) java.util.Arrays.fill(inputKeyMaterial, (byte) 0); - if (handshakeSecret != null) java.util.Arrays.fill(handshakeSecret, (byte) 0); - if (km2 != null) java.util.Arrays.fill(km2, (byte) 0); - if (km3 != null) java.util.Arrays.fill(km3, (byte) 0); - if (clientPrivateKey != null) java.util.Arrays.fill(clientPrivateKey, (byte) 0); + if (oprf != null) Arrays.fill(oprf, (byte) 0); + if (stretchedOprf != null) Arrays.fill(stretchedOprf, (byte) 0); + if (randomizedPassword != null) Arrays.fill(randomizedPassword, (byte) 0); + if (maskingKey != null) Arrays.fill(maskingKey, (byte) 0); + if (authKey != null) Arrays.fill(authKey, (byte) 0); + if (seed != null) Arrays.fill(seed, (byte) 0); + if (dh1 != null) Arrays.fill(dh1, (byte) 0); + if (dh2 != null) Arrays.fill(dh2, (byte) 0); + if (dh3 != null) Arrays.fill(dh3, (byte) 0); + if (inputKeyMaterial != null) Arrays.fill(inputKeyMaterial, (byte) 0); + if (handshakeSecret != null) Arrays.fill(handshakeSecret, (byte) 0); + if (km2 != null) Arrays.fill(km2, (byte) 0); + if (km3 != null) Arrays.fill(km3, (byte) 0); + if (clientPrivateKey != null) Arrays.fill(clientPrivateKey, (byte) 0); + if (prk != null) Arrays.fill(prk, (byte) 0); } } static class LoginStreamIOCall { private final LoginServiceGrpc.LoginServiceStub stub; - private final java.util.concurrent.BlockingQueue responseQueue = - new java.util.concurrent.LinkedBlockingQueue<>(); + private final BlockingQueue responseQueue = new LinkedBlockingQueue<>(); private StreamObserver requestObserver; private volatile Throwable error; private volatile boolean completed = false; diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java index 0489862e28bd..eb3ca3eddd67 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java @@ -19,6 +19,7 @@ import com.google.api.core.InternalApi; import com.google.auth.oauth2.AccessToken; import com.google.auth.oauth2.GoogleCredentials; +import com.google.common.base.Preconditions; import com.google.crypto.tink.util.SecretBytes; import io.grpc.ManagedChannel; import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder; @@ -43,9 +44,9 @@ public class SpannerOmniCredentials extends GoogleCredentials { private SslContext sslContext = null; public SpannerOmniCredentials(String username, SecretBytes password, String target) { - this.username = com.google.common.base.Preconditions.checkNotNull(username); - this.password = com.google.common.base.Preconditions.checkNotNull(password); - com.google.common.base.Preconditions.checkNotNull(target); + this.username = Preconditions.checkNotNull(username); + this.password = Preconditions.checkNotNull(password); + Preconditions.checkNotNull(target); // Parse target and initialize settings. If target starts with http://, use plaintext. if (target.startsWith("http://")) { @@ -84,8 +85,7 @@ public AccessToken refreshAccessToken() throws IOException { loginChannel = builder.build(); LoginClient loginClient = new LoginClient(loginChannel); - com.google.cloud.spanner.omni.Login.AccessToken protoToken = - loginClient.login(username, password); + Login.AccessToken protoToken = loginClient.login(username, password); String tokenValue = Base64.getEncoder().encodeToString(protoToken.toByteArray()); long expireTimeMillis = diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java index fdcb3dfbb8d5..69125e0dccd0 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2026 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; +import java.util.Arrays; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.bouncycastle.asn1.x9.X9ECParameters; @@ -222,19 +223,26 @@ public static byte[] expand(byte[] keyMaterial, byte[] info, int size) } public static byte[] stretch(byte[] input) throws GeneralSecurityException { - byte[] salt = expand(input, "Stretch".getBytes(UTF_8), ARGON2_SALT_LENGTH); - Argon2Parameters params = - new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id) - .withSalt(salt) - .withParallelism(ARGON2_THREADS) - .withMemoryAsKB(ARGON2_MEMORY_LIMIT) - .withIterations(ARGON2_ITERATION_COUNT) - .build(); - Argon2BytesGenerator generator = new Argon2BytesGenerator(); - generator.init(params); - byte[] result = new byte[STRETCH_OUTPUT_LENGTH]; - generator.generateBytes(input, result); - return result; + byte[] salt = null; + try { + salt = expand(input, "Stretch".getBytes(UTF_8), ARGON2_SALT_LENGTH); + Argon2Parameters params = + new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id) + .withSalt(salt) + .withParallelism(ARGON2_THREADS) + .withMemoryAsKB(ARGON2_MEMORY_LIMIT) + .withIterations(ARGON2_ITERATION_COUNT) + .build(); + Argon2BytesGenerator generator = new Argon2BytesGenerator(); + generator.init(params); + byte[] result = new byte[STRETCH_OUTPUT_LENGTH]; + generator.generateBytes(input, result); + return result; + } finally { + if (salt != null) { + Arrays.fill(salt, (byte) 0); + } + } } public static byte[] extract(byte[] inputKeyMaterial) throws GeneralSecurityException { diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/ExperimentalHostHelper.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/ExperimentalHostHelper.java index e2e66a0403ad..7da07f2332c1 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/ExperimentalHostHelper.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/testing/ExperimentalHostHelper.java @@ -42,10 +42,10 @@ public static void appendExperimentalHost(StringBuilder uri) { uri.append(";isExperimentalHost=true"); String username = System.getProperty(USERNAME, ""); String password = System.getProperty(PASSWORD, ""); - if (!com.google.common.base.Strings.isNullOrEmpty(username)) { + if (!Strings.isNullOrEmpty(username)) { uri.append(";username=").append(username); } - if (!com.google.common.base.Strings.isNullOrEmpty(password)) { + if (!Strings.isNullOrEmpty(password)) { uri.append(";password=").append(password); } if (isMtlsSetup()) { diff --git a/java-spanner/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITAutoRefreshTest.java b/java-spanner/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITAutoRefreshTest.java index 2388f45b3062..bf54229f0e9b 100644 --- a/java-spanner/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITAutoRefreshTest.java +++ b/java-spanner/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITAutoRefreshTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 Google LLC + * Copyright 2026 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From a848143998bf9313b5d9b654c8505e7133121b2f Mon Sep 17 00:00:00 2001 From: sagnghos Date: Tue, 9 Jun 2026 10:47:35 +0000 Subject: [PATCH 10/15] add comments --- .../cloud/spanner/omni/LoginClient.java | 40 ++++++++++--------- .../spanner/omni/SpannerOmniCredentials.java | 15 ++++++- .../cloud/spanner/omni/opaque/OpaqueUtil.java | 8 ++++ 3 files changed, 42 insertions(+), 21 deletions(-) diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java index ddced4827799..7342a0de7e54 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java @@ -62,6 +62,7 @@ public AccessToken login(String username, SecretBytes password) throws SpannerEx Preconditions.checkNotNull(password); byte[] passwordBytes = null; byte[] clientPrivateKeyshare = null; + byte[] blind = null; try { passwordBytes = password.toByteArray(InsecureSecretKeyAccess.get()); byte[] randomNonce = OpaqueUtil.nonce(); @@ -73,7 +74,7 @@ public AccessToken login(String username, SecretBytes password) throws SpannerEx clientPrivateKeyshare = keyPair[0]; byte[] clientPublicKeyshare = keyPair[1]; byte[] clientNonce = OpaqueUtil.nonce(); - byte[] blind = new byte[32]; + blind = new byte[32]; SECURE_RANDOM.nextBytes(blind); byte[] blindedMessage = OpaqueUtil.blind(passwordBytes, blind); @@ -151,12 +152,17 @@ public AccessToken login(String username, SecretBytes password) throws SpannerEx } throw SpannerExceptionFactory.newSpannerException(e); } finally { + // Securely zero out all intermediate sensitive buffers to prevent them + // from persisting in heap dumps or lingering in memory (memory scraping attacks). if (passwordBytes != null) { Arrays.fill(passwordBytes, (byte) 0); } if (clientPrivateKeyshare != null) { Arrays.fill(clientPrivateKeyshare, (byte) 0); } + if (blind != null) { + Arrays.fill(blind, (byte) 0); + } } } @@ -234,6 +240,8 @@ private byte[] generateClientMac( envelopeNonce.toByteArray(), serverPublicKey.toByteArray(), username.getBytes(StandardCharsets.UTF_8))); + // Use MessageDigest.isEqual for constant-time comparison to prevent timing attacks. + // A standard Arrays.equals or ByteString.equals fails fast and can reveal byte matches. if (!MessageDigest.isEqual(expectedTag, authTag.toByteArray())) { throw new GeneralSecurityException("Auth tag mismatch"); } @@ -280,6 +288,7 @@ private byte[] generateClientMac( } return OpaqueUtil.mac(km3, OpaqueUtil.sha256(OpaqueUtil.concat(preamble, expectedServerMac))); } finally { + // Zero out derived keys and diffie-hellman secrets to prevent credential scraping. if (oprf != null) Arrays.fill(oprf, (byte) 0); if (stretchedOprf != null) Arrays.fill(stretchedOprf, (byte) 0); if (randomizedPassword != null) Arrays.fill(randomizedPassword, (byte) 0); @@ -299,11 +308,10 @@ private byte[] generateClientMac( } static class LoginStreamIOCall { + private static final Object COMPLETED_SENTINEL = new Object(); private final LoginServiceGrpc.LoginServiceStub stub; - private final BlockingQueue responseQueue = new LinkedBlockingQueue<>(); + private final BlockingQueue responseQueue = new LinkedBlockingQueue<>(); private StreamObserver requestObserver; - private volatile Throwable error; - private volatile boolean completed = false; LoginStreamIOCall(LoginServiceGrpc.LoginServiceStub stub) { this.stub = stub; @@ -317,16 +325,12 @@ public void onNext(LoginResponse value) { @Override public void onError(Throwable t) { - error = t; - // Add a dummy response to unblock getResponse if it's waiting - responseQueue.add(LoginResponse.getDefaultInstance()); + responseQueue.add(t); } @Override public void onCompleted() { - completed = true; - // Add a dummy response to unblock getResponse if it's waiting - responseQueue.add(LoginResponse.getDefaultInstance()); + responseQueue.add(COMPLETED_SENTINEL); } }); } @@ -336,16 +340,14 @@ void send(LoginRequest request) { } LoginResponse getResponse() throws InterruptedException { - LoginResponse response = responseQueue.take(); - if (response == LoginResponse.getDefaultInstance()) { - if (error != null) { - throw SpannerExceptionFactory.newSpannerException(error); - } - if (completed) { - return null; - } + Object response = responseQueue.take(); + if (response instanceof Throwable) { + throw SpannerExceptionFactory.newSpannerException((Throwable) response); + } + if (response == COMPLETED_SENTINEL) { + return null; } - return response; + return (LoginResponse) response; } void halfClose() { diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java index eb3ca3eddd67..fb091605144c 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java @@ -19,6 +19,7 @@ import com.google.api.core.InternalApi; import com.google.auth.oauth2.AccessToken; import com.google.auth.oauth2.GoogleCredentials; +import com.google.cloud.spanner.SpannerExceptionFactory; import com.google.common.base.Preconditions; import com.google.crypto.tink.util.SecretBytes; import io.grpc.ManagedChannel; @@ -74,6 +75,10 @@ public void initChannel(boolean usePlainText, SslContext sslContext) { @Override public AccessToken refreshAccessToken() throws IOException { + // Create a new gRPC channel for every token refresh. We don't reuse a persistent channel + // because token refresh happens infrequently (e.g. once an hour) and keeping a long-lived + // connection open can lead to resource leaks (threads, TCP connections) if the credentials + // object is discarded without explicit shutdown. ManagedChannel loginChannel = null; try { NettyChannelBuilder builder = NettyChannelBuilder.forTarget(this.target); @@ -103,12 +108,18 @@ public AccessToken refreshAccessToken() throws IOException { } throw new IOException("Failed to login to Spanner Omni", e); } finally { + // Ensure the channel is shut down immediately after the token is fetched + // to avoid leaking any Netty threads or HTTP/2 connections. if (loginChannel != null) { - loginChannel.shutdownNow(); + loginChannel.shutdown(); try { - loginChannel.awaitTermination(5, TimeUnit.SECONDS); + if (!loginChannel.awaitTermination(5, TimeUnit.SECONDS)) { + loginChannel.shutdownNow(); + } } catch (InterruptedException e) { + loginChannel.shutdownNow(); Thread.currentThread().interrupt(); + throw SpannerExceptionFactory.newSpannerException(e); } } } diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java index 69125e0dccd0..0968b08489d6 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java @@ -186,6 +186,8 @@ private static ECPoint mapToCurveSSWU(BigInteger u, ECCurve curve) { public static byte[] getHashToCurve(byte[] message, byte[] domain) throws GeneralSecurityException { + // Implements hash-to-curve using the Simplified SWU (SSWU) mapping. + // This securely and uniformly maps an arbitrary string (the password) onto the elliptic curve. byte[] uniformBytes = expandMessageXmd(message, domain, 96); byte[] u0Bytes = new byte[48]; byte[] u1Bytes = new byte[48]; @@ -223,6 +225,8 @@ public static byte[] expand(byte[] keyMaterial, byte[] info, int size) } public static byte[] stretch(byte[] input) throws GeneralSecurityException { + // Stretches the OPRF evaluation using Argon2 (a memory-hard KDF). + // This is computationally expensive by design to protect against offline dictionary attacks. byte[] salt = null; try { salt = expand(input, "Stretch".getBytes(UTF_8), ARGON2_SALT_LENGTH); @@ -305,6 +309,10 @@ public static byte[] diffieHellman(byte[] privateKey, byte[] peerPublicKey) public static byte[] randomOracleSha256(byte[] x, BigInteger max) throws GeneralSecurityException { + // Implements a random oracle mapping using iterated SHA-256 blocks. + // Iteratively hashes the input and a block counter to generate a large uniformly distributed + // integer, + // which is then reduced modulo 'max'. int hashOutputLength = 256; int outputBitLength = max.bitLength() + hashOutputLength; int iterCount = (int) Math.ceil((double) outputBitLength / hashOutputLength); From 59fa4dcabfb3a6655b5923cc83eb4431bb1a9613 Mon Sep 17 00:00:00 2001 From: sagnghos Date: Tue, 9 Jun 2026 11:02:45 +0000 Subject: [PATCH 11/15] address gemini comments - 3 --- .../google/cloud/spanner/SpannerOptions.java | 5 ++--- .../spanner/connection/ConnectionOptions.java | 21 +++++++++++++++++-- .../cloud/spanner/omni/LoginClient.java | 20 +++++++++++++----- .../cloud/spanner/omni/opaque/OpaqueUtil.java | 7 ++++++- 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java index 94958e02ff79..300ad3f61e9c 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java @@ -2189,9 +2189,8 @@ public SpannerOptions build() { } else if (experimentalHost != null && credentials == null) { credentials = environment.getDefaultExperimentalHostCredentials(); } - if (credentials instanceof com.google.cloud.spanner.omni.SpannerOmniCredentials) { - ((com.google.cloud.spanner.omni.SpannerOmniCredentials) credentials) - .initChannel(this.usePlainText, this.mTLSContext); + if (credentials instanceof SpannerOmniCredentials) { + ((SpannerOmniCredentials) credentials).initChannel(this.usePlainText, this.mTLSContext); } if (this.numChannels == null) { this.numChannels = diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java index 422a121444b7..bfad540e9520 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java @@ -98,6 +98,9 @@ import io.opentelemetry.api.OpenTelemetry; import java.io.IOException; import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharsetEncoder; import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.ArrayList; @@ -765,12 +768,26 @@ && getInitialConnectionPropertyValue(OAUTH_TOKEN) == null } else if ((isExperimentalHostPattern || isExperimentalHost()) && !Strings.isNullOrEmpty(username) && !Strings.isNullOrEmpty(password)) { - byte[] passwordBytes = password.getBytes(StandardCharsets.UTF_8); + char[] passwordChars = password.toCharArray(); + byte[] passwordBytes = null; SecretBytes secretBytes; try { + CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder(); + CharBuffer charBuffer = CharBuffer.wrap(passwordChars); + ByteBuffer byteBuffer = + ByteBuffer.allocate((int) (encoder.maxBytesPerChar() * charBuffer.remaining())); + encoder.encode(charBuffer, byteBuffer, true); + encoder.flush(byteBuffer); + byteBuffer.flip(); + passwordBytes = new byte[byteBuffer.remaining()]; + byteBuffer.get(passwordBytes); + Arrays.fill(byteBuffer.array(), (byte) 0); secretBytes = SecretBytes.copyFrom(passwordBytes, InsecureSecretKeyAccess.get()); } finally { - Arrays.fill(passwordBytes, (byte) 0); + if (passwordBytes != null) { + Arrays.fill(passwordBytes, (byte) 0); + } + Arrays.fill(passwordChars, '\0'); } this.credentials = new SpannerOmniCredentials(username, secretBytes, this.host); } else if ((isExperimentalHostPattern || isExperimentalHost()) diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java index 7342a0de7e54..7524b45791a9 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java @@ -193,7 +193,12 @@ private byte[] generateClientMac( try { oprf = OpaqueUtil.finalize(blind, initialOpaqueResponse.getEvaluatedMessage().toByteArray()); stretchedOprf = OpaqueUtil.stretch(oprf); - randomizedPassword = OpaqueUtil.extract(OpaqueUtil.concat(oprf, stretchedOprf)); + byte[] oprfConcat = OpaqueUtil.concat(oprf, stretchedOprf); + try { + randomizedPassword = OpaqueUtil.extract(oprfConcat); + } finally { + Arrays.fill(oprfConcat, (byte) 0); + } maskingKey = OpaqueUtil.expand( randomizedPassword, OpaqueUtil.MASKING_KEY_INFO.getBytes(StandardCharsets.UTF_8), 32); @@ -226,10 +231,15 @@ private byte[] generateClientMac( envelopeNonce.toByteArray(), OpaqueUtil.PRIVATE_KEY_INFO.getBytes(StandardCharsets.UTF_8)), 32); - byte[][] clientKeyPair = - OpaqueUtil.generateKeyPair( - OpaqueUtil.concat( - seed, OpaqueUtil.DIFFIE_HELLMAN_KEY_INFO.getBytes(StandardCharsets.UTF_8))); + byte[] seedConcat = + OpaqueUtil.concat( + seed, OpaqueUtil.DIFFIE_HELLMAN_KEY_INFO.getBytes(StandardCharsets.UTF_8)); + byte[][] clientKeyPair; + try { + clientKeyPair = OpaqueUtil.generateKeyPair(seedConcat); + } finally { + Arrays.fill(seedConcat, (byte) 0); + } clientPrivateKey = clientKeyPair[0]; byte[] clientPublicKey = clientKeyPair[1]; diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java index 0968b08489d6..e86e86afc85a 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java @@ -327,7 +327,12 @@ public static byte[] randomOracleSha256(byte[] x, BigInteger max) byte[] iBytes = new byte[] {(byte) i}; byte[] bignumBytes = concat(iBytes, x); - byte[] hashedString = sha256(bignumBytes); + byte[] hashedString; + try { + hashedString = sha256(bignumBytes); + } finally { + Arrays.fill(bignumBytes, (byte) 0); + } // Ensure hashedString is treated as a positive integer BigInteger newBigNum = new BigInteger(1, hashedString); From 9db4074295185fdff328ee24b93e8f51e87ee552 Mon Sep 17 00:00:00 2001 From: sagnghos Date: Tue, 9 Jun 2026 11:37:04 +0000 Subject: [PATCH 12/15] address gemini comments - 4 --- .../cloud/spanner/omni/LoginClient.java | 162 ++++++++++-------- 1 file changed, 92 insertions(+), 70 deletions(-) diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java index 7524b45791a9..5044739d6198 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java @@ -46,7 +46,7 @@ public class LoginClient { private final LoginServiceGrpc.LoginServiceStub stub; public LoginClient(ManagedChannel channel) { - this.stub = LoginServiceGrpc.newStub(channel).withDeadlineAfter(60, TimeUnit.SECONDS); + this.stub = LoginServiceGrpc.newStub(channel); } /** @@ -79,73 +79,81 @@ public AccessToken login(String username, SecretBytes password) throws SpannerEx byte[] blindedMessage = OpaqueUtil.blind(passwordBytes, blind); - LoginStreamIOCall call = new LoginStreamIOCall(stub); - - // 1. Send Handshake Request - LoginRequest handshakeRequest = - LoginRequest.newBuilder() - .setUsername(username) - .setHandshakeRequest(AuthenticationHandshakeRequest.newBuilder()) - .build(); - call.send(handshakeRequest); - LoginResponse handshakeResponse = call.getResponse(); - - if (handshakeResponse == null || !handshakeResponse.hasHandshakeResponse()) { - throw SpannerExceptionFactory.newSpannerException( - com.google.cloud.spanner.ErrorCode.UNAUTHENTICATED, - "Failed to receive handshake response from server."); + try (LoginStreamIOCall call = + new LoginStreamIOCall(stub.withDeadlineAfter(60, TimeUnit.SECONDS))) { + + // 1. Send Handshake Request + LoginRequest handshakeRequest = + LoginRequest.newBuilder() + .setUsername(username) + .setHandshakeRequest(AuthenticationHandshakeRequest.newBuilder()) + .build(); + call.send(handshakeRequest); + LoginResponse handshakeResponse = call.getResponse(); + + if (handshakeResponse == null || !handshakeResponse.hasHandshakeResponse()) { + throw SpannerExceptionFactory.newSpannerException( + com.google.cloud.spanner.ErrorCode.UNAUTHENTICATED, + "Failed to receive handshake response from server."); + } + + AuthenticationMethod method = + handshakeResponse.getHandshakeResponse().getAuthenticationMethod(); + if (method != AuthenticationMethod.AUTHENTICATION_METHOD_OPAQUE) { + throw SpannerExceptionFactory.newSpannerException( + com.google.cloud.spanner.ErrorCode.UNAUTHENTICATED, + "Unsupported authentication method: " + method); + } + + // 2. Send Initial OPAQUE Request + LoginRequest initialRequest = + LoginRequest.newBuilder() + .setUsername(username) + .setOpaqueRequest( + OpaqueLoginRequest.newBuilder() + .setInitialRequest( + InitialOpaqueLoginRequest.newBuilder() + .setBlindedMessage(ByteString.copyFrom(blindedMessage)) + .setClientNonce(ByteString.copyFrom(clientNonce)) + .setClientPublicKeyshare( + ByteString.copyFrom(clientPublicKeyshare)))) + .build(); + + call.send(initialRequest); + LoginResponse initialResponse = call.getResponse(); + + InitialOpaqueLoginResponse initialOpaqueResponse = + initialResponse.getOpaqueResponse().getInitialResponse(); + + byte[] clientMac = + generateClientMac( + username, + blind, + clientNonce, + clientPublicKeyshare, + clientPrivateKeyshare, + initialOpaqueResponse); + + LoginRequest finalRequest = + LoginRequest.newBuilder() + .setUsername(username) + .setOpaqueRequest( + OpaqueLoginRequest.newBuilder() + .setFinalRequest( + FinalOpaqueLoginRequest.newBuilder() + .setClientMac(ByteString.copyFrom(clientMac)))) + .build(); + + call.send(finalRequest); + call.halfClose(); + LoginResponse finalResponse = call.getResponse(); + if (finalResponse == null) { + throw SpannerExceptionFactory.newSpannerException( + com.google.cloud.spanner.ErrorCode.UNAUTHENTICATED, + "Server closed the stream without returning an access token."); + } + return finalResponse.getAccessToken(); } - - AuthenticationMethod method = - handshakeResponse.getHandshakeResponse().getAuthenticationMethod(); - if (method != AuthenticationMethod.AUTHENTICATION_METHOD_OPAQUE) { - throw SpannerExceptionFactory.newSpannerException( - com.google.cloud.spanner.ErrorCode.UNAUTHENTICATED, - "Unsupported authentication method: " + method); - } - - // 2. Send Initial OPAQUE Request - LoginRequest initialRequest = - LoginRequest.newBuilder() - .setUsername(username) - .setOpaqueRequest( - OpaqueLoginRequest.newBuilder() - .setInitialRequest( - InitialOpaqueLoginRequest.newBuilder() - .setBlindedMessage(ByteString.copyFrom(blindedMessage)) - .setClientNonce(ByteString.copyFrom(clientNonce)) - .setClientPublicKeyshare(ByteString.copyFrom(clientPublicKeyshare)))) - .build(); - - call.send(initialRequest); - LoginResponse initialResponse = call.getResponse(); - - InitialOpaqueLoginResponse initialOpaqueResponse = - initialResponse.getOpaqueResponse().getInitialResponse(); - - byte[] clientMac = - generateClientMac( - username, - blind, - clientNonce, - clientPublicKeyshare, - clientPrivateKeyshare, - initialOpaqueResponse); - - LoginRequest finalRequest = - LoginRequest.newBuilder() - .setUsername(username) - .setOpaqueRequest( - OpaqueLoginRequest.newBuilder() - .setFinalRequest( - FinalOpaqueLoginRequest.newBuilder() - .setClientMac(ByteString.copyFrom(clientMac)))) - .build(); - - call.send(finalRequest); - call.halfClose(); - LoginResponse finalResponse = call.getResponse(); - return finalResponse.getAccessToken(); } catch (Exception e) { if (e instanceof InterruptedException) { Thread.currentThread().interrupt(); @@ -317,15 +325,16 @@ private byte[] generateClientMac( } } - static class LoginStreamIOCall { + static class LoginStreamIOCall implements AutoCloseable { private static final Object COMPLETED_SENTINEL = new Object(); private final LoginServiceGrpc.LoginServiceStub stub; private final BlockingQueue responseQueue = new LinkedBlockingQueue<>(); - private StreamObserver requestObserver; + private final StreamObserver requestObserver; + private boolean closed = false; LoginStreamIOCall(LoginServiceGrpc.LoginServiceStub stub) { this.stub = stub; - requestObserver = + this.requestObserver = stub.login( new StreamObserver() { @Override @@ -362,6 +371,19 @@ LoginResponse getResponse() throws InterruptedException { void halfClose() { requestObserver.onCompleted(); + closed = true; + } + + @Override + public void close() { + if (!closed) { + closed = true; + try { + requestObserver.onError(new RuntimeException("Client cancelled the login stream")); + } catch (Exception e) { + // Ignore + } + } } } } From f0730f1504be61d6d30ccb5386169d5f0e5612d2 Mon Sep 17 00:00:00 2001 From: sagnghos Date: Tue, 9 Jun 2026 12:15:07 +0000 Subject: [PATCH 13/15] address gemini comments - 5 --- .../google/cloud/spanner/SpannerOptions.java | 31 ++------------ .../spanner/connection/ConnectionOptions.java | 28 +------------ .../cloud/spanner/omni/LoginClient.java | 4 +- .../spanner/omni/SpannerOmniCredentials.java | 41 +++++++++++++++---- 4 files changed, 41 insertions(+), 63 deletions(-) diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java index 300ad3f61e9c..59218d45fef4 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java @@ -67,7 +67,6 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.ThreadFactoryBuilder; -import com.google.crypto.tink.InsecureSecretKeyAccess; import com.google.crypto.tink.util.SecretBytes; import com.google.spanner.v1.DirectedReadOptions; import com.google.spanner.v1.ExecuteSqlRequest; @@ -94,15 +93,10 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.time.Duration; import java.util.ArrayList; -import java.util.Arrays; import java.util.Base64; import java.util.HashMap; import java.util.List; @@ -1830,6 +1824,9 @@ public Builder setExperimentalHost(String host) { * resulting token for use in subsequent Spanner API calls. The endpoint must be set on the * builder before calling this method. * + *

Note: The provided {@code password} array will be cleared (zeroed out) by this method for + * security purposes. + * * @param username The username for login. * @param password The password for login. * @return this builder @@ -1843,27 +1840,7 @@ public Builder login(String username, char[] password) { Preconditions.checkArgument( password != null && password.length > 0, "password cannot be null or empty"); - byte[] passwordBytes = null; - SecretBytes secretBytes; - try { - CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder(); - CharBuffer charBuffer = CharBuffer.wrap(password); - ByteBuffer byteBuffer = - ByteBuffer.allocate((int) (encoder.maxBytesPerChar() * charBuffer.remaining())); - encoder.encode(charBuffer, byteBuffer, true); - encoder.flush(byteBuffer); - byteBuffer.flip(); - passwordBytes = new byte[byteBuffer.remaining()]; - byteBuffer.get(passwordBytes); - Arrays.fill(byteBuffer.array(), (byte) 0); - - secretBytes = SecretBytes.copyFrom(passwordBytes, InsecureSecretKeyAccess.get()); - } finally { - if (passwordBytes != null) { - Arrays.fill(passwordBytes, (byte) 0); - } - Arrays.fill(password, '\0'); - } + SecretBytes secretBytes = SpannerOmniCredentials.convertToSecretBytes(password); super.setCredentials( new SpannerOmniCredentials(username, secretBytes, this.experimentalHost)); diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java index bfad540e9520..697debd0e3dd 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java @@ -91,20 +91,14 @@ import com.google.common.base.Strings; import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableMap; -import com.google.crypto.tink.InsecureSecretKeyAccess; import com.google.crypto.tink.util.SecretBytes; import io.grpc.Deadline; import io.grpc.Deadline.Ticker; import io.opentelemetry.api.OpenTelemetry; import java.io.IOException; import java.net.URL; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -768,27 +762,7 @@ && getInitialConnectionPropertyValue(OAUTH_TOKEN) == null } else if ((isExperimentalHostPattern || isExperimentalHost()) && !Strings.isNullOrEmpty(username) && !Strings.isNullOrEmpty(password)) { - char[] passwordChars = password.toCharArray(); - byte[] passwordBytes = null; - SecretBytes secretBytes; - try { - CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder(); - CharBuffer charBuffer = CharBuffer.wrap(passwordChars); - ByteBuffer byteBuffer = - ByteBuffer.allocate((int) (encoder.maxBytesPerChar() * charBuffer.remaining())); - encoder.encode(charBuffer, byteBuffer, true); - encoder.flush(byteBuffer); - byteBuffer.flip(); - passwordBytes = new byte[byteBuffer.remaining()]; - byteBuffer.get(passwordBytes); - Arrays.fill(byteBuffer.array(), (byte) 0); - secretBytes = SecretBytes.copyFrom(passwordBytes, InsecureSecretKeyAccess.get()); - } finally { - if (passwordBytes != null) { - Arrays.fill(passwordBytes, (byte) 0); - } - Arrays.fill(passwordChars, '\0'); - } + SecretBytes secretBytes = SpannerOmniCredentials.convertToSecretBytes(password.toCharArray()); this.credentials = new SpannerOmniCredentials(username, secretBytes, this.host); } else if ((isExperimentalHostPattern || isExperimentalHost()) && defaultExperimentalHostCredentials != null) { diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java index 5044739d6198..7b4827dc42da 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java @@ -147,10 +147,10 @@ public AccessToken login(String username, SecretBytes password) throws SpannerEx call.send(finalRequest); call.halfClose(); LoginResponse finalResponse = call.getResponse(); - if (finalResponse == null) { + if (!finalResponse.hasAccessToken()) { throw SpannerExceptionFactory.newSpannerException( com.google.cloud.spanner.ErrorCode.UNAUTHENTICATED, - "Server closed the stream without returning an access token."); + "Server failed to return an access token."); } return finalResponse.getAccessToken(); } diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java index fb091605144c..dc67e7dbd39b 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/SpannerOmniCredentials.java @@ -19,13 +19,17 @@ import com.google.api.core.InternalApi; import com.google.auth.oauth2.AccessToken; import com.google.auth.oauth2.GoogleCredentials; -import com.google.cloud.spanner.SpannerExceptionFactory; import com.google.common.base.Preconditions; import com.google.crypto.tink.util.SecretBytes; import io.grpc.ManagedChannel; import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder; import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext; import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; import java.util.Base64; import java.util.Date; import java.util.concurrent.TimeUnit; @@ -44,6 +48,29 @@ public class SpannerOmniCredentials extends GoogleCredentials { private boolean usePlainText = false; private SslContext sslContext = null; + public static SecretBytes convertToSecretBytes(char[] passwordChars) { + byte[] passwordBytes = null; + try { + CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder(); + CharBuffer charBuffer = CharBuffer.wrap(passwordChars); + ByteBuffer byteBuffer = + ByteBuffer.allocate((int) (encoder.maxBytesPerChar() * charBuffer.remaining())); + encoder.encode(charBuffer, byteBuffer, true); + encoder.flush(byteBuffer); + byteBuffer.flip(); + passwordBytes = new byte[byteBuffer.remaining()]; + byteBuffer.get(passwordBytes); + Arrays.fill(byteBuffer.array(), (byte) 0); + return SecretBytes.copyFrom( + passwordBytes, com.google.crypto.tink.InsecureSecretKeyAccess.get()); + } finally { + if (passwordBytes != null) { + Arrays.fill(passwordBytes, (byte) 0); + } + Arrays.fill(passwordChars, '\0'); + } + } + public SpannerOmniCredentials(String username, SecretBytes password, String target) { this.username = Preconditions.checkNotNull(username); this.password = Preconditions.checkNotNull(password); @@ -93,11 +120,12 @@ public AccessToken refreshAccessToken() throws IOException { Login.AccessToken protoToken = loginClient.login(username, password); String tokenValue = Base64.getEncoder().encodeToString(protoToken.toByteArray()); - long expireTimeMillis = - protoToken.getExpirationTime().getSeconds() * 1000 - + protoToken.getExpirationTime().getNanos() / 1000000; - - if (expireTimeMillis <= System.currentTimeMillis()) { + long expireTimeMillis; + if (protoToken.hasExpirationTime()) { + expireTimeMillis = + protoToken.getExpirationTime().getSeconds() * 1000 + + protoToken.getExpirationTime().getNanos() / 1000000; + } else { expireTimeMillis = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(60); } @@ -119,7 +147,6 @@ public AccessToken refreshAccessToken() throws IOException { } catch (InterruptedException e) { loginChannel.shutdownNow(); Thread.currentThread().interrupt(); - throw SpannerExceptionFactory.newSpannerException(e); } } } From 9632caf10a5ae7545e9334a6a031731a99a622a8 Mon Sep 17 00:00:00 2001 From: sagnghos Date: Tue, 9 Jun 2026 12:48:32 +0000 Subject: [PATCH 14/15] address gemini comments - 6 --- .../cloud/spanner/omni/LoginClient.java | 10 +- .../cloud/spanner/omni/opaque/OpaqueUtil.java | 148 +++++++++++------- 2 files changed, 97 insertions(+), 61 deletions(-) diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java index 7b4827dc42da..304980401d88 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java @@ -63,6 +63,7 @@ public AccessToken login(String username, SecretBytes password) throws SpannerEx byte[] passwordBytes = null; byte[] clientPrivateKeyshare = null; byte[] blind = null; + byte[] blindedMessage = null; try { passwordBytes = password.toByteArray(InsecureSecretKeyAccess.get()); byte[] randomNonce = OpaqueUtil.nonce(); @@ -77,7 +78,7 @@ public AccessToken login(String username, SecretBytes password) throws SpannerEx blind = new byte[32]; SECURE_RANDOM.nextBytes(blind); - byte[] blindedMessage = OpaqueUtil.blind(passwordBytes, blind); + blindedMessage = OpaqueUtil.blind(passwordBytes, blind); try (LoginStreamIOCall call = new LoginStreamIOCall(stub.withDeadlineAfter(60, TimeUnit.SECONDS))) { @@ -171,6 +172,9 @@ public AccessToken login(String username, SecretBytes password) throws SpannerEx if (blind != null) { Arrays.fill(blind, (byte) 0); } + if (blindedMessage != null) { + Arrays.fill(blindedMessage, (byte) 0); + } } } @@ -186,6 +190,7 @@ private byte[] generateClientMac( byte[] stretchedOprf = null; byte[] randomizedPassword = null; byte[] maskingKey = null; + byte[] credentialResponsePad = null; byte[] authKey = null; byte[] seed = null; byte[] dh1 = null; @@ -210,7 +215,7 @@ private byte[] generateClientMac( maskingKey = OpaqueUtil.expand( randomizedPassword, OpaqueUtil.MASKING_KEY_INFO.getBytes(StandardCharsets.UTF_8), 32); - byte[] credentialResponsePad = + credentialResponsePad = OpaqueUtil.expand( maskingKey, OpaqueUtil.concat( @@ -311,6 +316,7 @@ private byte[] generateClientMac( if (stretchedOprf != null) Arrays.fill(stretchedOprf, (byte) 0); if (randomizedPassword != null) Arrays.fill(randomizedPassword, (byte) 0); if (maskingKey != null) Arrays.fill(maskingKey, (byte) 0); + if (credentialResponsePad != null) Arrays.fill(credentialResponsePad, (byte) 0); if (authKey != null) Arrays.fill(authKey, (byte) 0); if (seed != null) Arrays.fill(seed, (byte) 0); if (dh1 != null) Arrays.fill(dh1, (byte) 0); diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java index e86e86afc85a..c68d4d3ebdad 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/opaque/OpaqueUtil.java @@ -97,37 +97,47 @@ private static byte[] expandMessageXmd(byte[] msg, byte[] DST, int lenInBytes) byte[] zPad = new byte[64]; byte[] libStr = new byte[] {(byte) (lenInBytes >> 8), (byte) (lenInBytes & 0xFF)}; - md.update(zPad); - md.update(msg); - md.update(libStr); - md.update((byte) 0); - md.update(dstPrime); - byte[] b0 = md.digest(); - - byte[] bOut = new byte[ell * bInBytes]; - - md.update(b0); - md.update((byte) 1); - md.update(dstPrime); - byte[] b1 = md.digest(); - System.arraycopy(b1, 0, bOut, 0, bInBytes); - - byte[] bi = b1; - for (int i = 2; i <= ell; i++) { - byte[] bXor = new byte[bInBytes]; - for (int j = 0; j < bInBytes; j++) { - bXor[j] = (byte) (b0[j] ^ bi[j]); - } - md.update(bXor); - md.update((byte) i); + byte[] b0 = null; + byte[] bOut = null; + byte[] b1 = null; + + try { + md.update(zPad); + md.update(msg); + md.update(libStr); + md.update((byte) 0); md.update(dstPrime); - bi = md.digest(); - System.arraycopy(bi, 0, bOut, (i - 1) * bInBytes, bInBytes); - } + b0 = md.digest(); + + bOut = new byte[ell * bInBytes]; - byte[] res = new byte[lenInBytes]; - System.arraycopy(bOut, 0, res, 0, lenInBytes); - return res; + md.update(b0); + md.update((byte) 1); + md.update(dstPrime); + b1 = md.digest(); + System.arraycopy(b1, 0, bOut, 0, bInBytes); + + byte[] bi = b1; + for (int i = 2; i <= ell; i++) { + byte[] bXor = new byte[bInBytes]; + for (int j = 0; j < bInBytes; j++) { + bXor[j] = (byte) (b0[j] ^ bi[j]); + } + md.update(bXor); + md.update((byte) i); + md.update(dstPrime); + bi = md.digest(); + System.arraycopy(bi, 0, bOut, (i - 1) * bInBytes, bInBytes); + } + + byte[] res = new byte[lenInBytes]; + System.arraycopy(bOut, 0, res, 0, lenInBytes); + return res; + } finally { + if (b0 != null) Arrays.fill(b0, (byte) 0); + if (bOut != null) Arrays.fill(bOut, (byte) 0); + if (b1 != null) Arrays.fill(b1, (byte) 0); + } } catch (Exception e) { throw new GeneralSecurityException("Failed to expand message", e); } @@ -188,23 +198,38 @@ public static byte[] getHashToCurve(byte[] message, byte[] domain) throws GeneralSecurityException { // Implements hash-to-curve using the Simplified SWU (SSWU) mapping. // This securely and uniformly maps an arbitrary string (the password) onto the elliptic curve. - byte[] uniformBytes = expandMessageXmd(message, domain, 96); - byte[] u0Bytes = new byte[48]; - byte[] u1Bytes = new byte[48]; - System.arraycopy(uniformBytes, 0, u0Bytes, 0, 48); - System.arraycopy(uniformBytes, 48, u1Bytes, 0, 48); + byte[] uniformBytes = null; + byte[] u0Bytes = null; + byte[] u1Bytes = null; + try { + uniformBytes = expandMessageXmd(message, domain, 96); + u0Bytes = new byte[48]; + u1Bytes = new byte[48]; + System.arraycopy(uniformBytes, 0, u0Bytes, 0, 48); + System.arraycopy(uniformBytes, 48, u1Bytes, 0, 48); - BigInteger u0 = new BigInteger(1, u0Bytes).mod(p); - BigInteger u1 = new BigInteger(1, u1Bytes).mod(p); + BigInteger u0 = new BigInteger(1, u0Bytes).mod(p); + BigInteger u1 = new BigInteger(1, u1Bytes).mod(p); - X9ECParameters params = CustomNamedCurves.getByName(CURVE_NAME); - ECCurve curve = params.getCurve(); + X9ECParameters params = CustomNamedCurves.getByName(CURVE_NAME); + ECCurve curve = params.getCurve(); - ECPoint q0 = mapToCurveSSWU(u0, curve); - ECPoint q1 = mapToCurveSSWU(u1, curve); + ECPoint q0 = mapToCurveSSWU(u0, curve); + ECPoint q1 = mapToCurveSSWU(u1, curve); - ECPoint r = q0.add(q1).normalize(); - return r.getEncoded(true); + ECPoint r = q0.add(q1).normalize(); + return r.getEncoded(true); + } finally { + if (uniformBytes != null) { + Arrays.fill(uniformBytes, (byte) 0); + } + if (u0Bytes != null) { + Arrays.fill(u0Bytes, (byte) 0); + } + if (u1Bytes != null) { + Arrays.fill(u1Bytes, (byte) 0); + } + } } public static byte[] blind(byte[] password, byte[] blindScalar) throws GeneralSecurityException { @@ -336,6 +361,7 @@ public static byte[] randomOracleSha256(byte[] x, BigInteger max) // Ensure hashedString is treated as a positive integer BigInteger newBigNum = new BigInteger(1, hashedString); + Arrays.fill(hashedString, (byte) 0); hashOutput = hashOutput.add(newBigNum); } @@ -346,24 +372,28 @@ public static byte[] randomOracleSha256(byte[] x, BigInteger max) byte[] scalarBytes = new byte[hashOutputLength / 8]; byte[] hashOutputBytes = hashOutput.toByteArray(); - // Copy into 32 byte array - if (hashOutputBytes.length <= scalarBytes.length) { - System.arraycopy( - hashOutputBytes, - 0, - scalarBytes, - scalarBytes.length - hashOutputBytes.length, - hashOutputBytes.length); - } else { - // If hashOutputBytes is 33 bytes due to sign bit - System.arraycopy( - hashOutputBytes, - hashOutputBytes.length - scalarBytes.length, - scalarBytes, - 0, - scalarBytes.length); + try { + // Copy into 32 byte array + if (hashOutputBytes.length <= scalarBytes.length) { + System.arraycopy( + hashOutputBytes, + 0, + scalarBytes, + scalarBytes.length - hashOutputBytes.length, + hashOutputBytes.length); + } else { + // If hashOutputBytes is 33 bytes due to sign bit + System.arraycopy( + hashOutputBytes, + hashOutputBytes.length - scalarBytes.length, + scalarBytes, + 0, + scalarBytes.length); + } + return scalarBytes; + } finally { + Arrays.fill(hashOutputBytes, (byte) 0); } - return scalarBytes; } public static byte[][] generateKeyPair(byte[] deriveInput) throws GeneralSecurityException { From 91538f7e5b1ea4c019ce860d6623f24a579f5ac7 Mon Sep 17 00:00:00 2001 From: sagnghos Date: Tue, 9 Jun 2026 13:15:46 +0000 Subject: [PATCH 15/15] address gemini comments - 7 --- .../main/java/com/google/cloud/spanner/omni/LoginClient.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java index 304980401d88..0d7715cbb919 100644 --- a/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java +++ b/java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/omni/LoginClient.java @@ -226,6 +226,9 @@ private byte[] generateClientMac( OpaqueUtil.xorBytes( initialOpaqueResponse.getMaskedResponse().toByteArray(), credentialResponsePad); ByteString envelope = ByteString.copyFrom(serializedEnvelope); + if (envelope.size() < 65) { + throw new GeneralSecurityException("Invalid envelope size: " + envelope.size()); + } ByteString serverPublicKey = envelope.substring(0, 33); ByteString envelopeNonce = envelope.substring(33, 33 + 16); ByteString authTag = envelope.substring(33 + 16, 33 + 16 + 16);