1515 require file unless file . start_with? ( 'lcm-snowflake-driver' )
1616end
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+
1826module 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
104156end
0 commit comments