Skip to content

Commit

Permalink
Merge branch 'master' into Snow-732360-Allow-Connection-Caching-to-be…
Browse files Browse the repository at this point in the history
…-Disabled
  • Loading branch information
sfc-gh-ext-simba-jf committed Aug 13, 2024
2 parents 9bd0540 + e2a092d commit 2c308df
Show file tree
Hide file tree
Showing 36 changed files with 1,731 additions and 686 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ snowflake-whitelist
Golang
ClientTelemetryFramework
lib/*
.wiremock/**

# WhiteSource Scan
wss*.config
Expand Down
11 changes: 11 additions & 0 deletions parent-pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
<version.plugin.sortpom>3.0.1</version.plugin.sortpom>
<version.plugin.source>3.2.1</version.plugin.source>
<version.plugin.surefire>3.0.0</version.plugin.surefire>
<version.plugin.wiremock>3.8.0</version.plugin.wiremock>
</properties>

<dependencyManagement>
Expand Down Expand Up @@ -507,6 +508,12 @@
<version>${version.plugin.surefire}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.wiremock</groupId>
<artifactId>wiremock-standalone</artifactId>
<version>${version.plugin.wiremock}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down Expand Up @@ -757,5 +764,9 @@
<groupId>org.apache.maven.surefire</groupId>
<artifactId>common-junit48</artifactId>
</dependency>
<dependency>
<groupId>org.wiremock</groupId>
<artifactId>wiremock-standalone</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,11 @@ private static void verifyFilePermissionSecure(Path configFilePath)
Arrays.asList(PosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_READ)
.contains(o))) {
logger.error(
"Reading from file {} is not safe because of insufficient permissions", configFilePath);
"Reading from file %s is not safe because file permissions are different than read/write for user",
configFilePath);
throw new SnowflakeSQLException(
String.format(
"Reading from file %s is not safe because of insufficient permissions",
"Reading from file %s is not safe because file permissions are different than read/write for user",
configFilePath));
}
}
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/net/snowflake/client/core/SFLoginInput.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,22 @@ public class SFLoginInput {
private boolean enableClientStoreTemporaryCredential;
private boolean enableClientRequestMfaToken;

private Duration browserResponseTimeout;

// Additional headers to add for Snowsight.
Map<String, String> additionalHttpHeadersForSnowsight;

SFLoginInput() {}

Duration getBrowserResponseTimeout() {
return browserResponseTimeout;
}

SFLoginInput setBrowserResponseTimeout(Duration browserResponseTimeout) {
this.browserResponseTimeout = browserResponseTimeout;
return this;
}

public String getServerUrl() {
return serverUrl;
}
Expand Down
23 changes: 20 additions & 3 deletions src/main/java/net/snowflake/client/core/SFSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,17 @@ public class SFSession extends SFBaseSession {
*/
private int retryTimeout = 300;

<<<<<<< HEAD
private boolean enableClientStoreTemporaryCredential = true;
private boolean enableClientRequestMfaToken = true;
=======
/**
* Max timeout for external browser authentication in seconds
*
* <p>Default: 120
*/
private Duration browserResponseTimeout = Duration.ofSeconds(120);
>>>>>>> master

// This constructor is used only by tests with no real connection.
// For real connections, the other constructor is always used.
Expand Down Expand Up @@ -492,6 +501,12 @@ public void addSFSessionProperty(String propertyName, Object propertyValue) thro
}
break;

case BROWSER_RESPONSE_TIMEOUT:
if (propertyValue != null) {
browserResponseTimeout = Duration.ofSeconds((Integer) propertyValue);
}
break;

