Tag Archives: WSLogin

ISIM 6 API Access from a remote machine

This question appears on many sites and blogs in separate parts, but I’ve not seen a complete description yet of the whole setup. Either way – this post documents my working example of getting the ISIM API working from a remote machine.

If you’re using IDI then the setup in terms of the classpath is the same apart from needing to put the jars either in your TDI installation directory JRE folder (under 3rdparty) or as specified by com.ibm.di.loader.userjars in your solution.properties file. The code will obviously need to be re-written in Javascript, but largely that’s just a matter of specifying methods with the full class name prefixed with “Packages.”.

I should also say that while the ISIM Web Services API is the initial client of choice it’s still a little limited so if you want to do more, then running a full remote API can be necessary. And of course if you need full beans functionality then you need to run inside the ISIM server itself to get the full API.

Anyway – back to Java an ISIM API on a remote machine.

Setup steps;

  • Download the IBM JDK for eclipse for your environment from here
  • Build a client directory – lets say that’s called C:\ISIM6_Client
  • Copy sas.client.props from the ISIM server. Use the one under <WAS_HOME> /profiles/AppSrv01/properties. Put the file into C:\ISIM6_Client\etc
  • Copy ssl.client.props from the ISIM server. Use the one under <WAS_HOME> /profiles/AppSrv01/properties. Put the file into C:\ISIM6_Client\etc
    • Edit this file and change the “user.root” at the top of the file to “C:\ISIM6_Client”
  • Copy (or create) key.p12 and trust.p12 in C:\ISIM6_Client\etc. You can copy these files from the ISIM server under <WAS_HOME>/profiles/AppSrv01/etc
    • Putting these files into C:\ISIM_Client\etc and updating ssl.client.props means that the ssl.client.props properties “com.ibm.ssl.keyStore” and “com.ibm.ssl.trustStore” will refer to them correctly.
    • These will contain the certificate of your ISIM server. If you point to a new ISIM server make sure “com.ibm.ssl.enableSignerExchangePrompt=gui” is set in ssl.client.props and then you will get a certificate import prompt that you can just accept to add the certificate for the new server to your trust store.
  • Either copy orb.properties from <WAS_HOME>/java/jre/lib/orb.properties into <JAVA_HOME>/lib or create one with the following contents;
# IBM JDK properties
org.omg.CORBA.ORBClass=com.ibm.CORBA.iiop.ORB
org.omg.CORBA.ORBSingletonClass=com.ibm.rmi.corba.ORBSingleton
javax.rmi.CORBA.StubClass=com.ibm.rmi.javax.rmi.CORBA.StubDelegateImpl
javax.rmi.CORBA.PortableRemoteObjectClass=com.ibm.rmi.javax.rmi.PortableRemoteObject
javax.rmi.CORBA.UtilClass=com.ibm.ws.orb.WSUtilDelegateImpl

 # WS Plugins
com.ibm.CORBA.ORBPluginClass.com.ibm.ws.wlm.client.WLMClient
com.ibm.CORBA.ORBPluginClass.com.ibm.ws.orbimpl.transport.WSTransport
com.ibm.CORBA.ORBPluginClass.com.ibm.ws.orbimpl.WSORBPropertyManager
com.ibm.CORBA.ORBPluginClass.com.ibm.ISecurityUtilityImpl.SecurityPropertyManager
com.ibm.CORBA.ORBPluginClass.com.ibm.ws.orb.WSSubcontractInitImpl

 # WS Interceptors
