Wednesday Nov 14, 2007

Leopard (Mac OS 10.5) / Mac OS X 10.4 and Java 6

In case, you're looking for Java 6 on Mac OS X (10.4/10.5): https://connect.apple.com

It's the roughly same 'old' build we've seen before:

teufelchen: steffo$ /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home/bin/java -version
java version "1.6.0-dp"
Java(TM) SE Runtime Environment (build 1.6.0-dp-b88-34)
Java HotSpot(TM) Client VM (build 1.6.0-b88-17-release, mixed mode, sharing)

Tuesday Sep 25, 2007

A standalone OpenSSO client

OpenSSO has a server part (deployed behind a /fam URI or similar) and a client part (e.g. a J2EE agent, or the OpenID extension). In any case you have ensure that the AMConfig.properties for each part do correspond w.r.t. encryption keys, agent IDs etc. Since debugging an J2EE agent or even OpenID extension might be unfeasible (at least as a first step), I use a stand-alone client which sources the AMAgent.properties used by e.g. the OpenID extension.

The following code is example and works well for OpenSSO, Sun Java System Access Manager (7.0 and 7.1) all deployed in realm mode.

To build the JAR, make sure that you include the OpenSSO Client SDK as well as the servlet.jar to your (NetBeans) project.

/\*
 \* OpenSSOConnect.java
 \*
 \* Created on November 2, 2006, 11:18 AM
 \*
 \* To change this template, choose Tools | Template Manager
 \* and open the template in the editor.
 \*/

/\*\*
 \*
 \* @author steffo
 \*/


// OpenSSO installation has a default realm 'init8' as well as an authentication chain 'init8'

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.ChoiceCallback;
import javax.security.auth.callback.ConfirmationCallback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.TextInputCallback;
import javax.security.auth.callback.TextOutputCallback;
import javax.security.auth.callback.UnsupportedCallbackException;

import netscape.ldap.util.DN;

import com.iplanet.am.util.SystemProperties;
import com.iplanet.sso.SSOToken;
import com.sun.identity.authentication.AuthContext;
import com.sun.identity.idm.AMIdentity;
import com.sun.identity.idm.AMIdentityRepository;
import com.sun.identity.idm.IdRepoException;
import com.sun.identity.idm.IdSearchControl;
import com.sun.identity.idm.IdSearchOpModifier;
import com.sun.identity.idm.IdSearchResults;
import com.sun.identity.idm.IdType;
import com.sun.identity.idm.IdUtils;
import com.sun.identity.security.AdminTokenAction;


import com.sun.identity.authentication.spi.AuthLoginException;


public class OpenSSOConnect {

	public static void main(String[] argv) {
		boolean remote = false;
		if (argv.length > 0) {
			String r = argv[0];
			if (r.equalsIgnoreCase("remote")) {
				remote = true;
			}
		}
		Properties props = new Properties();

		try {
                        //Point this to the AMConfig.properties, you want to check
			FileInputStream amconfig = new FileInputStream("/Users/steffo/Projekte/OpenSSO/OpenID-Provider/src/opensso/extensions/openid/provider/resources/AMConfig.properties");
			
			props.load(amconfig);
		} catch (IOException e) {
			System.out.println("AMConfig.properties was not found");
		}

		props.setProperty("com.iplanet.services.debug.level", "message");
                props.setProperty("com.iplanet.am.naming.ignoreNamingService", "true");
		
                //remote=true;
		if (remote) {
			props.setProperty("com.iplanet.am.sdk.package", "com.iplanet.am.sdk.remote");
		} else {
			props.setProperty(AdminTokenAction.AMADMIN_MODE, "true");
		}
		System.out.println("Properties set");
		SystemProperties.initializeProperties(props);
		try {
			SSOToken token = getSSOToken();
			System.out.println("Getting AMIdentityRepository object");

			AMIdentityRepository idrepo = new AMIdentityRepository(token, "init8");
                        
                       

			System.out.println("Using TOKEN to get AMIdentity object " + "and read attrs");
			AMIdentity tmpId = IdUtils.getIdentity(token);
			System.out.println("Calling Attributes getting all attributes: " + tmpId.getAttributes());
						

		} catch (Exception ex) {
			ex.printStackTrace();
		}
		System.exit(0);
	}

