Tuesday Jun 30, 2009

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.

 

Friday Jun 12, 2009

OpenSSO and the Quest for the Holy Grails

grailquest

With apologies to Monty Python Fans....

Did you ever want to use OpenSSO with Grails? Now you can!

The astute reader of this blog (that's you Mom!) will know that you can protect Spring applications with the OpenSSO Spring 2 Security provider

As it turns out, Grails has a plugin that let's you use Spring Security for authentication and authorization. If we marry this plugin with the provider, we ought to be able to use OpenSSO with Grails. Don't ya love it when a plan comes together?

To get started, you will need to download the OpenSSO Grails plugin from here, and install it using the grails install-plugin command. 

To give credit where credit is due, the OpenSSO plugin is largely based on the work of the Spring Security Grails plugin. The original authors are T.Yamamoto, Hatian Sun, and Burt Beckwith. My humble contribution is the OpenSSO glue code and the integration of the OpenSSO Spring Security extension. For reasons that I won't go into here, I elected to create a separate version of the plugin specifically for OpenSSO (ping me if you want the details).

I would also suggest downloading this sample Grails application that demonstrates how to use the plugin in a Grails Application.

 Yes. But what does it do?

 The OpenSSO plugin provides the following functionality to a Grails Application:

Single Sign On (SSO) with OpenSSO:

The plugin delegates logon to OpenSSO. If the user has previously authenticated to OpenSSO, the browser will present a cookie containing the SSO token. Providing the session is still valid, the user will be transparently signed on the Grails application.  If the user does not have a token, the plugin redirects them to OpenSSO. After succesfull authentication, the user is then redirected back to the application.  

This means that your application is not responsible for authentication. In fact, there are no logon or password screens to maintain as OpenSSO handles it for you. One of the nice benefits of this approach is that the authentication method and strength is factored out of the application. Want to use one time passwords? How about AD?  No problem - just configure the authentication chain in OpenSSO. No changes to your application.  

URL Policy Enforcement

 The plugin provides for enforcement of URL policy using OpenSSO.  This works quite nicely with Grails and it's "REST" like structure for controller URLs. So we can (for example), allow one group of users to /list controller items, and another group of users to /update or /create new items. Custom controller methods (beyond the standard CRUD methods) can use the same mechanism. 

Note that this largely eliminates the need for the @Secured annotations in Grails code - since the same effect can be implemented using URL policy. This externalizes the authorization into OpenSSO - which is generally a good thing. 

Controller Security Methods  

 The plugin injects several security methods into your controllers to provide access to the security context. Here is sampling of methods available to controllers:

isUserInRole("ROLE_MANAGER")   - true if a user belongs to the specified Role
isUserLogon()	 -  true if the user is logged on (authenticated)
getGrantedAuthorities() - returns an array of Strings representing the Granted Authorities (Spring terminology for role names) that this user posseses.

GSP Tags

The plugin provides access to GSP security tags. These tags can be used in your Grails view to drive the display based on the user's role or authentication status.

For example:

<g:ifNotGranted role="ROLE_MANAGERS">You are not a Manager!!! </g:ifNotGranted>

<g:ifAllGranted role="ROLE_MANAGERS">Congrats. You are a manager!</g:ifAllGranted>
Time permitting, I may create a cookbook on how to get this all working with the sample application. Drop me a line if you are interested.

PS. Just what is the wing speed velocity of swallow?  

Tuesday May 05, 2009

Open Source Identity Connector for Google Apps


google apps

Identity Manager 8.1 (or later) contains support for a very cool open source connector framework. The project name isn't too exciting (Identity Connectors ?  definitely needs some marketing love ) but the end result is fantastic.

 I had the experience of porting my IdM legacy adapter for Google Apps to this new framework. The API is much simpler (no depedencies on IdM or any other product), and the concepts are clean and well thought out. Just what one would expect from a team that a has a few decades of experience building connectors. 

 You can download the google apps connector, along with many other bundles here.

 Feedback is most welcome

An OpenSSO Lab using VirtualBox

opensso logo

As part of the Reboot conference in Victoria, I developed a hands on OpenSSO lab using VirtualBox.  The virtual image is running OpenSolaris 2009.06 (dev), GlassFish v3, and OpenSSO (express build 7).  

The goal of the lab is to provide a short (it should take you 4-5 hours to complete) introduction to OpenSSO that covers basic installation, SAML federation using Fedlets, and installing Policy Agents.  

The intended audience for the lab are developers or those that want to understand the functional aspects of OpenSSO. David Goldsmith has developed a much more comprehensive OpenSSO lab that focuses on complex, load balanced configurations. If you are more interested in the infrastructure side of things, check out his blog posting on the lab.  David is a training pro - and his stuff is always top notch. 

This lab is meant to be facilitated, but if you want to follow along at home,  read on:

  • Make sure you have a computer with a MINIMUM of 2GB of RAM, 10GB free disk. Dual core CPU is strongly recommended. 
  • Download and install VirtualBox 2.2.2. or later (earlier versions are not compatible with this lab)
  • You should have an ssh client (e.g. putty.exe on Windows) installed.

The lab documents (zipped pdf) can be downloaded here.

The Virtual Image is split into four zip fragments:

http://mediacast.sun.com/users/WarrenStrange/media/xaa.zip

These fragments needs to be pasted together, and then unzipped.

On Unix-ish systems:  

cat xa[abcd].zip > bigfile.zip

On Windows use can use the copy command:

copy /b xaa.zip+xab.zip+xac.zip+xad.zip   bigfile.zip

Unzip the file, and then import the appliance into VirtualBox.

The image is a \*completed\* version of the lab (everything is installed). The idea is to give you a known starting point. If you want to experiment with the lab, start with the uninstall procedures first. You can take a VirtualBox snapshot to save the lab state, or use ZFS snapshots from within the OpenSolaris image.  

 To save some memory, the OpenSolaris GUI has been disabled. You can enable the GUI with the following command:

pfexec svcadm enable gdm  

Note:  When importing the appliance you may encounter a bug where the import "hangs".  After letting the disk fully import, you will need to kill VirtualBox and start it again. You will find that the imported disk image is now in the Media Manager - and can be added to the new Virtual machine. You should be able to boot the image after assigning the disk. 

Important Update: 

Running a Solaris 64 bit kernel under VirtualBox can occasionally trigger very high CPU consumption- making the startup of OpenSSO take a long time (10+ minutes). See this bugid for details.  To get around this problem boot the image in 32 bit mode. The easiest way to do this is to change your VirtualBox settings to select "OpenSolaris" as the OS Type instead of "OpenSolaris 64 bit". 


Thursday Feb 26, 2009

Spring comes early - an updated OpenSSO Spring Security provider


Following on the pioneering work of Robert Dale  and Miguel Alonso I have updated the OpenSSO Spring provider with additional support for authorization. You can now use Spring security JSP tags, method security annotations and Spring method security point cuts.

Where to get it!

You can download the provider and a sample Spring application from the OpenSSO Extensions project page.


The package-info header is reproduced below:

Package com.sun.identity.provider.springsecurity Description

A Spring 2 Security provider for OpenSSO.

Provides authentication and authorization plugins for the Spring 2 Security framework. For an example of how to configure this module refer to the OpenSSO / Spring example

Authentication

The provider delegates authentication to the OpenSSO instance configured in the applications AMConfig.properties. When a user tries to access an application web page, the spring provider will check for a valid SSOToken. If the user is not authenticated they will be redirected to OpenSSO. Once authentication is complete, OpenSSO will redirect the user back to the application.

Upon authentication, a Spring UserDetails object is created for the user and placed in the session. This can be used by the application to query for the user principal and other information. The spring security authentication tags can be used within a JSP, as shown in the following example:

  The Logged on Principal is <security:authentication property="principal.username"/>
  
 

Authorization - Web URL Policy

The provider delegates URL policy decisions to OpenSSO. This is different than most Spring 2 providers where the URL policy is configured in the application using annotations or spring XML configuration.

OpenSSO is queried for URL policy decisions, and will return ALLOW, DENY or null. A null return means that OpenSSO does not have a policy for the requested URL. The provider will return an ABSTAIN vote if the OpenSSO policy decision is null. If you wish to implement a policy of "Deny that which is not explicity permitted" you will want to use Springs AffirmativeBased voter in your security configuration. This ensures that at least one voter must "ALLOW" the request.

Authorization - Roles

Spring Security uses the concept of GrantedAuthorities which are analagous to roles in OpenSSO. This provider converts OpenSSO group (role) membership into Spring GrantedAuthorities. The current implementation converts an OpenSSO group membership (for example "staff") into a GrantedAuthority by concatenating the prefix "ROLE_" with the upper cased group name. For example, if a user belongs to the OpenSSO groups "staff" and "admins", they will be granted "ROLE_STAFF" and "ROLE_ADMINS" authorizations.

Authorizations can be used in JSPs using the Spring security tags. For example, the following JSP snippet will output different results depending on whether the user belongs to the staff group or not:

<security:authorize ifAllGranted="ROLE_STAFF">
    <div align="left"><h2>Congrats!! You have the Staff role</h2></div>
</security:authorize>

<security:authorize ifNotGranted="ROLE_STAFF">
    <div align="left"><h2>TOO BAD SO SAD - You do NOT have the Staff role</h2></div>
</security:authorize>
 
 

Authorizations can also be used to protect methods using Spring pointcuts or annotations. The example below demonstrates using JSR security annotations:

@RolesAllowed("ROLE_ADMIN") public String sayHello() { return "Hello" }

The above method will throw a Spring Security AccessException if the user is not in the admin group.


Monday Dec 29, 2008

A Python script to encode iMovie .dv files to MP4 using HandBrake



I recently captured some old 8mm video tape of the family to iMovie.  My strategy for archiving is to copy the material to a new medium every few years. We will see how that works out.


In any event, I want to throw all the videos on a hard drive and store it offsite in our safety deposit box. However, the raw .DV footage is too large and won't fit (and I am too cheap to buy more hard drives or a larger safety deposit box). 

Necessity being the mother of invention, I needed a script to encode and compress all my .DV footage. MP4 seems to be a good choice for a format that is widely supported and offers good compression quality.  I wanted to preserve the folder event structure in iMovie - so a simple find command was not going to cut it.

I started off with bash - but quickly became frustrated with the quirky syntax. One of the problems with shell scripts is that file and path names are strings - not objects. You often run into escaping issues when presented with long file names and special characters.  You can work around these issues - but it is much more painful than it ought to be.

I elected to give python a go and see if it was any easier. This is my first python script - and I don't claim this is a particullarily good example. However - if you are facing the same issue - please feel free to use this as a starting point.

You will need a copy of the Handbrake CLI  to perform the mp4 encoding. Handbrake uses the x264 encoder.


Without further ado, here is the script:


/Users/warrenstrange/src/videorip/src/videorip.py
 1 #!/usr/bin/env python

 2 # Script to encode DV files to MP4 using HandBrakeCLI
 3 # Preserves the folder structure of the iMove events
 4 __author__="warrenstrange"
 5 __date__ ="$Dec 28, 2008 6:28:09 PM$"

 6 
 7 import os
 8 import subprocess
 9 import os.path

10 
11 # Source for .dv files
12 root = "/Volumes/Velocity1/iMovie Events.localized"
13 # Destination for encoded MP4 files
14 dest = "/Volumes/WSTCD/mp4.bak"

15 #dest = "/var/tmp/xx"
16 
17 def encode(path, dest):
18     for root, dirs, files in os.walk(path, topdown=False):

19         for name in files:
20             # Get the extension
21             (base, ext)=os.path.splitext(name)
22             # If it is a .dv file

23             if ext.lower() == ".dv":
24                 # Get the directory folder where the .dv file is stored
25                 (h,tail) = os.path.split(root)
26                 # Form the destination directory folder name

27                 destdir = os.path.join(dest,tail)
28                 # Create the destination directory if required
29                 if not os.path.exists(destdir):
30                     os.mkdir(destdir)

31                 # Form the output file name (.MP4 extenstion)
32                 newfile = os.path.join(destdir, base + ".MP4")
33                 infile = os.path.join(root,name)
34                 # If it already exists don't overwrite it - skip it

35                 if os.path.exists(newfile):
36                     print "skipping " + infile
37                 else:
38                     subprocess.call( ["HandBrakeCLI", "--preset=Universal", "-i" ,infile, "-o", newfile])

39               
40     
41 if __name__ == "__main__":
42     encode(root, dest)
43     
44 

Wednesday Dec 10, 2008

OpenSolaris / OpenDS / OpenSolaris client LDAP - the missing pieces

OpenSolaris

There is a great article on the Sun Developer Network that explains how to set up OpenDS as a naming service for OpenSolaris.

 I found a few glitches when going through the process, and have documented my "fixes" here.  Use these at your own risk!

SSL and Certificate Madness

Setting up certificates is always an excercise in frustration.  I elected to install OpenDS and let it generate it's own self signed cert. This is somewhat different than the SDN article where they generate the cert and import it into OpenDS.  Note that self signed certs are fine for development, but for production you should always use a real certificate.


 In order for a Solaris LDAP client to authenticate using LDAPS, it is necessary to import the self signed cert from the server into the clients local keystore. For Solaris, the keystore is in the old Netscape format (nss) in the /var/ldap directory.

The first thing we need to do is to export the OpenDS cert. By default OpenDS uses JKS database (Java Keystore).  The OpenDS Wiki has instructions on how to change the default keystore. The following keytool script exports the cert into a PEM format file that we can import on the client:

more export-cert.sh 
#!/bin/sh
# Export the opends self signed cert from the keystore to a PEM format that we can import into the LDAP client
# Note when prompted for a password just enter return - you will get a warning but it will work
keytool -keystore /opt/opends/config/keystore -export -alias server-cert -rfc -file /tmp/opends.pem

You should now see a cert in /tmp/opends.pem

 Next we need to import this cert on the OpenSolaris ldap client. In theory "pktool" supports creating and managing nss format databases, but I found it would not work (I always got SSL errors).   Certutil seems to do the trick. By default it is not installed on OpenSolaris 2008.11.

pkg install is your friend:

pkg install SUNWtlsu

The following commands (on the client!) will initialize the nss store and import the certificate that you previously exported from the OpenDS server (copy it to the client first).

cd /var/ldap
certutil -N -d . 
certutil -A -n defaultCert -i /tmp/opends.pem  -t CT -d .
# The key files need to be world readable
chmod a+r \*.db

You can now test LDAPS from the client to make sure SSL is working. You might want to tail your opends access log to watch for the incoming connection.   The following script will test the connection:

more testssl.sh 
#!/bin/sh
host=opensolaris
nssdb=/var/ldap/cert8.db
ldapsearch -h $host -p 636 -P $nssdb  -D "cn=Directory Manager" -b "" -s base "" vendorVersion

Updating OpenDS ACIs

OpenDS

I found I needed to add a few ACIs to make the ldap client search work. I used the following script:

[Note: Watch the cut n paste on the script. The ACI formatting/escaping is tricky. All ACIs should be on a single line]

 more setaci
#!/bin/sh
# Sample script to modify OpenDS for Solaris LDAP clients 
# Modify as required for your environment
# Note that ACIs are all on one line. If you cut n paste make sure to fix this
# You need to put the Director Manager password in the file /tmp/.dmp  (e..g echo "password" > /tmp/.dmp)


# ldap server hostname
host=opensolaris
#port=389
# admin port
port=4444

# dsconfig command
dsc=/opt/opends/bin/dsconfig 
# proxy dn used by ldap clients
dn="cn=solaris,ou=LDAPauth,dc=sundemo,dc=net"

# LDAP Server Sort Result extension
$dsc -h $host -p $port --trustAll \\
-D "cn=directory manager" -j /tmp/.dmp -n \\
set-access-control-handler-prop \\
--add global-aci:"(targetcontrol=\\"1.2.840.113556.1.4.473\\")(version 3.0; acl \\"LDAP Administrator Server Sort\\"; allow (all) us
erdn = \\"ldap:///$dn\\";)"

 # VLV extension
