2

I used the following code (see this SO post) to read a userId and password stored as a JC2 Alias on my WAS 7 server.

    Map<String, String> map = new HashMap<String, String>();
    map.put(Constants.MAPPING_ALIAS, MDM_JC2_ALIAS);
    CallbackHandler callbackHandler = WSMappingCallbackHandlerFactory.getInstance().getCallbackHandler(map, null);
    LoginContext loginContext = new LoginContext(DEFAULT_PRINCIPAL_MAPPING, callbackHandler);
    loginContext.login();
    Subject subject = loginContext.getSubject();
    Set<Object> credentials = subject.getPrivateCredentials();
    PasswordCredential passwordCredential = (PasswordCredential) credentials.iterator().next();
    userId = passwordCredential.getUserName();
    password = new String(passwordCredential.getPassword());

The code works fine. But now I am trying to use it in a batch process. To test the batch process I have to use Run->Debug As in Rad 8.5. (I configure the process using Run->Debug As->Debug configurations). I am getting the error "java.lang.NullPointerException: WSMappingCallbackHandlerFactory not initialized". I have stepped through the code that works and can't see any difference in the values from the code which doesn't work. I suspect I may need to modify the build path in my debug configuration but I don't know what to change.

EDIT:

I don't think I have explained the situation very well. The code works inside of a web service running on WAS 7. We have completely different project which has some code which is called as a batch job as follows:

-classpath D:\WebSphere\AppServer\profiles\AppSrv01\Apps\Cell01\SSS.ear\PlanningEJB.jar;
D:\WebSphere\AppServer\profiles\AppSrv01\Apps\Cell01\SSS.ear\Planning.war\WEB-INF\classes;
D:\Progra~1\IBM\SQLLIB\java\db2jcc.jar -Dlog4j.configuration=file:/d:/apps/websphere/SSS/properties/log4J.properties
url.planning.batch.AppName D:\\apps\\websphere\\SSS\\properties\\sss.properties

I want to add the code to read the userId and Password to the code which is called as a batch job. Normally to debug the code called as a batch job we use Debug Configuration and the server does not have to be running. I can set breakpoints and step through the code and it works until I get to the callbackHandler line.

Community
  • 1
  • 1
ponder275
  • 903
  • 2
  • 12
  • 33
  • When you said the code works fine. Do you mean you can get it working with Run->Run As but fail when you try to debug? If that's what not what you mean, can you clarify on the setup/environment that you use when you can get it to work? – Elson Yuen Jan 24 '17 at 22:04
  • It works fine in a web project where it is called as a web service. – ponder275 Jan 24 '17 at 22:49
  • 1
    You need to start server in the debug mode and then call that service, you should be switched to debug perspective and breakpoint if you set one there. If you are trying to debug it as standard java application, it will not work. It must be run from the server. – Gas Jan 25 '17 at 09:44
  • 1
    To get configuration information outside the server, you need to use one of the `com.ibm.websphere.management.*` APIs like (**com.ibm.websphere.management.configservice.ConfigService**), MBeans, or wsadmin jacl/jython. As @Gas said, the API you're using will only work in the server. – Scott Kurz Jan 25 '17 at 15:16
  • 1
    In saying you're running this in "batch" mode do you mean you're attempting to run a standalone Java main(), outside the server? If so, are you assuming that any API available within the server environment is available outside a server simply by placing the appropriate classes on your classpath? That's not the case, and if the API won't work outside the server there's nothing you can do to the classpath or Debug configuration to change that. – Scott Kurz Jan 26 '17 at 13:45
  • [This](https://www.ibm.com/developerworks/community/forums/html/topic?id=222f5fb4-0ddd-4acb-a09f-da5af828fdf4) might help you get started on a JMX approach. – Scott Kurz Jan 26 '17 at 13:46
  • Thank you Gas and Scott for the help. Scott, if you want to put your comments as an answer I will mark it as accepted. – ponder275 Jan 26 '17 at 16:08
  • Glad to help @ponder275. Added an answer with more detailed sample and run config. I'm also going to propose an edit of the question title to make it clearer. – Scott Kurz Jan 27 '17 at 15:49
  • I think the new title will make it easier for others to use. Websphere help is often hard to find. Thanks! – ponder275 Jan 30 '17 at 19:48

1 Answers1

2

How to write a Java client (running outside the server) to view WebSphere authentication alias info

You can't use the same APIs from a client running outside the server as you could running within the server.

To do this in Java, (as opposed to wsadmin/Jython which would be an alternative approach), you could start with code like:

Sample Java Code

package mypkg;

import java.util.Properties;

import javax.management.ObjectName;

import com.ibm.websphere.management.AdminClient;
import com.ibm.websphere.management.AdminClientFactory;
import com.ibm.websphere.management.Session;
import com.ibm.websphere.management.configservice.ConfigServiceHelper;
import com.ibm.websphere.management.configservice.ConfigServiceProxy;

public class MyAdminClient {

    public static void main(String[] args) throws Exception {


        String aliasToFind = "blahAlias";  // Or "MyNode/blahAlias" if you use the node prefix.
        String SOAP_CONNECTOR_ADDRESS_PORT = "8879";
        String host = "localhost";

        // Initialize the AdminClient
        Properties adminProps = new Properties();
        adminProps.setProperty(AdminClient.CONNECTOR_TYPE, AdminClient.CONNECTOR_TYPE_SOAP);
        adminProps.setProperty(AdminClient.CONNECTOR_HOST, host);
        adminProps.setProperty(AdminClient.CONNECTOR_PORT, SOAP_CONNECTOR_ADDRESS_PORT);
        AdminClient adminClient = AdminClientFactory.createAdminClient(adminProps);

        // Get the ConfigService implementation
        ConfigServiceProxy configService = new ConfigServiceProxy(adminClient);

        Session session = new Session();

        // Find the parent security object
        ObjectName security = ConfigServiceHelper.createObjectName(null, "Security", null);
        ObjectName[] securityName = configService.queryConfigObjects(session, null, security, null);
        security = securityName[0];

        ObjectName authData = ConfigServiceHelper.createObjectName(null, "JAASAuthData", null);
        ObjectName[] authDataEntries = configService.queryConfigObjects(session, null, authData, null);
        ObjectName auth;

        for (int i=0; i < authDataEntries.length; i++) {
            auth = authDataEntries[i];
            Object aliasAttr = configService.getAttribute(session, auth, "alias");
            if (aliasAttr.equals(aliasToFind)) {
                System.out.println("Alias located: alias = " + configService.getAttribute(session, auth, "alias")
                + "; userId = " + configService.getAttribute(session, auth, "userId")                                
                + "; password = " + configService.getAttribute(session, auth, "password"));
                break;
            }
        }
    }
}

Use 'Administration Thin Client' to compile/run against

In the simplest case (without security, which might be useful for getting started), you can simply add the Administration Thin Client to your Eclipse project's Properties->Java Build Path.

In WebSphere V9 this would be the file WAS_INSTALL_ROOT/runtimes/com.ibm.ws.admin.client_9.0.jar and it's similar for other versions.

To run with security enabled you'll probably need to set additional system properties and possibly additional setup depending on JDK. See [here]( https://www.ibm.com/support/knowledgecenter/SSAW57_9.0.0/com.ibm.websphere.nd.multiplatform.doc/ae/txml_adminclient.html) for more info.

References / Credit

  • I started from the solution here
  • More on developing a Java administrative client
Scott Kurz
  • 4,985
  • 1
  • 18
  • 40