	public static SSOToken getSSOToken() throws Exception {
                //We created a user 'steffo' with credenials 'password'
		return getSSOToken("init8", "steffo", "password");

	}

	protected static SSOToken getSSOToken(String org, String uid,
			String password) throws Exception {

		AuthContext ac = new AuthContext(org);
		ac.login(AuthContext.IndexType.SERVICE, "init8");
		Callback[] callbacks = null;
		if (ac.hasMoreRequirements()) {
			callbacks = ac.getRequirements();

			if (callbacks != null) {
				try {
					addLoginCallbackMessage(callbacks, uid, password);
					ac.submitRequirements(callbacks);
				} catch (Exception e) {
					debugMessage("Login failed!!");
                                        debugMessage("--> " + ac.getLoginException().getMessage());
					e.printStackTrace();
					return null;
				}
			}
		}
		if (ac.getStatus() == AuthContext.Status.SUCCESS) {
			debugMessage("Login success!!");
		} else if (ac.getStatus() == AuthContext.Status.FAILED) {
			debugMessage("Login has failed!!");
                        debugMessage("--> " + ac.getLoginException().getMessage());
		} else if( ac.getStatus() == AuthContext.Status.IN_PROGRESS ) {
                        // This may happen when the password is about to expire and must be reset.
                        // Analyze the error message to be sure what is going on.
			debugMessage( "Login is in progress !" );
                        //debugMessage("--> " + ac.getLoginException().getMessage());
                        if( ac.hasMoreRequirements() ) {
                                callbacks = ac.getRequirements();
                                if( callbacks != null ) {
                                    debugMessage( "Callbacks for new password will be processed !" );
                                    try {
                                            addNewPasswordCallbackMessage( callbacks, uid, password, "Geheim03" );
                                            ac.submitRequirements( callbacks );
                                    } catch( Exception e ) {
                                            debugMessage( "Login failed while processing new password callbacks." );
                                            debugMessage("--> " + ac.getLoginException().getMessage());
                                            e.printStackTrace();
                                            return null;
                                    }
                                }
                        }
                    if( ac.getStatus() == AuthContext.Status.SUCCESS )
                            debugMessage( "Login success after switch to new password!" );                           
                    else {
                            debugMessage( "Login failed after switch to new password!" );  
                            debugMessage("--> " + ac.getLoginException().getMessage());
                            }

                }
                   else {
			debugMessage("Unknown status: " + ac.getStatus());
                        debugMessage("--> " + ac.getLoginException().getMessage());
		}

		SSOToken token = ac.getSSOToken();
		return token;

	}

	// Get user's inputs and set them to callback array.
	static void addLoginCallbackMessage(Callback[] callbacks, String uid,
			String password) throws UnsupportedCallbackException {
		debugMessage("begin addLoginCallbackMessage()");
		int i = 0;
		try {
			for (i = 0; i < callbacks.length; i++) {
				if (callbacks[i] instanceof TextOutputCallback) {
					debugMessage("Got TextOutputCallback");
					// Display the message according to the specified type
					TextOutputCallback toc = (TextOutputCallback) callbacks[i];
					switch (toc.getMessageType()) {
					case TextOutputCallback.INFORMATION:
						debugMessage(toc.getMessage());
						break;
					case TextOutputCallback.ERROR:
						debugMessage("ERROR: " + toc.getMessage());
						break;
					case TextOutputCallback.WARNING:
						debugMessage("WARNING: " + toc.getMessage());
						break;
					default:
						debugMessage("Unsupported message type: "
								+ toc.getMessageType());
					}
				} else if (callbacks[i] instanceof NameCallback) {
					debugMessage("Got NameCallback");
					NameCallback nc = (NameCallback) callbacks[i];
					nc.setName(uid);
				} else if (callbacks[i] instanceof PasswordCallback) {
					debugMessage("Got PasswordCallback");
					PasswordCallback pc = (PasswordCallback) callbacks[i];
					pc.setPassword(new String(password).toCharArray());
				} else if (callbacks[i] instanceof TextInputCallback) {
					debugMessage("Got TextInputCallback");
					// prompt for text input
					TextInputCallback tic = (TextInputCallback) callbacks[i];
					// ignore the provided defaultValue
					System.err.print(tic.getPrompt());
					System.err.flush();
					tic.setText((new BufferedReader(new InputStreamReader(
							System.in))).readLine());

				} else if (callbacks[i] instanceof ChoiceCallback) {
					debugMessage("Got ChoiceCallback");
					// prompt for choice input
					ChoiceCallback cc = (ChoiceCallback) callbacks[i];
					System.err.print(cc.getPrompt());

					String[] strChoices = cc.getChoices();
					for (int j = 0; j < strChoices.length; j++) {
						System.err
								.print("choice[" + j + "] : " + strChoices[j]);
					}
					System.err.flush();
					cc.setSelectedIndex(Integer.parseInt((new BufferedReader(
							new InputStreamReader(System.in))).readLine()));
				}
			}
		} catch (Exception e) {
			throw new UnsupportedCallbackException(callbacks[i],
					"Callback exception: " + e);
		}
	}
        
        static void addNewPasswordCallbackMessage(  Callback[] callbacks,
                                                    String uid,
                                                    String oldPassword,
                                                    String newPassword ) throws UnsupportedCallbackException
        {
		int pwdCount    = 0;
		int i           = 0;
		try {
			for (i = 0; i < callbacks.length; i++) {
				if (callbacks[i] instanceof TextOutputCallback) {
					debugMessage( "Got TextOutputCallback while setting new password." );
					// simply display the message
					TextOutputCallback toc = (TextOutputCallback) callbacks[i];
					debugMessage(toc.getMessage() + " :" + toc.getMessage() );
				} else if (callbacks[i] instanceof NameCallback) {
					debugMessage( "Got NameCallback while setting new password - this should not happen !" );
                                        debugMessage( "Maybe you hit the next login module." );
				} else if (callbacks[i] instanceof PasswordCallback) {
					debugMessage( "Got PasswordCallback while setting new password." );
                                        
					PasswordCallback pc = (PasswordCallback) callbacks[i];

                                        // set first password callback with value of old password, the others with the new one
                                        if( pwdCount == 0 )
                                            pc.setPassword( new String( oldPassword ).toCharArray() );
                                        else
                                            pc.setPassword( new String( newPassword ).toCharArray() );
                                        
                                        pwdCount++;
                                            
				} else if (callbacks[i] instanceof ConfirmationCallback) {
					debugMessage( "Got ConfirmationCallback while setting new password !" );
					ConfirmationCallback cc = (ConfirmationCallback) callbacks[i];
                                        // "0" is the index of SUBMIT
                                        cc.setSelectedIndex( 0 );
				} else if (callbacks[i] instanceof TextInputCallback) {
					debugMessage( "Got TextInputCallback while setting new password - this should not happen !" );
				} else if (callbacks[i] instanceof ChoiceCallback) {
					debugMessage( "Got ChoiceCallback while setting new password - this should not happen !" );
				}
			}
		} catch( Exception e ) {
			throw new UnsupportedCallbackException( callbacks[i], "Callback exception: " + e );
		}
	}

	static void debugMessage(String msg) {
		System.out.println(msg);
	}

}

Monday Sep 24, 2007

OpenSSO with OpenID (on the Mac featuring Glassfish)