$dsc -h $host -p $port --trustAll \\
-D "cn=directory manager" -j /tmp/.dmp -n \\
set-access-control-handler-prop \\
--add global-aci:'(targetcontrol="1.3.6.1.4.1.42.2.27.9.5.8 || 2.16.840.1.113730.3.4.9" ) (version 3.0; acl "Allow Account Statu
s and VLV controls for Proxy"; allow(read, proxy) userdn="ldap:///'$dn'";)'

Configuring the LDAP client

Now you are ready to configure the LDAP client.  I used the following script (adjust to your environment as required):

more ldapclient.sh 
ldapclient -v manual \\
-a domainName=localdomain \\
-a credentialLevel=proxy \\
-a defaultSearchBase=dc=sundemo,dc=net \\
-a proxyDN=cn=solaris,ou=LDAPauth,dc=sundemo,dc=net \\
-a defaultServerList=10.0.1.199:636 \\
-a authenticationMethod=tls:simple \\
-a proxyPassword=SolarisRulz 

 
  
 
  

At this point you also may want to fix up your /etc/nsswitch.conf and use files/dns for host resolution (instead of ldap). If you get wierdness running simple commands (e.g. ping opensolaris) it is probably because host name resolution is trying to use ldap.

 The ldaplist command can be used to test the client setup:

# ldaplist passwd  
dn: uid=test01,ou=People,dc=sundemo,dc=net


You now should have a fully functioning ldap client!

A client profile can be generated for import into ldap. This makes installing subsequent clients easier. Instead of using the manual install, you run the ldapclient init variant. This configures the client to pull it's configuration from the directory. The added bonus is that changes to the configuration will be dynamically pulled by the client's ldap_cachemgr.


The following command will generate LDIF which you can import into the directory:

more genprofile.sh 
ldapclient genprofile \\
-a profileName=opensolarisclient \\
-a defaultSearchBase=dc=sundemo,dc=net \\
-a credentialLevel=proxy \\
-a defaultServerList=10.0.1.199:636 \\
-a authenticationMethod=tls:simple \\

Sample Output:

# ./genprofile.sh dn: cn=opensolarisclient,ou=profile,dc=sundemo,dc=net ObjectClass: top ObjectClass: DUAConfigProfile defaultServerList: 10.0.1.199:636 defaultSearchBase: dc=sundemo,dc=net authenticationMethod: tls:simple cn: opensolarisclient credentialLevel: proxy

You can configure more attributes using an LDAP editor. See  LDAP Client Profiles for more information.


 And yes, this process is harder than it needs to be!    OpenDS will be in the IPS repository very soon - and hopefully some of the ldap configuration steps will be taken care of.


 
  



