Authenticating a JavaFX application using OpenSSO

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.

 

Comments:

Post a Comment:
Comments are closed for this entry.
About

Things that amuse me

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today
News

No bookmarks in folder

Blogroll