I've been asked for this a couple of times. Building and getting the OpenID extension for OpenSSO running
is no rocket science but there is no clear 'how to' document available. Here is what I do; the components I'm using are:

  • Sun Java System Directory Server 6 (from Java Enterprise System 5.1, running on Solaris 10U4 (Parallels))
  • Glassfish v2
  • Java "1.5.0_07" (Apple Build)
  • NetBeans 6.0M10 (to build the OpenID endpoint for OpenSSO)
  • OpenID Client (from the Python libs at http://www.openidenabled.com/)

I assume that you have already downloaded and deployed OpenSSO in the Glassfish application server. Also, you must be able to successfully login to OpenSSO's console as 'amadmin'.

Overall Scenario

We will setup 4 (HTTP) services:

  • A site-simulator for an OpenID enabled website (OpenID client) listening at openid.init8.net:8001 (openid.init.net is an alias for 127.0.0.1 - loopback)
  • An Apache server which serves your OpenID (http://teufelchen.init8.net/steffo). The 'index.html' delivered by this service contains a reference to the OpenID endpoint (i.e. OpenID extension for OpenSSO)
  • OpenID endpoint at teufelchen.init8.net:18080/openid/service
  • OpenSSO server at teufelchen.init8.net:8080/fam

The 4 components correspond to the ones used by Sun's deployment (as described in Hubert's blog: the relying party (Python client), the OpenID Identifier Server (Apache), OpenID Extension (OpenID Endpoint at 18080), Login (OpenSSO server at 8080). There is no registration component in our example. Users are either created from the OpenSSO console or privioned to an LDAP data source.

Step 1. Download and build the OpenID extension

First, login to OpenSSO's console and create an account to be used by the OpenID extension (the OpenID extension is an OpenSSO client which tries to authenticate against the OpenSSO server).

  1. Goto http://teufelchen.init8.net:8080/fam/UI/Login?service=ldapService
  2. Next select your realm and click on the Subjects tab.
  3. You should see different sub-tabs: User, Agent, Filtered-Role etc. Click on 'Agent'
  4. Click on 'New' and create a new agent of type Webservice Security Provider. Choose e.g. 'openid' and 'password' as ID and credentials.

Second, checkout the OpenSSO source code via

cvs -d :pserver:yourlogin@cvs.dev.java.net:/cvs checkout opensso

an save the result in e.g. ~/Projects/OpenSSO/src. Next, dowload the OpenSSO ClientSDK and save the JAR famclientsdk.jar in e.g. ~/Projects/OpenSSO/clientSDK/. The client SDK is needed by the OpenID extension.

The OpenID extension is at: opensso/extensions/openid/provider/ in the OpenSSO source tree. You'll also find a build.xml with all the necessary targets there. Now copy the following JARs to opensso/extensions/openid/provider/extlib:

  • commons-codec-1.3.jar (from Apache common codecs)
  • j2ee.jar (from Glassfish libs)
  • famclientsdk.jar (you've just downloaded this one)
  • jsf-facelets.jar (jave.net site)

Setup a NetBeans project; I used 'Java Project with existing Ant script'. Make sure you add the above JARs to your NetBeans project. There are two properties files which are crucial

  • AMConfig.properties
  • Provider.properties

More information can be found the extension's README

AMConfig.properties

AMConfig.properties contains configuration information required by the OpenSSO client SDK (do not mix up this one up with the OpenSSO server configuration file which has the same name but resides somewhere at /etc/OpenSSO or /etc/SUNWam - you've been asked for the exact location during the OpenSSO installation). Make sure that everything in this file is correct. Also check that the debug directity exists and that the naming URL is correct. Here are the keys that work for my setup:

com.iplanet.services.debug.level=warning
com.iplanet.services.debug.directory=/tmp
com.iplanet.am.notification.url=http://teufelchen.init8.net:8080/fam/notificationservice
# This is the ID of the Webservice Security Provider you created above
com.sun.identity.agents.app.username=openid
# And that's the password in clear text
com.iplanet.am.service.password=password
# And that's the encrypted password (obtained from running 'ampassword')
com.iplanet.am.service.secret=AQICJZXYu2vVsQ/WAwEdJh/x3+m2+daOUe3Y
# Check your sever's AMConfig.properties for the next value
am.encryption.pwd=AQICJZXYu2vVsQ/WAwEdJh/x3+m2+daOUe3Y
com.sun.identity.client.encryptionKey=AQICJZXYu2vVsQ/WAwEdJh/x3+m2+daOUe3Y
com.iplanet.security.encryptor=com.iplanet.services.util.JCEEncryption
com.sun.identity.idm.remote.notification.enabled=true
com.iplanet.am.sdk.remote.pollingTime=1
com.sun.identity.sm.notification.enabled=true
com.sun.identity.sm.cacheTime=1
com.iplanet.am.server.protocol=http
com.iplanet.am.server.host=teufelchen.init8.net
com.iplanet.am.server.port=8080
com.iplanet.am.cookie.name=iPlanetDirectoryPro
com.iplanet.am.session.client.polling.enable=true
com.iplanet.am.session.client.polling.period=180
com.iplanet.am.admin.cli.certdb.dir=@CONTAINER_CERTDB_DIR@
com.iplanet.am.admin.cli.certdb.prefix=@CONTAINER_CERTDB_PREFIX@
com.iplanet.am.admin.cli.certdb.passfile=@BASEDIR@/@PRODUCT_DIR@/config/.wtpass
com.sun.identity.agents.server.log.file.name=/tmp/amRemotePolicyLog
com.sun.identity.agents.logging.level=NONE
com.sun.identity.agents.notification.enabled=false
com.sun.identity.agents.notification.url=@NOTIFICATION_URL@
com.sun.identity.agents.polling.interval=3
com.sun.identity.policy.client.cacheMode=subtree
com.sun.identity.liberty.ws.soap.supportedActors=http://schemas.xmlsoap.org/soap/actor/next

Make sure, that in your setup, the values of the server's and client's AMConfig.properties match.

Provider.properties

There are only a few keys here.

openid.provider.service_url=http://teufelchen.init8.net:18080/openid/service
openid.provider.identity_pattern=http://teufelchen.init8.net/(.+)
# The next one is the Universal ID pattern of your OpenSSO installation
openid.provider.principal_pattern=id=(.+),ou=user,dc=init8,dc=net
openid.provider.encryption_key=mXiwLS8bsVBjQJ+dw13lTw==
openid.provider.login_url=http://teufelchen.init8.net:8080/fam/UI/Login?goto=
openid.provider.simple_registration=true
openid.provider.external_target=_blank
openid.provider.strict_protocol=false

You can now build the OpenID extension by selecting the target 'war'.

I deployed the 'provider.jar' at http://teufelchen.nit8.net:18080/openid. Browse to http://teufelchen.nit8.net:18080/openid and you should see the service end point.

Step 2. Configuring your OpenID URL and create a user in OpenSSO

The OpenID URL I want to use is: "http://teufelchen.init8.net/steffo". Browsing to this URL should retrieve the document at $DOCROOT/steffo/index.html. I used Apache's standard 'index.html' (the one that gives you the 'Seeing this instead of the website you expected?') and pasted the following between th HEAD tag:

<link rel="openid.server" href="http://teufelchen.init8.net:18080/openid/service"/>

You also have to create a user in OpenSSO. The ID of that user depends on the OpenID you want to use. If you want to use "http://teufelchen.init8.net/steffo", create a user "steffo". Note that this user might reside in an external LDAP (in which case you have to configure an appropriate authentication module and data source - but that's not required for this sample).

Step 3. Download and install the OpenID client

Download the Python libs at http://www.openidenabled.com/ . Follow the installation instructions and edit the file 'consumer.py' in the examples directory. Modify the following keys:

OPENID_PROVIDER_NAME = 'OpenSSOOpenID'
OPENID_PROVIDER_URL ='http://teufelchen.init8.net:18080/openid/service'

You can now start the consumer from the command shell: python consumer.py --port 8001

This sets up an HTTP service. The above command outputs something like:

Server running at:
http://openid.init8.net:8001/

I put a fake entry to /etc/hosts which assigns 127.0.0.1 the name "openid.init8.net". Direct your browser to this URL. You can now enter your OpenID (e.g. http://teufelchen.init8.net/steffo) into the box. Next, you'll be redirected to OPenSSO's login screen. After successfully entering your credential, you'll see a message like

The website http://openid.init8.net:8001/ is requesting confirmation that your OpenID identity is http://teufelchen.init8.net/steffo.

Done.

Thursday Mar 22, 2007

UNESCO on Ethical Implications of Emerging Technologies

The 2007 report is out and covers

  • Semantic Web and MetaData
  • Digital Identity Management and Biometrics
  • RFID and Sensor Networks
  • Geospatial Web and Location-based services
  • Mash Networking
  • Grid Computing
  • New Computing Technologies

Wednesday Mar 21, 2007

The need for virtualization on Load Balancers

Surprisingly many (big) companies still don't use load-balancing switches (LBs). I am talking of hardware boxes like Alteon, Foundry, Nauticus. Those that use LBs, use them in mission-critical environments. If any of these companies plans to rollout a new project that could benefit from a load-balanced network environment, they're instantly in a big discussion with the people who operate these boxes.

Since these boxes are mission-critical, configuration changes require a lot of discussion. This is espacially true if you want to convince these people to use configurations they've never used before (e.g. proxy IP addresses). End of the game

  • a lot discussions about what to configure and why it is needed
  • an unplanned outage of the mission-critical service (maybe)
  • dropping the hardware load-balancing for the new project and using a software LB solution

It would be easier to buy a seperate load-balancer for each project. But then: costs, costs, costs. A load-balancer with appropriate features is not a cheap thing: 10-20K EUR per box, at least 2 boxes (high-availability), three environments (development, integration, production) with 60-120K EUR per project/application.

So what's the alternative: discussions or cheap software solutions? Well the cheap software solutions I saw (I'm not talking about Resonate here, I'm talkling about things like BEAs LB plugin, DNS round-robin etc) don't take you that far. Load-balancing is a network thing, is a hardware thing (you don't use multi-homed PCs for L3 routing, don't you).

Discussions? The average time spend on discussions on how to configure the load-balancer without affecting the other applications is 5-10 days (you, the network guy plus some project manager). Yes, that's 5-15K EUR per project. Assume you have 3-5 projects on you LB infrastructure, that's 15-75K EUR spend on discussions. Plus the amount that is caused by the unplanned outage (maybe not of the production system but non-availability of the integration system can also cost money). So in total: 5-80K EUR.

That money could be saved if the network guy can easily be assured that the new configuration won't harm his existing one. That's what virtualization can do for you (and for him). Every project get its own sandbox on one LB platform.

Thursday Mar 01, 2007

Java Enterprise System 5 is out

Java ES 5 is out! Most exciting things for me in this release

  • Directory Server 6 and Directry Proxy/Virtual Directory (which now allows you to aggregate a single view not only from LDAP sources but also from SQL or flat files). Not that this is the first major upgrade of an overall very, very stable and mature product since 2003.
  • WebServer 7 comes with Elliptic Curve Cryptography support
  • J2EE Application Server 8.2 has zone support
  • Identity Manager 7.0 now support SPML 2.0, has a nice integration in NetBeans and includes Identity Auditor
  • Access Manager 7.1 now has a simplified single WAR deployment.


It also comes with a better systems management support.

Since Paralles 2.5 is now also officially released, the reduces the amount of beta software on my Mac substantially. Since I work in the identity systems area I haven't tested all of the Java ES components. However, for a PoC/TOI I had 6 instances of Directory Server 6 plus Directory Proxy and MySQL database running in my Solaris 10 Parallels image. No problems apart from the clock issue (which might be a problem with S10U1 and doesn't show up with Update 3 of Solaris 10). All this requires some memory; 2GB seem to be sufficient, and the simple truth "Hubraum ist durch nicht zu ersetzen außer durch noch mehr Hubraum" holds here as well.

Thursday Feb 15, 2007

Parallels (and Nevada)

Short version: yes it works out of the box. I downloaded the Parallels Beta 2.5 (Build 3150) software. For some reason the activation key didn't work - had to get a trial key. Started Parallels and immediately froze my Mac. Reboot (that's a shame because I found all the stuff around my OS X quite stable and that happened before). Anyway, I took the latest Nevada build and installed it. No problems so far. I'll post detailed results later.
About

steffo

Search

Top Tags
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