Tuesday Nov 25, 2008

Modifying the CustomerDBSpring sample REST application to run on Glassfish V3



Netbeans 6.5 comes with sample applications (CustomerDB and CustomerDBSpring)  that demonstrate how to use the Jersey REST APIs. By default these deploy on Glassfish V2.


If you want to try this on Glassfish V3, you will need to change your persistence.xml to use EclipseLink instead of Toplink. (EclipseLink is the new JPA provider in V3 ).  This should do the trick:



<persistence-unit name="CustomerDBSpringPU" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/sample</jta-data-source>
    <class>customerdb.Customer</class>
    <class>customerdb.DiscountCode</class>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
      <property name="eclipselink.target-database" value="Derby"/>
      <property name="eclipselink.logging.level" value="FINE"/>
    </properties>
 </persistence-unit>


Friday Nov 14, 2008

DimDim Web Conferencing



I just tried DimDim web conferencing. This is a free (for up to 20 people) Web conferencing solution.

Participants only need a web browser (the usually suspects, Firefox, IE, Safari). If you are hosting and want to share your desktop you need to install a browser plugin  (works on Mac, Window and Linux).  Desktop sharing is a tad laggy but was still very usable.


Check it out at:

http://www.dimdim.com/


Tuesday Oct 14, 2008

