Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove RSA Public Key #21

Merged
merged 6 commits into from
Oct 19, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
*.iml
.idea
target/
profile.json
12 changes: 10 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,14 @@
<scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-ext-jdk15on -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-ext-jdk15on</artifactId>
<version>1.60</version>
<scope>test</scope>
</dependency>


<!-- Jose4J provides token authentication for GS -->
<dependency>
Expand All @@ -234,14 +242,14 @@
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.4</version>
<version>2.9.6</version>
</dependency>

<!-- Jackson Databind api -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.4</version>
<version>2.9.6</version>
</dependency>


Expand Down
13 changes: 13 additions & 0 deletions profile.json.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"user": "user name",
"account": "account name",
"private_key": "PEM Private Key",
"port": 443,
"host": "account_name.snowflakecomputing.com",
"schema": "schema",
"scheme": "https",
"database": "database name",
"connect_string": "jdbc:snowflake://account_name.snowflakecomputing.com:443",
"ssl": "on",
"warehouse": "warehouse name"
}
116 changes: 105 additions & 11 deletions src/main/java/net/snowflake/ingest/SimpleIngestManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,14 @@

import java.io.IOException;
import java.net.URISyntaxException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import java.util.Collections;
import java.util.List;
import java.util.Set;
Expand Down Expand Up @@ -217,10 +224,11 @@ private void init(String account, String user, String pipe,
* Snowflake DB
*
* @param account The account into which we're loading
* @param user the user performing this load
* @param pipe the fully qualified name of the pipe
* @param user the user performing this load
* @param pipe the fully qualified name of the pipe
* @param keyPair the KeyPair we'll use to sign JWT tokens
*/
@Deprecated
public SimpleIngestManager(String account, String user, String pipe,
KeyPair keyPair)
{
Expand All @@ -232,30 +240,116 @@ public SimpleIngestManager(String account, String user, String pipe,
}


/**
* Constructs a SimpleIngestManager for a given user in a specific account
* In addition, this also takes takes the target table and source stage
* Finally, it also requires a valid private key registered with
* Snowflake DB
*
* @param account The account into which we're loading
* @param user the user performing this load
* @param pipe the fully qualified name of the pipe
* @param privateKey the private key we'll use to sign JWT tokens
* @throws NoSuchAlgorithmException if can't create
* key factory by using RSA algorithm
* @throws InvalidKeySpecException if private key or public key is
* invalid
*/
public SimpleIngestManager(String account, String user, String pipe,
PrivateKey privateKey)
throws InvalidKeySpecException, NoSuchAlgorithmException
{
KeyPair keyPair = createKeyPairFromPrivateKey(privateKey);

//call our initializer method
init(account, user, pipe, keyPair);

//create the request builder
this.builder = new RequestBuilder(account, user, keyPair);
}


/**
* Constructs a SimpleIngestManager for a given user in a specific account
* In addition, this also takes takes the target table and source stage
* Finally, it also requires a valid KeyPair object registered with
* Snowflake DB
*
* @param account the account into which we're loading
* @param user the user performing this load
* @param pipe the fully qualified name of the pipe
* @param keyPair the KeyPair we'll use to sign JWT tokens
* @param account the account into which we're loading
* @param user the user performing this load
* @param pipe the fully qualified name of the pipe
* @param keyPair the KeyPair we'll use to sign JWT tokens
* @param schemeName http or https
* @param hostName the hostname
* @param port the port number
* @param hostName the hostname
* @param port the port number
*/
@Deprecated
public SimpleIngestManager(String account, String user, String pipe,
KeyPair keyPair, String schemeName,
String hostName, int port)
KeyPair keyPair, String schemeName,
String hostName, int port)
{
//call our initializer method
init(account, user, pipe, keyPair);

//make the request builder we'll use to build messages to the service
builder = new RequestBuilder(account, user, keyPair,
schemeName, hostName, port);
schemeName, hostName, port);
}

/**
* Constructs a SimpleIngestManager for a given user in a specific account
* In addition, this also takes takes the target table and source stage
* Finally, it also requires a valid private key registered with
* Snowflake DB
*
* @param account the account into which we're loading
* @param user the user performing this load
* @param pipe the fully qualified name of the pipe
* @param privateKey the private key we'll use to sign JWT tokens
* @param schemeName http or https
* @param hostName the hostname
* @param port the port number
* @throws NoSuchAlgorithmException if can't create key factory by using
* RSA algorithm
* @throws InvalidKeySpecException if private key or public key is invalid
*/
public SimpleIngestManager(String account, String user, String pipe,
PrivateKey privateKey, String schemeName,
String hostName, int port)
throws NoSuchAlgorithmException, InvalidKeySpecException
{
KeyPair keyPair = createKeyPairFromPrivateKey(privateKey);
//call our initializer method
init(account, user, pipe, keyPair);

//make the request builder we'll use to build messages to the service
builder = new RequestBuilder(account, user, keyPair,
schemeName, hostName, port);

}

