Skip to content

Instantly share code, notes, and snippets.

@csjx
Last active June 25, 2019 20:17
Show Gist options
  • Save csjx/7ea6a65b17af3bc344de5fd897fa2893 to your computer and use it in GitHub Desktop.
Save csjx/7ea6a65b17af3bc344de5fd897fa2893 to your computer and use it in GitHub Desktop.
Using the JavaFX WebView embedded WebKit browser for ORCID authentication
package org.dataone.client.javafx;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.CookieManager;
import java.net.CookieHandler;
import java.net.HttpCookie;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Example application that instantiates a JavaFX WebView browser and
* loads a login page. When the user clicks the button to log in, they
* are redirected to the DataONE Coordinating Node (CN). The CN mints
* and registers cookie internally, and redirects the browser to orcid.org.
* The user logs in via ORCID, and is redirected back to the CN. The CN mints
* a JWT token, and stores it internally, redirecting the browser back to a
* success page. On observing the success page in the browser location,
* the application stores the cookies sent by the CN, and then fetches the JWT
* token from the CN at the /portal/token endpoint by sending the JSESSIONID
* cookie back to the CN. The token is then set as a Java variable in the
* application for later use.
*/
public class LoginApp extends Application {
/* The token to be used for DataONE API calls */
private static String token = "no-token-yet";
/**
* Constructor - Builds a LoginApp instance
*/
public LoginApp() {
}
/**
* Application entrypoint method
* @param args
*/
public static void main(String[] args) {
// Launch the JavaFX application
launch(args);
}
/**
* Start the application - overrides Application.start()
* @param primaryStage
* @throws Exception
*/
@Override
public void start(Stage primaryStage) throws Exception {
// Set up a default cookie store to access cookies set by the CN
CookieManager cookieManager = new CookieManager();
CookieHandler.setDefault(cookieManager);
// Create a browser window
WebView webView = new WebView();
// Set a listener that looks for the "success" page after authentication
webView.getEngine().locationProperty().addListener((observable, oldLocation, newLocation) -> {
if ( newLocation != null && newLocation.endsWith("orcid-success.html") ) {
HttpURLConnection connection = null;
String cookieString = "";
// Now make a call back to the CN to get the JWT token
try {
// Set up the CN token endpoint
URL tokenURL = new URL("https://cn-stage-2.test.dataone.org/portal/token");
connection = (HttpURLConnection) tokenURL.openConnection();
// Manually set the JSESSIONID cookie in the request. This is quick and dirty,
// and probably should use a cookie handling library to create proper RFC 6265
// strings like Apache HTTPClient
for (HttpCookie cookie : cookieManager.getCookieStore().getCookies() ) {
if (cookie.getName() == "JSESSIONID" && cookie.getPath() == "/portal" ) {
cookieString = cookie.getName().concat("=").concat(cookie.getValue());
}
}
// Set connection properties
connection.setRequestProperty("Cookie", cookieString);
connection.setRequestMethod("GET");
connection.setConnectTimeout(10000); // 10 sec establish connection timeout
connection.setReadTimeout(10000); // 10 sec read response timeout
// Spool the CN server response into a string buffer
String input;
StringBuffer response = new StringBuffer();
BufferedReader reader = new BufferedReader(
new InputStreamReader(connection.getInputStream()));
while ( (input = reader.readLine()) != null ) {
response.append(input);
}
reader.close();
// Set the token from the string buffer
token = response.toString();
} catch (MalformedURLException mue) {
mue.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
if ( connection != null ) {
connection.disconnect();
}
}
System.out.println("Copy and paste this token into the https://jwt.io debugger to see it's contents:");
System.out.println(token);
}
});
// Finally load the login web page and render it
webView.getEngine().load("https://dev.nceas.ucsb.edu/orcid-login.html");
VBox vBox = new VBox(webView);
Scene scene = new Scene(vBox, 960, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>orcid-login-example</artifactId>
<name>ORCID Login Example</name>
<groupId>org.dataone</groupId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-web</artifactId>
<version>11</version>
</dependency>
</dependencies>
</project>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment