Skip to content

Authenticating a JavaFX application using OpenSSO

June 30, 2009

At JavaONE 2009, Super Pat showed a nice JavaFX demo that used OpenSSO identity services to authenticate and authorize a user.   The demo displays a username / password dialog box to collect the user’s credentials, which are sent to OpenSSO using identity services. If the user provides the correct credentials, a token is returned that represents their OpenSSO session. This token can be sent back in subsequent identity services calls to perform authorization checks.

I wanted to know if we could use the browser’s SSO token in preference to displaying the dialog box in JavaFX. This approach has a couple of advantages:

  • Authentication is abstracted out from our application – and is handled by OpenSSO where it belongs.   This makes it easy to modify the authentication chain. For example, we can use two factor authentication – without modifying our JavaFX code.
  • We can share the SSO session across both browser and JavaFX applications.

The key to making this work is the Java Plugin, which provides a bridge between a Java applet (or JavaFX) and the browser.

Here is a small JavaFX example that uses the plugin to gain access to the SSO token. The example works as follows:

  • The JavaFX applet grabs a reference to the browsers DOM using the plugin.
  • The DOM is queried for the OpenSSO cookie (iPlanetDirectoryPro).
  • If the cookie is found, the token value is sent to OpenSSO identity services to validate the session.
  • If the cookie is not found, or the OpenSSO session is not valid, the applet opens a browser window to the OpenSSO login page.  After successful authentication the user will now have a valid token in their session.

Here is the JavaFX utility class that handles the REST identity calls to OpenSSO. We use the HttpRequest class to do the heavy lifting:

/Users/warrenstrange/src/tmp/JavaFXOpenSSOTest/src/openssotest/Util.fx
  1 /*
  2  * Util.fx
  3  *
  4  * Created on Jun 18, 2009, 5:09:55 PM
  5  */
  6
  7 package openssotest;
  8
  9 import javafx.io.http.HttpRequest;
 10 import javafx.io.http.HttpHeader;
 11
 12
 13 /**
 14  * Utility functions to support OpenSSO integration
 15  *
 16  * @author warrenstrange
 17  */
 18
 19
 20 // todo: We should get this from opensso
 21 def cookieName = "iPlanetDirectoryPro";
 22
 23
 24 /**
 25  * Parse the OpenSSO token from the cookie string
 26  */
 27
 28 public function getTokenFromString(cookies:String) {
 29     var token = null;
 30
 31     if( cookies != null ) {
 32         var start = cookies.indexOf(cookieName);
 33         if( start > 0 ) {
 34             var ts = start + cookieName.length()+1;
 35             var te = cookies.indexOf(";", ts);
 36             if( te < 0) {
 37                 token = cookies.substring(ts);
 38             }
 39             else
 40                 token = cookies.substring(ts,te);
 41         }
 42     }
 43     return token;
 44 }
 45
 46 /**
 47  * Authenticate using OpenSSO identity services (/identity)
 48  * We pass in the SSO token we get from the browser.
 49  *
 50  * Note this is an async process. We start the request and return it to the caller.
 51  * When the request is complete the setAuth callback function will be
 52  * called. This function will be passed in a boolean indicating if the
 53  * user has been authenticated or not.
 54  */
 55
 56 public function authenticate(token: String, setAuth: function(isAuth:Boolean):Void): HttpRequest {
 57
 58     var request: HttpRequest = HttpRequest {
 59         location: "http://opensso.my2do.com:8080/opensso/identity/isTokenValid"
 60         method: HttpRequest.POST
 61
 62         headers: [
 63             HttpHeader {
 64                 name: HttpHeader.CONTENT_TYPE;
 65                 value: "application/x-www-form-urlencoded";
 66             },
 67             HttpHeader {
 68                 name: HttpHeader.CONTENT_LENGTH;
 69                 value: "0";
 70             }
 71
 72             HttpHeader {
 73                 name: "Cookie";
 74                 value: "{cookieName}={token}";
 75             }
 76         ];
 77
 78         onInput: function(is: java.io.InputStream) {
 79             // grab response from opensso
 80             try {
 81                 var conv = new StreamConverter(is);
 82                 var s = conv.convertStreamToString();
 83                 println("Response back from opensso={s}");
 84                 if( s != null and s.indexOf("true") > 0) {
 85                     setAuth(true);
 86                 }
 87                 else
 88                     setAuth(false);
 89             } finally {
 90                 is.close();
 91             }
 92         }
 93
 94         onException: function(ex: java.lang.Exception) {
 95             println("onException - exception: {ex.getClass()} {ex.getMessage()}");
 96         }
 97     };
 98
 99     request.start();
100
101     return request;
102
103 }
104
105
106

The Main.fx panel shows the SSO Token (if present), and the users authentication status. 

Apologies for the lame GUI!

/Users/warrenstrange/src/tmp/JavaFXOpenSSOTest/src/openssotest/Main.fx
  1 /*
  2  * Main.fx
  3  *
  4  * Created on Jun 16, 2009, 11:45:58 AM
  5  */
  6
  7 package openssotest;
  8
  9 import javafx.stage.Stage;
 10 import javafx.scene.Scene;
 11 import javafx.scene.text.Text;
 12
 13 import com.sun.javafx.runtime.adapter.Applet;
 14
 15 import javafx.geometry.HPos;
 16 import javafx.scene.layout.Flow;
 17 import javafx.scene.control.Button;
 18 import javafx.io.http.HttpRequest;
 19
 20
 21 import java.net.URL;
 22
 23
 24
 25 /**
 26  * Sample JavaFX application that authenticate the user using OpenSSO.
 27  * The user's browswer is quried for the SSO token. If it is not found a new
 28  * browwer window is opened up to the OpenSSO login page.
 29  *
 30  * @author warrenstrange
 31  */
 32
 33 var applet: Applet = FX.getArgument("javafx.applet") as Applet;
 34 var window = netscape.javascript.JSObject.getWindow(applet);
 35 var document : org.w3c.dom.html.HTMLDocument = DOMHelper.getDocument(applet);
 36
 37 var cookies = document.getCookie();
 38 var token = Util.getTokenFromString(cookies);
 39
 40
 41 var prequest: HttpRequest; // holds state of authenticate async REST call
 42
 43 def width = 800;
 44 def height = 600;
 45
 46 var authenticated = false;
 47
 48
 49 var url =new URL("http://opensso.my2do.com:8080/opensso");
 50
 51 Stage {
 52     title: "JavaFX / OpenSSO Test"
 53     width: width
 54     height: height
 55     scene: Scene {
 56         content: [
 57
 58             Flow {
 59                 vertical: true
 60                 height: 300 // columns will wrap at 300
 61                 hgap: 5 // horizontal gap between columns
 62                 vgap: 5 // vertical gap between nodes in a column
 63                 nodeHPos: HPos.LEFT // each node will be left-aligned within its column
 64                 content: [
 65
 66                 Text {
 67                     content: bind if( token != null ) {
 68                             "SSOToken = {token}"
 69                         }
 70                         else "No Token";
 71
 72                 },
 73                 Text {
 74                     content: bind if (authenticated )
 75                         { "Authenticated!" } else "Not Authenticated";
 76
 77                 },
 78
 79                 Button {
 80                     text: "Authenticate Now!";
 81                     action: function() {
 82                         cookies = document.getCookie();
 83                         token = Util.getTokenFromString(cookies);
 84                         println ("Authenticate called with {token}");
 85
 86                         // call authenticate identity service
 87                         // when complete, it will call our anon function
 88                         // if we are NOT authenticated, a new browser window
 89                         // will be launched pointing the user at the opensso
 90                         // login page
 91                         prequest = Util.authenticate(token,
 92                             function(isAuthenticated:Boolean):Void {
 93                                 authenticated = isAuthenticated;
 94                                 if( not authenticated ) {
 95                                     var c = applet.getAppletContext();
 96                                     c.showDocument(url, "_blank");
 97                                 }
 98                             } );
 99                         println ("Authenticate returned");
100                     }
101                 }
102
103                 ]
104             }
105             ]
106     }
107 }
108

You can download the complete netbeans project here.
Advertisements

Comments are closed.

%d bloggers like this: