Skip to content

Commit 51a2297

Browse files
Merge pull request #2042 from gooddata/GRIF-312
GRIF-312: Support Snowflake key paid authentication
2 parents 8f60c7f + 50dd65f commit 51a2297

File tree

2 files changed

+64
-2
lines changed

2 files changed

+64
-2
lines changed

ci/snowflake/pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@
1919
<artifactId>slf4j-api</artifactId>
2020
<version>1.7.2</version>
2121
</dependency>
22+
<dependency>
23+
<groupId>org.bouncycastle</groupId>
24+
<artifactId>bcprov-jdk18on</artifactId>
25+
<version>1.80</version>
26+
</dependency>
27+
<dependency>
28+
<groupId>org.bouncycastle</groupId>
29+
<artifactId>bcpkix-jdk18on</artifactId>
30+
<version>1.80</version>
31+
</dependency>
2232
</dependencies>
2333

2434
<profiles>

lib/gooddata/cloud_resources/snowflake/snowflake_client.rb

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@
1515
require file unless file.start_with?('lcm-snowflake-driver')
1616
end
1717

18+
java_import 'java.io.StringReader'
19+
java_import 'org.bouncycastle.openssl.PEMParser'
20+
java_import 'org.bouncycastle.jce.provider.BouncyCastleProvider'
21+
java_import 'org.bouncycastle.asn1.pkcs.PrivateKeyInfo'
22+
java_import 'org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo'
23+
java_import 'org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder'
24+
java_import 'org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter'
25+
1826
module GoodData
1927
module CloudResources
2028
class SnowflakeClient < CloudResourceClient
@@ -75,11 +83,19 @@ def connect
7583
GoodData.logger.info "Setting up connection to Snowflake #{@url}"
7684

7785
prop = java.util.Properties.new
78-
prop.setProperty('user', @authentication['basic']['userName'])
79-
prop.setProperty('password', @authentication['basic']['password'])
8086
prop.setProperty('schema', @schema)
8187
prop.setProperty('warehouse', @warehouse)
8288
prop.setProperty('db', @database)
89+
90+
if @authentication['keyPair']
91+
prop.setProperty('user', @authentication['keyPair']['userName'])
92+
private_key_str = build_private_key(@authentication['keyPair']['privateKey'], @authentication['keyPair']['passPhrase'])
93+
prop.setProperty('private_key_base64', private_key_str)
94+
else
95+
prop.setProperty('user', @authentication['basic']['userName'])
96+
prop.setProperty('password', @authentication['basic']['password'])
97+
end
98+
8399
# Add JDBC_QUERY_RESULT_FORMAT parameter to fix unsafe memory issue of Snowflake JDBC driver
84100
prop.setProperty('JDBC_QUERY_RESULT_FORMAT', 'JSON')
85101

@@ -99,6 +115,42 @@ def build_url(url)
99115

100116
url
101117
end
118+
119+
private
120+
121+
def build_private_key(private_key_string, pass_phrase)
122+
java.security.Security.removeProvider("BC")
123+
java.security.Security.addProvider(BouncyCastleProvider.new)
124+
125+
begin
126+
pem_parser = PEMParser.new(StringReader.new(private_key_string))
127+
pem_object = pem_parser.readObject
128+
129+
if pem_object.is_a?(PKCS8EncryptedPrivateKeyInfo)
130+
builder = JceOpenSSLPKCS8DecryptorProviderBuilder.new
131+
decryptor = builder.build(pass_phrase.to_java.to_char_array)
132+
private_key_info = pem_object.decryptPrivateKeyInfo(decryptor)
133+
else pem_object.is_a?(PrivateKeyInfo)
134+
private_key_info = pem_object
135+
end
136+
137+
ensure
138+
pem_parser&.close
139+
end
140+
141+
converter = JcaPEMKeyConverter.new
142+
private_key = converter.getPrivateKey(private_key_info)
143+
pem_str = convert_private_key(private_key)
144+
java.util.Base64.getEncoder.encodeToString(pem_str.encode('UTF-8').bytes)
145+
end
146+
147+
def convert_private_key(private_key)
148+
pem = "-----BEGIN PRIVATE KEY-----\n"
149+
encoder = java.util.Base64.getMimeEncoder(64, "\n".to_java_bytes)
150+
base64 = encoder.encodeToString(private_key.getEncoded)
151+
"#{pem}#{base64}\n-----END PRIVATE KEY-----"
152+
end
153+
102154
end
103155
end
104156
end

0 commit comments

Comments
 (0)