Clojure and Lisp Revival





I have always been fascinated by Lisp, but it just seemed like one of those languages that while theoretically nice was completely impractical.  Lisp environments have either been powerful but proprietary, or have been free but limited in capability.  Although Lisp is one of the oldest language around (circa 1950s!)it has remained a niche language, never quite attracting enough critical mass to make it a serious alternative to mainstream languages such as Java, ruby, or C#.


Clojure might just change that.

It's a Lisp dialect built on top of the JVM, and it solves many problems which have impaired Lisp adoption:
  • Courtesy of the JVM, Clojure has access to the world's largest collection of software libraries. 
  • It's a two way street. Clojure is able to create classes that can be called from Java.
  • Clojure has a cross platform GUI. Love it or hate it, Swing does a reasonable job at solving this problem. My money is on someone leveraging JavaFX libraries to build a DSL with Clojure. Might be a nice alternative to JavaFX script!
  • It's got a free IDE. Enclojure is a Netbeans plugin that provides a namespace browser, editor, code completion, and interaction with REPL. For a Java guy used to the Edit-Compile-Jar-Deploy-Run cycle it's pretty neat to be able to incrementally send expressions to the REPL.
  • It's fast (or at least fast enough). Expressions entered in the REPL (the Read Evaluate, and Print Loop) are compiled directly to Java byte code. As Java gets better at dynamic languages (think invokedynamic!), Clojure gets faster.
  • It's practical. Rich Hickey, the mastermind behind Clojure, has made a few design choices that improve the performance and interoperability with the JVM. For example, Clojure supports vectors, maps, and sequences, all of which map nicely to Java constructs.  