org.omg.PortableInterceptor.ORBInitializerClass.com.ibm.ws.Transaction.JTS.TxInterceptorInitializer
org.omg.PortableInterceptor.ORBInitializerClass.com.ibm.ejs.ras.RasContextSupport
org.omg.PortableInterceptor.ORBInitializerClass.com.ibm.ISecurityLocalObjectBaseL13Impl.ClientRIWrapper
org.omg.PortableInterceptor.ORBInitializerClass.com.ibm.ws.activity.remote.cos.ActivityServiceClientInterceptor
org.omg.PortableInterceptor.ORBInitializerClass.com.ibm.ISecurityLocalObjectBaseL13Impl.CSIClientRI
org.omg.PortableInterceptor.ORBInitializerClass.com.ibm.debug.olt.ivbtrjrt.OLT_RI
org.omg.PortableInterceptor.ORBInitializerClass.com.ibm.ws.wlm.client.WLMClientInitializer

 # WS ORB &amp; Plugins properties
com.ibm.ws.orb.transport.ConnectionInterceptorName=com.ibm.ISecurityLocalObjectBaseL13Impl.SecurityConnectionInterceptor
com.ibm.ws.orb.transport.WSSSLClientSocketFactoryName=com.ibm.ws.security.orbssl.WSSSLClientSocketFactoryImpl
com.ibm.CORBA.enableLocateRequest=true
com.ibm.CORBA.ORBCharEncoding=UTF8
com.ibm.CORBA.ForceTunnel=never
com.ibm.CORBA.TransportMode=Pluggable
  • Create the JAAS login file in C:\ISIM6_Client\etc\jaas_login_was.conf that contains the following line for ISIM 6;
WSLogin {
    com.ibm.ws.security.common.auth.module.proxy.WSLoginModuleProxy required delegate=com.ibm.ws.security.common.auth.module.WSLoginModuleImpl;
};
  • Finally, we need the jars that will make the client. I’m using Netbeans so I just create a new Library Tools->Libraries. Click the “New Library” button and add the following jars.
    • Note that tmsMessages.jar is a jar of the tmsMessages.* files from the ISIM server.

  • Next, create a new project in Netbeans;
    • Right click the project name, chose properties. Click Libraries.
      • Add or select the IBM JDK as your Java Platform – you may need create a new platform in “Manage Platforms” that points to the IBM JDK you downloaded in the first step.
      • Under the Compile tab add the ISIM6_Client library created in the previous step
  • Now, add some code to your project. This example is all about the setup of the client so I’m not spending time on the client code in particular, but the example below should be sufficient to get you going. Note that this code is not intended to be production ready – it’s a stripped down example to show exactly what’s happening. Also, check where you need to enter your usernames and passwords below;