/**
* generate key pair object from private key
*
* @param privateKey private key
* @return a key pair object
* @throws NoSuchAlgorithmException if can't create key factory by using
* RSA algorithm
* @throws InvalidKeySpecException if private key or public key is invalid
*/
private KeyPair createKeyPairFromPrivateKey(PrivateKey privateKey) throws
NoSuchAlgorithmException, InvalidKeySpecException
{
KeyFactory kf = KeyFactory.getInstance("RSA");

//generate public key from private key
RSAPrivateCrtKey privk = (RSAPrivateCrtKey) privateKey;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Throw proper user error in case user is passing in a PrivateKey not instancesof RSAPrivateCrtKey

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a checker

if(!(privateKey instanceof RSAPrivateCrtKey))
throw new IllegalArgumentException("Input private key is not a RSA private key");

RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(privk.getModulus(),
privk.getPublicExponent());
PublicKey publicK = kf.generatePublic(publicKeySpec);

//create key pairs
return new KeyPair(publicK, privateKey);
}


Expand Down
167 changes: 167 additions & 0 deletions src/test/java/net/snowflake/ingest/SimpleIngestSuite.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package net.snowflake.ingest;

import net.snowflake.ingest.connection.HistoryResponse;
import net.snowflake.ingest.connection.IngestResponse;
import net.snowflake.ingest.utils.StagedFileWrapper;
import org.junit.Before;
import org.junit.Test;
import org.junit.After;

import java.sql.Connection;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import static org.junit.Assert.assertTrue;

/**
* Example ingest sdk integration test
*/
public class SimpleIngestSuite
{
private Connection conn = null;
private SimpleIngestManager manager = null;

private final String TEST_FILE_PATH = "file://test_files/test1.csv";
private final String TEST_FILE_NAME = "test1.csv";

private String tableName = "";
private String pipeName = "";
private String stageName = "";

/**
* Create test table and pipe
*/
@Before
public void beforeAll() throws Exception
{
Random rand = new Random();

Long num = Math.abs(rand.nextLong());

tableName = "ingest_sdk_test_table_" + num;

pipeName = "ingest_sdk_test_pipe_" + num;

stageName = "ingest_sdk_test_stage_" + num;


TestUtils.executeQuery(
"create or replace table " + tableName + " (str string, num int)"
);

TestUtils.executeQuery(
"create or replace stage " + stageName
);

TestUtils.executeQuery(
"create or replace pipe " + pipeName + " as copy into " + tableName +
" from @" + stageName
);

}

/**
* Remove test table and pipe
*/
@After
public void afterAll()
{
//System.out.println(111);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove

TestUtils.executeQuery(
"drop pipe if exists " + pipeName
);

TestUtils.executeQuery(
"drop stage if exists " + stageName
);

TestUtils.executeQuery(
"drop table if exists " + tableName
);
}

/**
* ingest test
*/
@Test
public void test1() throws Exception
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a better name? testSimpleIngest?

{
//put
TestUtils.executeQuery(
"put " + TEST_FILE_PATH + " @" + stageName
);

//keeps track of whether we've loaded the file
boolean loaded = false;

//create ingest manager
SimpleIngestManager manager = TestUtils.getManager(pipeName);

//create a file wrapper
StagedFileWrapper myFile = new StagedFileWrapper(TEST_FILE_NAME, null);

//get an insert response after we submit
IngestResponse insertResponse = manager.ingestFile(myFile, null);

//create a new thread
ExecutorService service = Executors.newSingleThreadExecutor();

//fork off waiting for a load to the service
Future<?> result = service.submit(() ->
{

String beginMark = null;

while (true)
{

try
{
Thread.sleep(5000);
HistoryResponse response = manager.getHistory(null, null,
beginMark);

if (response != null && response.getNextBeginMark() != null)
{
beginMark = response.getNextBeginMark();
}
if (response != null && response.files != null)
{
for (HistoryResponse.FileEntry entry : response.files)
{
//if we have a complete file that we've
// loaded with the same name..
String filename = entry.getPath();
if (entry.getPath() != null && entry.isComplete() &&
filename.equals(TEST_FILE_NAME))
{
return;
}
}
}
} catch (Exception e)
{
e.printStackTrace();
}
}
}
);

//try to wait until the future is done
try
{
//wait up to 1 minutes to load
result.get(2, TimeUnit.MINUTES);
loaded = true;
} finally
{
assertTrue(loaded);


}
}

}
Loading