Most importantly, Clojure's functional style is perfectly suited to a future when massively parallel multi-core machines are the norm:

Functional programs eschew the external 'effects' of imperative
programs, and thus become easier to understand, reason about, and test,
since the activity of functions is completely local. To the extent a
portion of a program is purely functional, concurrency is a non-issue,
as there is simply no change to coordinate.
[http://clojure.org/state]

Check it out  here






Tuesday Jun 17, 2008

A Sun Identity Manger Resource Adapter for Google Apps



Google Apps provides a nice provisioning API to manage Google Apps accounts.


Using this API I have written a custom resource adapter for Sun for Sun Java System Identity Manager. Here is a screen shot showing the configured adapter:







This adapter enables you to manage the full life cycle of Google Apps accounts through Identity Manager. This includes the standard CRUD operations (Create, Read, Update, Delete) as well as enable/disable account, change/reset password and support for reconciliation.

Here is a screen shot showing the results of running a full reconciliation:





Along with the adapter, there is a user form provided that is compatible with the IdM dynamic tabbed user form framework:





As you can see from the above form, you can manage the Google Apps nicknames (mail aliases) for the user.


If you are interested in testing out this adapter, please drop me a note ( my email is warren dot strange at sun.com). My plan is to open source the adapter code - but this will be done in conjunction with a future IdM release. There is some exciting news coming on that front - can't say more right now, so stay tuned!











Tuesday Apr 29, 2008

Apple adds Java SE 6 support



Better late than never....


http://www.macrumors.com/2008/04/29/apple-adds-java-se-6-to-leopard/



Tuesday Apr 22, 2008

A script to add 3rd party artifacts to your maven repository



I find the maven command line very obtuse and have trouble remembering the right incantation to add 3rd party jars to a local repository.


Here is a small bash script which might be useful to others. You will need to edit this for your environment.


#!/bin/bash
# Add 3rd party jars to maven in a batch
# Usage: madd groupid version jar1 jar2 ...
#
# Edit the mvn command as per your repo setup

if [ $# -lt 3 ]; then
echo Usage: $0 groupid version jar1 jar2...
exit 1
fi

GROUPID=$1
shift
VERSION=$1
shift

for file in $\*
do
ARTIFACTID=`echo $file | sed -e 's/\\.jar//'`
mvn deploy:deploy-file -DgroupId=$GROUPID -DartifactId=$ARTIFACTID \\
-Dversion=$VERSION -Dpackaging=jar -Dfile=$file \\
-Durl=http://localhost:8081/nexus/content/repositories/thirdparty \\
-DrepositoryId=thirdparty
done

Monday Mar 10, 2008

Identity Manager IDE released as open source!



The Identity Manager IDE plugin for Netbeans has now been released as open source under the CDDL license.

Get it while it's hot @ http://identitymanageride.dev.java.net/



Highlights include support for Netbeans 6.0, and a new "Object Builder" to manage IdM Objects.


Monday Feb 18, 2008

Getting Groovy with OpenSSO REST Services



Recent builds of OpenSSO now include WS-\* and REST identity services. Check out Marina Sum's blog for an excellent overview.


Now it turns out that Groovy is a great way to explore REST services. Here is an example using OpenSSO (if you are trying this out at home change your base URL to reflect your OpenSSO installation).



def baseurl = "http://localhost:28080/opensso/identity/"

// Create and execute REST query string
def query = { String action, Map args ->
def s = baseurl + action;
def sep = "?"
args.each { key,value ->
def encoded = java.net.URLEncoder.encode(value,"UTF-8")
s += "${sep}${key}=${encoded}"
sep = "&"
}
return s.toURL().text
}

// authenticate to OpenSSO
def authenticate = { username, password ->
String s = query("authenticate", [ username:username, password:password] )
int i = s.indexOf('=')
if( i >= 0 )
return s.substring(i+1).trim()
else
return s;
}

// fetch the users attributes. Must supply the token returned by authenticate
def getAttributes = { token -> query("attributes", [subjectid:token]) }

// Test to see if the user identified by token is allowed to access the URI
def authorize = { token, uri, action = "GET" -> query("authorize", [subjectid:token, uri:uri, action:action]) }

def token = authenticate("user1", "password")

println getAttributes(token)
println authorize(token, "http://localhost:8080/protected")





As Mr. Powers would say, Groovy Baby"
About

Things that amuse me

Search

Archives
« July 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
31
  
       
Today
News

No bookmarks in folder

Blogroll