package isimapiclient;
import com.ibm.itim.apps.ApplicationException;
import com.ibm.itim.apps.InitialPlatformContext;
import com.ibm.itim.apps.PlatformContext;
import com.ibm.itim.apps.identity.PersonMO;
import com.ibm.itim.dataservices.model.DistinguishedName;
import com.ibm.itim.dataservices.model.domain.Person;
import java.rmi.RemoteException;
import java.util.Hashtable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginContext;
import com.ibm.websphere.security.auth.callback.WSCallbackHandlerImpl;
import javax.security.auth.login.LoginException;

 
 public class IsimApiClient {

     public static void main(String[] args) {

         try {
            IsimApiClient client = new IsimApiClient();
            PlatformContext itimPlatform = client.getPlatform();
            Subject subject = client.getSubject();

             System.out.println("loginContext: "+itimPlatform.toString() + " - " + subject);

             DistinguishedName empDN = new DistinguishedName("erglobalid=SOMEERGLOBALID,ou=0,ou=people,erglobalid=00000000000000000000,ou=ibm,dc=com");
            PersonMO employeeMO = new PersonMO(itimPlatform, subject, empDN);
            Person emp = employeeMO.getData();
            System.out.println("Data: " + emp.getProfileName());
            System.out.println("Name: " + emp.getName());

         } catch (RemoteException ex) {
            Logger.getLogger(IsimApiClient.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ApplicationException ex) {
            Logger.getLogger(IsimApiClient.class.getName()).log(Level.SEVERE, null, ex);
        } catch (LoginException ex) {
            Logger.getLogger(IsimApiClient.class.getName()).log(Level.SEVERE, null, ex);
        }

     }

 
     public PlatformContext getPlatform() {

         String hostname = "YOUR HOSTNAME";
        String port = "2809";    (Check BOOTSTRAP_ADDRESS on the ISIM server)

         System.setProperty("java.security.auth.login.config", "file:C:/ISIM6_Client/etc/jaas_login_was.conf");
    System.setProperty("com.ibm.CORBA.ConfigURL", "file: C:/ISIM6_Client/etc/sas.client.props");
    System.setProperty("com.ibm.SSL.ConfigURL", "file: C:/ISIM6_Client/etc/ssl.client.props");
    System.setProperty("com.ibm.CORBA.securityServerHost", hostname);
    System.setProperty("com.ibm.CORBA.securityServerPort", port);
    
    String appServerURL = "corbaloc:iiop:" + hostname + ":" + port;
    String platformContextFactory = "com.ibm.itim.apps.impl.websphere.WebSpherePlatformContextFactory";
    String itimRealm = "itimCustomRealm";
    String ejbUser = "isimsystem@" + itimRealm;        // Really important to include the @realm part
    String ejbPwd = "&lt;EJBPASSWORD&gt;";  (Check enRole.properties)

 
         Hashtable env = new java.util.Hashtable();
    env.put(InitialPlatformContext.CONTEXT_FACTORY, platformContextFactory);
    env.put(PlatformContext.PLATFORM_URL, appServerURL);
    env.put(PlatformContext.PLATFORM_PRINCIPAL, ejbUser);
    env.put(PlatformContext.PLATFORM_CREDENTIALS, ejbPwd);
    env.put(PlatformContext.PLATFORM_REALM, itimRealm);

         PlatformContext platform = null;
    
    try
    {
        platform = new InitialPlatformContext(env);
        System.out.println("Successfully got platform context");

     }
    catch(RemoteException e)
    {
        System.out.println("Error Class: " + e.getClass());
        System.out.println("Error Message: " + e.getMessage());
        System.out.println("Error LocalizedMessage: " + e.getLocalizedMessage());

     } catch (ApplicationException ex) {
            Logger.getLogger(IsimApiClient.class.getName()).log(Level.SEVERE, null, ex);
        }
        return platform;
    }

     private Subject getSubject() throws LoginException {

             String itimPswd = "&lt;ITIM MANAGER PASSWORD&gt;";
            String itimRealm = "itimCustomRealm";
            String itimUser = "itim manager";

             // Create the JAAS CallbackHandler
            CallbackHandler handler = null;
            if (itimRealm == null) {
                    System.out.println("getSubject: Realm is NULL");
                    handler = new WSCallbackHandlerImpl(itimUser, itimPswd);
            } else {
                    System.out.println("getSubject: Building callback handler: ["+itimUser+"]/["+itimRealm+"]/["+itimPswd+"]");
                    handler = new WSCallbackHandlerImpl(itimUser, itimRealm, itimPswd);
            }

             LoginContext loginContext = new LoginContext("WSLogin", handler);

             try
            {
                    System.out.println("Attempting login");
                    loginContext.login();
                    System.out.println("Logged in");
                    System.out.println("Obtained loginContext, subject is: " + loginContext.getSubject().toString());
            }
            catch(Exception e)
            {
                    System.out.println("Error Class: " + e.getClass());
                    System.out.println("Error Message: " + e.getMessage());
                    System.out.println("Error LocalizedMessage: " + e.getLocalizedMessage());

             }
            return loginContext.getSubject();
    }

 }

 

 

Errors

Some of the errors and solutions I have experienced along the way with this one;

Server ports – BOOTSTRAP_ADDRESS

If you don’t have the right port for your websphere server, then you can get the following error. In this case I have two clusters – one has the application server with a bootstrap port on 2811, the other on 2810 – my error below is when I mixed the two up (doh!).

SEVERE: null com.ibm.itim.apps.ApplicationException: 
Context: myserverCell01/clusters/ITIM_Messaging_Cluster, 
name: enroleejb.ManagedObjectImplHome: First component in name enroleejb.ManagedObjectImplHome not found. 
at com.ibm.itim.apps.identity.PersonMO.getData(PersonMO.java:149)

This error is similar – completely the wrong port and there is no process listening on it.  As usual, search for BOOTSTRAP_ADDRESS and locate the port for your Application Server WAS instance;

getSubject: Error Class: class com.ibm.websphere.security.auth.WSLoginFailedException getSubject: 
Error Message: SECJ0395E: Could not locate the SecurityServer at host/port:{0} to validate the userid and password entered. 
You might need to specify valid securityServerHost/Port in ${WAS_INSTALL_ROOT}/profiles/profile_name/properties/sas.client.props file. 
getSubject: Error LocalizedMessage: SECJ0395E: Could not locate the SecurityServer at host/port:{0} to validate the userid and password entered. 
You might need to specify valid securityServerHost/Port in ${WAS_INSTALL_ROOT}/profiles/profile_name/properties/sas.client.props file. loginContext: null

Name resolution

I remember this problem from back in the day with very old CORBA servers. What I didn’t realise was that my VPN connection from home was giving me a different reverse resolution to that in the office. Oh well – out with the hosts file in the end, but as usual it took a while to realise what the problem was.

It is also strange because I was providing the FQDN of my server in “com.ibm.CORBA.securityServerHost” and “PlatformContext.PLATFORM_URL”, but for some reason the client code was changing this to the shortname (at least that’s what appeared in the logs below). The problem in this case was environmental and some of my own making probably. While we have an ISIM cluster and load balancer in front of that for https traffic, the load balancer doesn’t handle the API port (BOOTSTRAP_PORT in WAS). So that meant I was doing this setup by going straight to a single AppServer. For some reason my VPN from home would resolve the AppServer hostname to IP correctly, but then when it attempted a reverse lookup for the IP address it got the load balancer FQDN back – no chance that would work! Two simple answers; 1) local hosts file to correct the name resolution while developing and 2) add the BOOTSTRAP_PORT to the loadbalancer configuration and use that fqdn instead. Either way the message is that you have to have your forward and reverse name resolution in place such that it resolves both ways to the same host/ip