case JDBC_DEFAULT_FORMAT_DATE_WITH_TIMEZONE:
if (propertyValue != null) {
setDefaultFormatDateWithTimezone(getBooleanValue(propertyValue));
Expand Down Expand Up @@ -557,7 +572,7 @@ public synchronized void open() throws SFException, SnowflakeSQLException {
+ " application: {}, app id: {}, app version: {}, login timeout: {}, retry timeout: {}, network timeout: {},"
+ " query timeout: {}, tracing: {}, private key file: {}, private key file pwd is {},"
+ " enable_diagnostics: {}, diagnostics_allowlist_path: {},"
+ " session parameters: client store temporary credential: {}, gzip disabled: {}",
+ " session parameters: client store temporary credential: {}, gzip disabled: {}, browser response timeout: {}",
connectionPropertiesMap.get(SFSessionProperty.SERVER_URL),
connectionPropertiesMap.get(SFSessionProperty.ACCOUNT),
connectionPropertiesMap.get(SFSessionProperty.USER),
Expand Down Expand Up @@ -589,7 +604,8 @@ public synchronized void open() throws SFException, SnowflakeSQLException {
connectionPropertiesMap.get(SFSessionProperty.ENABLE_DIAGNOSTICS),
connectionPropertiesMap.get(SFSessionProperty.DIAGNOSTICS_ALLOWLIST_FILE),
sessionParametersMap.get(CLIENT_STORE_TEMPORARY_CREDENTIAL),
connectionPropertiesMap.get(SFSessionProperty.GZIP_DISABLED));
connectionPropertiesMap.get(SFSessionProperty.GZIP_DISABLED),
connectionPropertiesMap.get(SFSessionProperty.BROWSER_RESPONSE_TIMEOUT));

HttpClientSettingsKey httpClientSettingsKey = getHttpClientKey();
logger.debug(
Expand Down Expand Up @@ -649,7 +665,8 @@ public synchronized void open() throws SFException, SnowflakeSQLException {
connectionPropertiesMap.get(SFSessionProperty.DISABLE_SAML_URL_CHECK))
: false)
.setEnableClientStoreTemporaryCredential(enableClientStoreTemporaryCredential)
.setEnableClientRequestMfaToken(enableClientRequestMfaToken);
.setEnableClientRequestMfaToken(enableClientRequestMfaToken)
.setBrowserResponseTimeout(browserResponseTimeout);

logger.info(
"Connecting to {} Snowflake domain",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ public enum SFSessionProperty {

ENABLE_CLIENT_STORE_TEMPORARY_CREDENTIAL("clientStoreTemporaryCredential", false, Boolean.class),

ENABLE_CLIENT_REQUEST_MFA_TOKEN("clientRequestMfaToken", false, Boolean.class);
ENABLE_CLIENT_REQUEST_MFA_TOKEN("clientRequestMfaToken", false, Boolean.class),

BROWSER_RESPONSE_TIMEOUT("BROWSER_RESPONSE_TIMEOUT", false, Integer.class);

// property key in string
private String propertyKey;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
Expand Down Expand Up @@ -256,6 +257,10 @@ private String generateProofKey() {
return Base64.getEncoder().encodeToString(randomness);
}

private int getBrowserResponseTimeout() {
return (int) loginInput.getBrowserResponseTimeout().toMillis();
}

/**
* Authenticate
*
Expand All @@ -265,6 +270,7 @@ private String generateProofKey() {
void authenticate() throws SFException, SnowflakeSQLException {
ServerSocket ssocket = this.getServerSocket();
try {
ssocket.setSoTimeout(getBrowserResponseTimeout());
// main procedure
int port = this.getLocalPort(ssocket);
logger.debug("Listening localhost: {}", port);
Expand Down Expand Up @@ -305,6 +311,13 @@ void authenticate() throws SFException, SnowflakeSQLException {
socket.close();
}
}
} catch (SocketTimeoutException e) {
throw new SFException(
e,
ErrorCode.NETWORK_ERROR,
"External browser authentication failed within timeout of "
+ getBrowserResponseTimeout()
+ " milliseconds");
} catch (IOException ex) {
throw new SFException(ex, ErrorCode.NETWORK_ERROR, ex.getMessage());
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
package net.snowflake.client.core;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
Expand All @@ -19,4 +20,5 @@
ElementType.METHOD
})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SnowflakeJdbcInternalApi {}
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,15 @@ public class SnowflakeBasicDataSource implements DataSource, Serializable {
private static final long serialversionUID = 1L;
private static final String AUTHENTICATOR_SNOWFLAKE_JWT = "SNOWFLAKE_JWT";
private static final String AUTHENTICATOR_OAUTH = "OAUTH";
<<<<<<< HEAD
private static final String AUTHENTICATOR_EXTERNAL_BROWSER = "EXTERNALBROWSER";
=======

private static final String AUTHENTICATOR_EXTERNAL_BROWSER = "EXTERNALBROWSER";

>>>>>>> master
private static final String AUTHENTICATOR_USERNAME_PASSWORD_MFA = "USERNAME_PASSWORD_MFA";

private String url;

private String serverName;
Expand Down Expand Up @@ -393,4 +400,9 @@ public void setEnableClientStoreTemporaryCredential(
this.setAuthenticator(AUTHENTICATOR_EXTERNAL_BROWSER);
this.properties.put("clientStoreTemporaryCredential", enableClientStoreTemporaryCredential);
}

public void setBrowserResponseTimeout(int seconds) {
this.setAuthenticator(AUTHENTICATOR_EXTERNAL_BROWSER);
this.properties.put("BROWSER_RESPONSE_TIMEOUT", Integer.toString(seconds));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,6 @@
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.filefilter.WildcardFileFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Class for uploading/downloading files
Expand All @@ -100,7 +98,6 @@ public class SnowflakeFileTransferAgent extends SFBaseFileTransferAgent {

private static final String localFSFileSep = systemGetProperty("file.separator");
private static final int DEFAULT_PARALLEL = 10;
private static final Logger log = LoggerFactory.getLogger(SnowflakeFileTransferAgent.class);

private final String command;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import net.snowflake.common.core.RemoteStoreFileEncryptionMaterial;

/**
* Handles encryption and decryption using AES.
* Handles encryption and decryption using AES CBC (for files) and ECB (for keys).
*
* @author ppaulus
*/
Expand All @@ -51,28 +51,17 @@ public static InputStream decryptStream(
RemoteStoreFileEncryptionMaterial encMat)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException,
BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
byte[] decodedKey = Base64.getDecoder().decode(encMat.getQueryStageMasterKey());

byte[] kekBytes = Base64.getDecoder().decode(encMat.getQueryStageMasterKey());
byte[] keyBytes = Base64.getDecoder().decode(keyBase64);

byte[] ivBytes = Base64.getDecoder().decode(ivBase64);

SecretKey queryStageMasterKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, AES);

SecretKey kek = new SecretKeySpec(kekBytes, 0, kekBytes.length, AES);
Cipher keyCipher = Cipher.getInstance(KEY_CIPHER);

keyCipher.init(Cipher.DECRYPT_MODE, queryStageMasterKey);

keyCipher.init(Cipher.DECRYPT_MODE, kek);
byte[] fileKeyBytes = keyCipher.doFinal(keyBytes);

SecretKey fileKey = new SecretKeySpec(fileKeyBytes, 0, decodedKey.length, AES);

SecretKey fileKey = new SecretKeySpec(fileKeyBytes, AES);
Cipher dataCipher = Cipher.getInstance(FILE_CIPHER);

IvParameterSpec ivy = new IvParameterSpec(ivBytes);

dataCipher.init(Cipher.DECRYPT_MODE, fileKey, ivy);

return new CipherInputStream(inputStream, dataCipher);
}

Expand All @@ -87,14 +76,14 @@ public static void decrypt(
IOException {
byte[] keyBytes = Base64.getDecoder().decode(keyBase64);
byte[] ivBytes = Base64.getDecoder().decode(ivBase64);
byte[] qsmkBytes = Base64.getDecoder().decode(encMat.getQueryStageMasterKey());
byte[] kekBytes = Base64.getDecoder().decode(encMat.getQueryStageMasterKey());
final SecretKey fileKey;

// Decrypt file key
{
final Cipher keyCipher = Cipher.getInstance(KEY_CIPHER);
SecretKey queryStageMasterKey = new SecretKeySpec(qsmkBytes, 0, qsmkBytes.length, AES);
keyCipher.init(Cipher.DECRYPT_MODE, queryStageMasterKey);
SecretKey kek = new SecretKeySpec(kekBytes, 0, kekBytes.length, AES);
keyCipher.init(Cipher.DECRYPT_MODE, kek);
byte[] fileKeyBytes = keyCipher.doFinal(keyBytes);

// previous version: fileKey = new SecretKeySpec(fileKeyBytes, offset = 0, len = qsmk.length,
Expand Down Expand Up @@ -154,13 +143,13 @@ public static CipherInputStream encrypt(
final byte[] fileKeyBytes = new byte[keySize];
final byte[] ivData;
final CipherInputStream cis;
final int blockSz;
final int blockSize;
{
final Cipher fileCipher = Cipher.getInstance(FILE_CIPHER);
blockSz = fileCipher.getBlockSize();
blockSize = fileCipher.getBlockSize();

// Create IV
ivData = new byte[blockSz];
ivData = new byte[blockSize];
getSecRnd().nextBytes(ivData);
final IvParameterSpec iv = new IvParameterSpec(ivData);

Expand All @@ -175,22 +164,22 @@ public static CipherInputStream encrypt(
cis = new CipherInputStream(src, fileCipher);
}

// Encrypt the file key with the QRMK
// Encrypt the file key with the QSMK
{
final Cipher keyCipher = Cipher.getInstance(KEY_CIPHER);
SecretKey queryStageMasterKey = new SecretKeySpec(decodedKey, 0, keySize, AES);

// Init cipher
keyCipher.init(Cipher.ENCRYPT_MODE, queryStageMasterKey);
byte[] encKeK = keyCipher.doFinal(fileKeyBytes);
byte[] encryptedKey = keyCipher.doFinal(fileKeyBytes);

// Store metadata
MatDesc matDesc = new MatDesc(encMat.getSmkId(), encMat.getQueryId(), keySize * 8);
// Round up length to next multiple of the block size
// Sizes that are multiples of the block size need to be padded to next
// multiple
long contentLength = ((originalContentLength + blockSz) / blockSz) * blockSz;
client.addEncryptionMetadata(meta, matDesc, ivData, encKeK, contentLength);
long contentLength = ((originalContentLength + blockSize) / blockSize) * blockSize;
client.addEncryptionMetadata(meta, matDesc, ivData, encryptedKey, contentLength);
}

return cis;
Expand Down
Loading

0 comments on commit 2c308df

Please sign in to comment.