Skip to content

Commit ea47073

Browse files
committed
feat(spanner): login functionality Spanner Omni
1 parent 85f51b2 commit ea47073

7 files changed

Lines changed: 1048 additions & 1 deletion

File tree

java-spanner/google-cloud-spanner/pom.xml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,14 +159,19 @@
159159
<version>0.6.1</version>
160160
<configuration>
161161
<protocArtifact>com.google.protobuf:protoc:4.33.2:exe:${os.detected.classifier}</protocArtifact>
162+
<pluginId>grpc-java</pluginId>
163+
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.64.0:exe:${os.detected.classifier}</pluginArtifact>
162164
<additionalProtoPathElements>
163165
<additionalProtoPathElement>${project.basedir}/../proto-google-cloud-spanner-v1/src/main/proto</additionalProtoPathElement>
166+
<additionalProtoPathElement>${project.basedir}/../google-cloud-spanner/src/main/proto</additionalProtoPathElement>
164167
</additionalProtoPathElements>
165168
</configuration>
166169
<executions>
167170
<execution>
168-
<id>test-compile</id>
171+
<id>compile</id>
169172
<goals>
173+
<goal>compile</goal>
174+
<goal>compile-custom</goal>
170175
<goal>test-compile</goal>
171176
</goals>
172177
</execution>
@@ -544,6 +549,16 @@
544549
<groupId>javax.annotation</groupId>
545550
<artifactId>javax.annotation-api</artifactId>
546551
</dependency>
552+
<dependency>
553+
<groupId>org.bouncycastle</groupId>
554+
<artifactId>bcprov-jdk18on</artifactId>
555+
<version>1.78</version>
556+
</dependency>
557+
<dependency>
558+
<groupId>com.google.crypto.tink</groupId>
559+
<artifactId>tink</artifactId>
560+
<version>1.13.0</version>
561+
</dependency>
547562
</dependencies>
548563
</profile>
549564
<profile>

java-spanner/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
import java.io.IOException;
9292
import java.net.MalformedURLException;
9393
import java.net.URL;
94+
import java.nio.charset.StandardCharsets;
9495
import java.nio.file.Files;
9596
import java.nio.file.Paths;
9697
import java.time.Duration;
@@ -1817,6 +1818,84 @@ public Builder setExperimentalHost(String host) {
18171818
return this;
18181819
}
18191820

1821+
1822+
/**
1823+
* Authenticates to Spanner Omni using the provided username and password file, and configures
1824+
* the resulting token for use in subsequent Spanner API calls. The endpoint must be set on the
1825+
* builder before calling this method.
1826+
*
1827+
* @param username The username for login.
1828+
* @param passwordFile The path to a file containing the password.
1829+
* @return this builder
1830+
*/
1831+
public Builder login(String username, String passwordFile) {
1832+
return login(username, passwordFile, true);
1833+
}
1834+
1835+
/**
1836+
* Authenticates to Spanner Omni using the provided username and password file, and configures
1837+
* the resulting token for use in subsequent Spanner API calls. The endpoint must be set on the
1838+
* builder before calling this method.
1839+
*
1840+
* @param username The username for login.
1841+
* @param passwordFile The path to a file containing the password.
1842+
* @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.
1843+
* @return this builder
1844+
*/
1845+
public Builder login(String username, String passwordFile, boolean backgroundRefresh) {
1846+
try {
1847+
byte[] rawBytes = Files.readAllBytes(Paths.get(passwordFile));
1848+
int len = rawBytes.length;
1849+
while (len > 0 && (rawBytes[len - 1] == '\n' || rawBytes[len - 1] == '\r')) {
1850+
len--;
1851+
}
1852+
byte[] passwordBytes = java.util.Arrays.copyOf(rawBytes, len);
1853+
return loginWithPasswordBytes(username, passwordBytes, backgroundRefresh);
1854+
} catch (IOException e) {
1855+
throw SpannerExceptionFactory.newSpannerException(
1856+
ErrorCode.NOT_FOUND, "Could not read password file: " + passwordFile, e);
1857+
}
1858+
}
1859+
1860+
/**
1861+
* Authenticates to Spanner Omni using the provided username and password, and configures the
1862+
* resulting token for use in subsequent Spanner API calls. The endpoint must be set on the
1863+
* builder before calling this method.
1864+
*
1865+
* @param username The username for login.
1866+
* @param password The password for login.
1867+
* @return this builder
1868+
*/
1869+
public Builder loginWithPassword(String username, String password) {
1870+
return loginWithPassword(username, password, true);
1871+
}
1872+
1873+
/**
1874+
* Authenticates to Spanner Omni using the provided username and password, and configures the
1875+
* resulting token for use in subsequent Spanner API calls. The endpoint must be set on the
1876+
* builder before calling this method.
1877+
*
1878+
* @param username The username for login.
1879+
* @param password The password for login.
1880+
* @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.
1881+
* @return this builder
1882+
*/
1883+
public Builder loginWithPassword(String username, String password, boolean backgroundRefresh) {
1884+
return loginWithPasswordBytes(username, password.getBytes(StandardCharsets.UTF_8), backgroundRefresh);
1885+
}
1886+
1887+
private Builder loginWithPasswordBytes(String username, byte[] password, boolean backgroundRefresh) {
1888+
if (this.experimentalHost == null) {
1889+
throw new IllegalStateException("Endpoint must be set before calling login.");
1890+
}
1891+
String target = this.experimentalHost.replaceFirst("^https?://", "");
1892+
com.google.crypto.tink.util.SecretBytes secretBytes = com.google.crypto.tink.util.SecretBytes.copyFrom(
1893+
password, com.google.crypto.tink.InsecureSecretKeyAccess.get());
1894+
java.util.Arrays.fill(password, (byte) 0);
1895+
super.setCredentials(new com.google.cloud.spanner.omni.SpannerOmniCredentials(username, secretBytes, target, backgroundRefresh));
1896+
return this;
1897+
}
1898+
18201899
/** Enables gRPC-GCP extension with the default settings. This option is enabled by default. */
18211900
public Builder enableGrpcGcpExtension() {
18221901
return this.enableGrpcGcpExtension(null);

0 commit comments

Comments
 (0)