My error;

getSubject: Error Class: class com.ibm.websphere.security.auth.WSLoginFailedException
getSubject: Error Message: SECJ0395E: Could not locate the SecurityServer at host/port:{0} to validate the userid and password entered. You might need to specify valid securityServerHost/Port in ${WAS_INSTALL_ROOT}/profiles/profile_name/properties/sas.client.props file.
getSubject: Error LocalizedMessage: SECJ0395E: Could not locate the SecurityServer at host/port:{0} to validate the userid and password entered. You might need to specify valid securityServerHost/Port in ${WAS_INSTALL_ROOT}/profiles/profile_name/properties/sas.client.props file.
loginContext: null

 

If you read this article from IBM, at the bottom it describes how to configure tracing for the corba client & doing this generated a log which turns the above ISIM message into something useful & that’s what showed me my UnknownHostException!;

11:08:57.801 com.ibm.CORBA.transport.TransportBase getHostIPAddress:134 P=735951:O=0:CT ORBRas[default]  java.net.UnknownHostException: MYHOSTNAME: MYHOSTNAME
    at java.net.InetAddress.getAllByName0(InetAddress.java:1384)
    at java.net.InetAddress.getAllByName(InetAddress.java:1293)
    at java.net.InetAddress.getAllByName(InetAddress.java:1218)
    at java.net.InetAddress.getByName(InetAddress.java:1168)
    at com.ibm.CORBA.transport.TransportBase.getHostIPAddress(TransportBase.java:132)

 

More errors

To be honest I had many, but didn’t capture them all. I’ve got more work to do on this client code so will update this post with what will be some more inevitable problems. That said, the configuration in this post should help you avoid most problems.