8989import com .google .cloud .spanner .SpannerOptions ;
9090import com .google .cloud .spanner .connection .ClientSideStatementValueConverters .GrpcInterceptorProviderConverter ;
9191import com .google .cloud .spanner .connection .StatementExecutor .StatementExecutorType ;
92+ import com .google .cloud .spanner .omni .SpannerOmniCredentials ;
9293import com .google .common .annotations .VisibleForTesting ;
9394import com .google .common .base .MoreObjects ;
9495import com .google .common .base .Preconditions ;
9596import com .google .common .base .Strings ;
9697import com .google .common .base .Suppliers ;
9798import com .google .common .collect .ImmutableMap ;
99+ import com .google .crypto .tink .util .SecretBytes ;
98100import io .grpc .Deadline ;
99101import io .grpc .Deadline .Ticker ;
100102import io .opentelemetry .api .OpenTelemetry ;
@@ -154,6 +156,8 @@ public class ConnectionOptions {
154156 static final boolean DEFAULT_USE_PLAIN_TEXT = false ;
155157 static final boolean DEFAULT_IS_EXPERIMENTAL_HOST = false ;
156158 static final SpannerOptions .InstanceType DEFAULT_TYPE = SpannerOptions .InstanceType .CLOUD ;
159+ static final String DEFAULT_USERNAME = "" ;
160+ static final String DEFAULT_PASSWORD = "" ;
157161 static final boolean DEFAULT_AUTOCOMMIT = true ;
158162 static final boolean DEFAULT_READONLY = false ;
159163 static final boolean DEFAULT_RETRY_ABORTS_INTERNALLY = true ;
@@ -224,6 +228,12 @@ public class ConnectionOptions {
224228 /** The type of Spanner instance to connect to (cloud, omni, or emulator). */
225229 public static final String TYPE_PROPERTY_NAME = "type" ;
226230
231+ /** Username for OPAQUE login */
232+ public static final String USERNAME_PROPERTY_NAME = "username" ;
233+
234+ /** Password for OPAQUE login */
235+ public static final String PASSWORD_PROPERTY_NAME = "password" ;
236+
227237 /** Client certificate path to establish mTLS */
228238 static final String CLIENT_CERTIFICATE_PROPERTY_NAME = "clientCertificate" ;
229239
@@ -775,6 +785,8 @@ private ConnectionOptions(Builder builder) {
775785 System .getenv ());
776786 GoogleCredentials defaultSpannerOmniCredentials =
777787 SpannerOptions .getDefaultSpannerOmniCredentialsFromSysEnv ();
788+ String username = getInitialConnectionPropertyValue (ConnectionProperties .USERNAME );
789+ String password = getInitialConnectionPropertyValue (ConnectionProperties .PASSWORD );
778790 // Using credentials on a plain text connection is not allowed, so if the user has not specified
779791 // any credentials and is using a plain text connection, we should not try to get the
780792 // credentials from the environment, but default to NoCredentials.
@@ -783,12 +795,18 @@ && getInitialConnectionPropertyValue(CREDENTIALS_URL) == null
783795 && getInitialConnectionPropertyValue (ENCODED_CREDENTIALS ) == null
784796 && getInitialConnectionPropertyValue (CREDENTIALS_PROVIDER ) == null
785797 && getInitialConnectionPropertyValue (OAUTH_TOKEN ) == null
798+ && Strings .isNullOrEmpty (getInitialConnectionPropertyValue (ConnectionProperties .USERNAME ))
786799 && usePlainText ) {
787800 this .credentials = NoCredentials .getInstance ();
788801 } else if (getInitialConnectionPropertyValue (OAUTH_TOKEN ) != null ) {
789802 this .credentials =
790803 new GoogleCredentials (
791804 new AccessToken (getInitialConnectionPropertyValue (OAUTH_TOKEN ), null ));
805+ } else if ((isSpannerOmniPattern || isSpannerOmni ())
806+ && !Strings .isNullOrEmpty (username )
807+ && !Strings .isNullOrEmpty (password )) {
808+ SecretBytes secretBytes = SpannerOmniCredentials .convertToSecretBytes (password .toCharArray ());
809+ this .credentials = new SpannerOmniCredentials (username , secretBytes , this .host );
792810 } else if ((isSpannerOmniPattern || isSpannerOmni ()) && defaultSpannerOmniCredentials != null ) {
793811 this .credentials = defaultSpannerOmniCredentials ;
794812 } else if (getInitialConnectionPropertyValue (CREDENTIALS_PROVIDER ) != null ) {
0 commit comments