-
Notifications
You must be signed in to change notification settings - Fork 4
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
[draft] Update OAuthSampleApp.java, Added refresh token api to get new access… #19
Conversation
… token using the refresh token, we can get the new access token in case of a wrong access token or an expired access token. Added API to get the new access_token using refresh_token note: When we request for new access_token using refresh token, This request will give us both the tokens. which we can save later to original tokens and start using new Tokens instead of old tokens
private static String OAUTH_SERVER = System.getenv("OAUTH_SERVER"); | ||
private static String OAUTH_HTTP_PORT = System.getenv("OAUTH_HTTP_PORT"); | ||
|
||
private static String getTokenUrl() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getTokenUrl, getHttpsTokenUrl, getIssuerUri, and getDiscoveryUrl are all unneeded. The only ones being used is the token/https token url and if we just have that be provided through the new environment variable then we don't need the get function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These unneccessary methods are removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changes are reasonable in isolation, but the task was to align the JDBC OAuth sample app with the ADO.NET implementation. We took a lot of time and effort to develop the ADO sample. My suggestion is to start with a port of the structure of the ADO.NET sample app.
- The user should configure it to run by setting values in a properties file with the same settings as are in the ADO.NET sample
- The app should check and set the values of the OAUTH_SAMPLE_ACCESS_TOKEN and OAUTH_SAMPLE_REFRESH_TOKEN environment variables.
- You should be able to run both sample apps interchangeably. Running the Java sample should set the access and refresh tokens that can be used by the ADO sample and visa versa.
- When reading the code, it should have the same overall logic and naming. If someone understands the one app, they should have an immediate familiarity with the other.
Here is a description of the flow that I suggest using. The ADO sample does essentially the same thing, and that's really what we want - to align the samples with a common recommended flow. Here are the steps:
One difference is that the ADO sample uses a configuration file instead of environment variables for the initial set of properties, excluding access token and refresh token. If we can do that for this sample as well that would be a good change. |
Changes in the client application done as per comments and discussion. SetUpDbForOAuth() -> Adding authentication record in Vertica database is having issues. It's dropping the user and authentication method, but while setting the Authentication record, there is some error because of which Token authentication is failing and Database connection with access token is unable to establish. Without SetUpDbForOAuth() method call, Application is woking good.
Commented SetUpDbForOAuth() and TearDown() call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some issues that must be addressed before this can be approved. See comments.
|
||
private static void TearDown() throws Exception | ||
{ | ||
System.out.println("TearDown"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we want the println here, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed unnecessary System - printlns.
System.out.println("TearDown"); | ||
Statement st = vConnection.createStatement(); | ||
String USER = prop.getProperty("User"); | ||
// st.execute("DROP USER IF EXISTS " + USER + " CASCADE"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we want to drop the user and auth method? This is the ADO.NET sample code:
public static async Task TearDown()
{
string USER = getSetting("User");
VerticaCommand cmd = new VerticaCommand("DROP USER IF EXISTS " + USER + " CASCADE", vConnection);
cmd.ExecuteNonQuery();
cmd.CommandText = "DROP AUTHENTICATION IF EXISTS adooauth CASCADE";
cmd.ExecuteNonQuery();
vConnection.Close();
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, We need to drop this user and auth method.
But As of now, there is an issue with adding/creating the Authentication record using sample app code. Same statements are able to execute via VSQL and it's working fine with this app.
But, if we use the same statements from outh sample app is not work. Need to check and resolve this issue. there after this methods we will uncomment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Issue resolved for the SetUpDbForOAuth and TearDown Method.
return DriverManager.getConnection( | ||
"jdbc:vertica://" + host + ":" + port + "/" + dbName, jdbcOptions); | ||
return DriverManager.getConnection( | ||
"jdbc:vertica://" + "172.17.0.45" + ":" + "5433" + "/" + "verticadb21451", jdbcOptions); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the server, port and database hard coded? This should not be in the PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the method to get this data from config.properties vars.
"jdbc:vertica://" + "172.17.0.45" + ":" + "5433" + "/" + "verticadb21451", jdbcOptions); | ||
} | ||
|
||
private static void ConnectToDatabase() throws SQLException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The overall formatting looks off. Please be sure to use standard source formatting and indentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The formating of code was done as per tab stop 4 and git had it as tab stop 8, updated that. Also made changes for indentation in git view.
ResultSet rs = executeQuery(conn); | ||
printResults(rs); | ||
conn.close(); | ||
//SetUpDbForOAuth(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this skip SetUpDbForOAuth? That seems pretty important.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @williammatherjones : There are some issues in SetUpDbForOAuth(){}
it's not able to set up the Oauth configurations in the Vertica database.
Note: Same Query statements are working fine if we execute using vsql and run this application. Need to analyze more to resolve this issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue with SetUpDbForOAuth method is resolved.
I think it would be good to take a closer look at the logic in how the ADO.NET OAuth sample connects. Right now, I don't think the logic to retry on failure is there. |
-> Removed all @commandline and picoli imports -> Removed all the blank lines from the file -> Indentation issue resolved. Note:Please adjust the tab stop as 4 to view the file content properly indented. -> Removed if else for first element in the map for framing the connectionString. -> All the Start braces and end braces are aligned and made the same in every place -> Added null check for an access token and refresh token after getting it from token URL
@Command(name = "OAuthSampleApp", mixinStandardHelpOptions = true, version = "OAuth sample app 1.0", description = "Connects to a Vertica database using OAuth") | ||
public class OAuthSampleApp implements Callable<Integer> { | ||
|
||
public class OAuthSampleApp implements Callable<Integer> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should always be a line between the start of the class and imports. There's also places in this file where there is no space between methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the space or empty lines from the file as per suggestions from @sandeep Rawat.
Added the line between class and imports.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are still no spaces between functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the spaces between the Functions.
Added config.properties file which would be required for running the sample app. User have to update the values as per configuration. Note: Given Sample example for the Connection string. Because Connection string will be accepted in this format. <KeyName>=<Value>;<KeyName>=<Value>;......
-> Added functions for the redundant code for copying data to the buffered output stream. -> removed unnecessary imports.
Removed ClientID, ClientSecret, Tokenurl from getconnection Call.
Added Line between imports and class
Debug prints removed
Deprecated method use JsonParser().parse(res); removed. used JsonParser.parseString(res);
private static String OAUTH_REFRESH_TOKEN_VAR_STRING = "OAUTH_SAMPLE_REFRESH_TOKEN"; | ||
private static Connection vConnection; | ||
// Get jdbc connection string from provided configuration | ||
private static String getConnectionString(String args) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can simplify this a lot by removing getConnectionString and getParam. Just put a sample connection string in the config properties like jdbc:vertica://localhost:5433/VMart or whatever you use.
// set Tokens as System Properties - new values to access_token and refresh_token | ||
String accessToken = jObject.has("access_token") ? jObject.get("access_token").getAsString() : null; | ||
String refreshToken = jObject.has("refresh_token") ? jObject.get("refresh_token").getAsString() : null; | ||
if (null == accessToken || null == refreshToken) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is possible that an IDP will return an access token but not a refresh token. If the refresh token is null, that could be OK, it just shouldn't be set in the environment variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, It's possible. As in our application, We are showing the use of access and refresh tokens, So let's have both tokens. This sample app shows how we can use the access and refresh token. If any User wants to have code without a refresh token, They can remove the code and use it as it's open-source code. Adding multiple scenarios like this will increase the complexity of the sample app.
throw new Exception("Access Token is not available."); | ||
}else | ||
{ | ||
Connection conn = connectToDB(accessToken); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be useful for these steps to print things for the user like "Attempting to connect with connection string: " + connectionString. Or "Executing query: " + query. Things like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the print msges as per suggestions
break; | ||
} | ||
try { | ||
ex.printStackTrace(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should be printing the stack trace here or on line 148. At this point in the flow, we are just refreshing the tokens, nothing 'wrong' has heppened.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
During compilation, It's giving an error for this code that it has an unhandled exception at this line. Due to this it needs to handle the exception and need to avoid the use of the "System.out.println" (console output) in the code as per discussion with Sandeep. Because of that whenever we need error details, I have used printStackTrace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When an access token is expired and you get a refresh token, is the stack trace printed out? That would be confusing to the user and what we want to avoid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed printing of stack traces while getting tokens in connect to database.
private static ResultSet executeQuery(Connection conn) throws SQLException | ||
{ | ||
Statement stmt = conn.createStatement(); | ||
return stmt.executeQuery("SELECT user_id, user_name FROM USERS ORDER BY user_id"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should print something like "Connected Successfully. The current user is: " + the query result.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here all the users available in the USERS table are getting printed from database table USERS. Added print to specify "executing query :" + query
- Added Fix for setup of Authentication record to Database. - Uncommented DBSetup and Teardown for Authentication setup before OAuth sample test run
Added DiscoveryUrl to be provided in config.properties file for OAuth Authentication
Added RefreshToken check and If both the tokens are available, then it will use those tokens, Or else it will get new tokens using password grant.
Check if access token is not available, Get the tokens. else if a refresh token is not available, Get the tokens. else set both the tokens to properties.
Indentation issue resolved
Indentation resolved
Comment indentation resolved
Added the logic to retry on failure as per ADO.Net Sample APP |
// uses the password grant flow | ||
private static void EnsureAccessToken() throws Exception | ||
{ | ||
try |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The added logic in this function is a little off. It should go like this:
If there is an access token, then it needs to be set, else
If there is not an access token and there is no refresh token, then get new tokens by password grant.
If there is not an access token but there is a refresh token, get new tokens by refresh grant.
If that refresh token has expired, then catch the exception and get tokens by password grant.
This logic is in ADO.NET sample application.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-> Code changes as per suggestion are completed.
-> EnsureAccesstoken and connectToDatabase code changed as per the ADO.Net Example.
New PR created due to commit issue with current PR 19. |
… token
using the refresh token, we can get the new access token in case of a wrong access token or an expired access token.
Added API to get the new access_token using refresh_token
note: When we request for new access_token using refresh token, This request will give us both the tokens. which we can save later to original tokens and start using new Tokens instead of old tokens