Websphere… omg

I just had my first foray into getting a simple war running in a WebSphere application server. Wow – what a nightmare. Man I hope i never have to do that again… what a waste. Just awful.

What’s worse, because it’s so ironic, it’s a spring boot based app which runs perfectly with with ‘java -jar …’ using the embedded tomcat, or jetty, or undertow.

 

Advertisements

Binding jBPM WorkItemHandlers from a Spring Context

I’ve just spent a lump of time (too much for how simple it really is) working out how to do this with jBPM 6.3 so I’ve added this blog to help those who come after.

This has worked for me – I’m not sure that it’s the ‘right’ or most efficient way to achieve the desired result however.

I’m using Spring Boot with jBPM 6.3 (this is valid for the commercial version too – jBoss BPM Suite 6.2). I’ve successfully loaded all the appropriate jBPM services using the instructions from the jBPM 6.3 documentation (though I’ve translated it to Spring Java config rather than the XML config documented), and am happily deploying and executing services.

The problem comes when trying to load WorkItemHandlers from a Spring context and I’ve fought the good fight for a week or three now on and off trying to find a good way to solve it. It’s taken time because there really isn’t a lot of help out there in Google land other than a gamut of hints indicating that many have had this issue and have solved it eventually but haven’t reflected the solution back out there.

In the end after reading quite a lot of the source code and stepping through a few times I took the suggestion from a thread in the jBoss developer forum and extended org.kie.spring.manager.SpringRuntimeManagerFactoryImpl in order to inject my own implementation of org.kie.api.runtime.manager.RegisterableItemsFactory which has a named list of Spring managed WorkItemHandlers which need to be made available to processes executed by jBPM.

My implementation of RuntimeManagerFactory factory is as follows. I’ve overridden the adjustEnvironment method to force my version of the RegisterableItemsFactory in; this method is called when setting up the runtime environment for a process execution.

package myjbpm.jbpm.common.workitemhandlers.impl;

import org.jbpm.runtime.manager.impl.SimpleRuntimeEnvironment;
import org.kie.api.runtime.manager.RegisterableItemsFactory;
import org.kie.api.runtime.manager.RuntimeEnvironment;
import org.kie.api.runtime.process.WorkItemHandler;
import org.kie.spring.manager.SpringRuntimeManagerFactoryImpl;


/**
 * This extends the jBPM {@link SpringRuntimeManagerFactoryImpl} in order to override {@link
 * SpringRuntimeManagerFactoryImpl#adjustEnvironment(RuntimeEnvironment)} method and put in our
 * own {@link RegisterableItemsFactory} implementation which has a reference to the Spring loaded {@link
 * WorkItemHandler} beans.
 */
public class CustomRegisterableItemsSpringRuntimeManagerFactoryImpl extends SpringRuntimeManagerFactoryImpl {

    private final RegisterableItemsFactory springRegisterableItemsFactory;


    public CustomRegisterableItemsSpringRuntimeManagerFactoryImpl(
            RegisterableItemsFactory springRegisterableItemsFactory) {
        this.springRegisterableItemsFactory = springRegisterableItemsFactory;
    }


    @Override
    protected void adjustEnvironment(final RuntimeEnvironment environment) {
        super.adjustEnvironment(environment);
        ((SimpleRuntimeEnvironment) environment).setRegisterableItemsFactory(springRegisterableItemsFactory);
    }
}

The matching RegisterableItemsFactory is as follows, notice that I extend jBPM’s DefaultRegisterableItemsFactory in order to maintain default functionality for other item types; these could be overridden to be retrieved from a Spring context also I expect:

package myjbpm.jbpm.common.workitemhandlers;

import org.jbpm.runtime.manager.impl.DefaultRegisterableItemsFactory;
import org.kie.api.runtime.manager.RuntimeEngine;
import org.kie.api.runtime.process.WorkItemHandler;

import java.util.Map;


public class SpringRegisterableItemsFactory extends DefaultRegisterableItemsFactory {

    private final SpringWorkItemHandlerProducer workItemHandlerProducer;


    public SpringRegisterableItemsFactory(SpringWorkItemHandlerProducer workItemHandlerProducer) {
        this.workItemHandlerProducer = workItemHandlerProducer;
    }


    @Override
    public Map<String, WorkItemHandler> getWorkItemHandlers(final RuntimeEngine runtime) {
        Map<String, WorkItemHandler> workItemHandlers = super.getWorkItemHandlers(runtime);
        workItemHandlers.putAll(workItemHandlerProducer.getWorkItemHandlers());

        return workItemHandlers;
    }
}

Where the SpringWorkItemHandlerProducer is used to translate the Spring injected java.util.List<NamedWorkItemHandler> into the java.util.Map<String, WorkItemHandler> expected by the RegisterableItemsFactory interface. It is as follows:

package myjbpm.jbpm.common.workitemhandlers.impl;

import myjbpm.jbpm.common.workitemhandlers.SpringWorkItemHandlerProducer;
import myjbpm.jbpm.domain.handler.NamedWorkItemHandler;
import org.kie.api.runtime.process.WorkItemHandler;

import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class SpringWorkItemHandlerProducerImpl implements SpringWorkItemHandlerProducer {

    private final Map&amp;amp;amp;lt;String, WorkItemHandler&amp;amp;amp;gt; workItemHandlers = new HashMap&amp;amp;amp;lt;&amp;amp;amp;gt;();


    public SpringWorkItemHandlerProducerImpl(List<NamedWorkItemHandler> workItemHandlers) {
        mapHandlers(workItemHandlers);
    }


    @Override
    public Map<String, WorkItemHandler> getWorkItemHandlers() {
        return workItemHandlers;
    }


    private void mapHandlers(final List<NamedWorkItemHandler> namedWorkItemHandlers) {
        for (NamedWorkItemHandler wih : namedWorkItemHandlers) {
            this.workItemHandlers.put(wih.getTaskName(), wih);
        }
    }
}

And NamedWorkItemHandler is:

package myjbpm.jbpm.domain.handler;

import org.kie.api.runtime.process.WorkItemHandler;


public interface NamedWorkItemHandler extends WorkItemHandler {
    String getTaskName();
}

Finally these are wired together using some simple Spring bean configuration as follows:

@Bean
public RuntimeManagerFactory runtimeManager(JtaTransactionManager transactionManager,
        UserGroupCallback userGroupCallback, RegisterableItemsFactory springRegisterableItemsFactory) {
    SpringRuntimeManagerFactoryImpl managerFactory = new CustomRegisterableItemsSpringRuntimeManagerFactoryImpl(
            springRegisterableItemsFactory);
    managerFactory.setTransactionManager(transactionManager);
    managerFactory.setUserGroupCallback(userGroupCallback);

    return managerFactory;
}


@Bean
public RegisterableItemsFactory registerableItemsFactory(
        SpringWorkItemHandlerProducer springWorkItemHandlerProducer) {
    return new SpringRegisterableItemsFactory(springWorkItemHandlerProducer);
}


@Bean
public SpringWorkItemHandlerProducer springWorkItemHandlerProducer(
        List<NamedWorkItemHandler> namedWorkItemHandlers) {
    return new SpringWorkItemHandlerProducerImpl(namedWorkItemHandlers);
}

Feedback welcome – particularly if you know a better way to do this, or can see a potential issue. I’ve only just got this working so it’s possible it’s horribly wrong once I get down the track further.

Securing your JBoss JMX Invoker Layer

If you use JBoss and have a nicely secured JMX Console and/or Web Console it’s a fairly safe bet that, like me, you haven’t secured the invoker layer; meaning any old monkey can most likely shutdown your container whenever they feel like it.

Recently I implemented an MBean in JBoss to use as a batch trigger from a ControlM implementation and was surprised (probably shouldn’t have been though) that all my carefully crafted security for the JMXConsole and Web Console was ignored with complete impunity by the tool (twiddle.sh) that I used to invoke my MBean. Since then I’ve been through a pile of pain trying to get an RMI call to a JBoss XMBean to require authentication and I thought I’d put some instructions in plain language on how to do it.

I do this for two reasons:

  1. because I bet a lot of developers miss this one; and
  2. because the documentation and other information I find online is limited and confusing.

For demonstration I’m going to use a standard JBoss MBean for setting system properties in a running application container.

A Simple Example of Setting a System Property in JBoss using Twiddle

Using the default JBoss version of twiddle.sh (in the bin directory beneath JBoss home) against the default JNP location of JBoss (localhost:1099) you can execute the following to set a system property in a running container.

# this assumes you're in the bin directory of JBoss Home.
./twiddle.sh -s localhost:1099 invoke "jboss:type=Service,name=SystemProperties" set myprop mypropvalue
'null'

To verify that you have been succesful (assuming you didn’t get an exception in the last operation) you can do the following:

# this assumes you're in the bin directory of JBoss Home.
./twiddle.sh -s localhost:1099 invoke "jboss:type=Service,name=SystemProperties" get myprop
mypropvalue

This example will work from anywhere on your network where you’re not prevented from reaching the JNP URL of the container (prevented by a firewall or IP filter for example) regardless of the JMX Console and Web Console security you’ve put in place (there is plenty of documentation around for securing the JMX Console and Web Console). This is because the JMX Console and Web Console are HTTP based and as such are secured in the normal way you would secure a website on JBoss (i.e. in web-inf.xml and jboss-web.xml) whereas the invoker layer is not HTTP based and as such must use an alternate method of security; the key file in this operation is the jmx-invoker-service.xml file in the JBoss deploy directory.

Securing the Invoker Layer

The invoker layer is the one you are calling through when you query or invoke on an MBean via RMI (i.e. with twiddle.sh – as above). This layer is not subject to the security constraints you will have placed on your HTTP based JMX Console or Web Consoles.

To make this layer secure the key file you’re interested in is the jmx-invoker-service.xml in the JBoss deploy directory; and the key operation configuration you will need to change is for ‘invoke’.

The default configuration of the invoke operation in this file is:

<server>

	<!-- excluded for brevity -->

	<mbean code="org.jboss.jmx.connector.invoker.InvokerAdaptorService" name="jboss.jmx:type=adaptor,name=Invoker" xmbean-dd="">
		<xmbean>
			<description>The JMX Detached Invoker Service</description>
			<class>org.jboss.jmx.connector.invoker.InvokerAdaptorService</class>

			<!-- excluded for brevity -->

			<operation>
				<description>The detached invoker entry point</description>
				<name>invoke</name>
				<parameter>
					<description>The method invocation context</description>
					<name>invocation</name>
					<type>org.jboss.invocation.Invocation</type>
				</parameter>
				<return-type>java.lang.Object</return-type>
				<descriptors>
					<interceptors>

						<!-- Uncomment to require authenticated users -->
						<!-- <interceptor code="org.jboss.jmx.connector.invoker.AuthenticationInterceptor" securityDomain="java:/jaas/jmx-console"/> -->

						<!-- Interceptor that deals with non-serializable results -->
						<interceptor code="org.jboss.jmx.connector.invoker.SerializableInterceptor" policyClass="StripModelMBeanInfoPolicy"/>

					</interceptors>
				</descriptors>
			</operation>
		</xmbean>
	</mbean>
</server>

So to switch on authentication we do what it says and ‘Uncomment to require authenticated users’:

<server>

	<!-- excluded for brevity -->

	<mbean code="org.jboss.jmx.connector.invoker.InvokerAdaptorService" name="jboss.jmx:type=adaptor,name=Invoker" xmbean-dd="">
		<xmbean>
			<description>The JMX Detached Invoker Service</description>
			<class>org.jboss.jmx.connector.invoker.InvokerAdaptorService</class>

			<!-- excluded for brevity -->

			<operation>
				<description>The detached invoker entry point</description>
				<name>invoke</name>
				<parameter>
					<description>The method invocation context</description>
					<name>invocation</name>
					<type>org.jboss.invocation.Invocation</type>
				</parameter>
				<return-type>java.lang.Object</return-type>
				<descriptors>
					<interceptors>

						<!-- Uncomment to require authenticated users -->
						<interceptor code="org.jboss.jmx.connector.invoker.AuthenticationInterceptor" securityDomain="java:/jaas/jmx-console"/>

						<!-- Interceptor that deals with non-serializable results -->
						<interceptor code="org.jboss.jmx.connector.invoker.SerializableInterceptor" policyClass="StripModelMBeanInfoPolicy"/>

					</interceptors>
				</descriptors>
			</operation>
		</xmbean>
	</mbean>
</server>

If you haven’t changed the default security realm for your JMX Console (i.e. java:/jaas/jmx-console) you will now have an invoker layer secured with the same credentials as for your JMX Console. To change this add a new security realm to your global login-config.xml in the conf directory of your container and match the name you give it in the securityDomain attribute of the Authentication Interceptor.

I’ve not yet delved too deeply into setting a specific set of roles, at this point I set my invoker user to JBossAdmin which means that user can do pretty much anything exposed to JMX. That’s ok for my purposes tho (feel free to write a response with the details of setting roles for particular JMX functions :-)).

Invoking on a Secure Invoker Layer

Ok so now that it’s secure how do you invoke an operation on it?

With the default JBoss twiddle.sh utility there are arguments -u (or –user=) for user and -p (–password=) for password.

# this assumes you're in the bin directory of JBoss Home.
./twiddle.sh -s localhost:1099 --user=myuser --password=mypassword invoke "jboss:type=Service,name=SystemProperties" get myprop
mypropvalue

These arguments work fine except your password is now in clear text and even worse is visible in the process list while it’s executing – in clear text with ‘password=’ conveniently placed for extraction by a simple script!! This seems a bit of an oversight in the tool to me.

To get around this issue in my environment I took the source and modified the main class of twiddle.jar to accept a password from Standard In (patch is below – no promises or guarantees though) which prevents the password showing in your password list and allows you to use standard encryption utilities to decrypt and pipe it into the process without ever making it visible clear text.

You would now invoke as follows:

# this assumes you're in the bin directory of JBoss Home.
mypassword | ./twiddle.sh -s localhost:1099 --user=myuser invoke "jboss:type=Service,name=SystemProperties" get myprop
mypropvalue

or better; from an encrypted password file (or better yet a repository) such as follows:

# this assumes you're in the bin directory of JBoss Home and have previously encrypted your password and encryption key into ~/.<username>.key and ~/.<username>.psw.
KEY=`cat ~/.<execution username>.key`
PWD=`cat ~/.<execution username>.psw | crypt $KEY`

PWD | ./twiddle.sh -s localhost:1099 --user=myuser invoke "jboss:type=Service,name=SystemProperties" get myprop
mypropvalue

to encrypt your password to be used as above you might do:

echo "<password>" | crypt > ~/.<execution username>.psw

which will request an encryption key which you would save as follows (for this example anyway):

cat "<encryption key>" > ~/.<execution username>.key

These files would, of course, be accessable only from your execution user.

Securing the JMX Console

For reference the key files you’re interested in here are:

  • conf/login-config.xml
  • deploy/jmx-console.war/META-INF/web.xml
  • deploy/jmx-console.war/META-INF/jboss-web.xml

Securing the JMX Web Console

For reference the key files you’re interested in here are:

  • conf/login-config.xml
  • deploy/management/web-console.war/META-INF/web.xml
  • deploy/management/web-console.war/META-INF/jboss-web.xml

Stack

These instructions will apply broadly but for reference purposes the stack I have is:

  • JBoss 4.2.3.GA
  • Java jdk1.6.0_13
  • Windows XP or Solaris 10

References

http://www.jboss.org/community/wiki/Twiddle

http://www.jboss.org/community/wiki/jbossserver-aquicktour

https://jira.jboss.org/jira/secure/attachment/12313982/jboss-securejmx.pdf (PDF Document)

Regards,
Jon

🙂

Patch For Twiddle to Take Password from StdIn (no promises or guarantees)


Index: src/main/org/jboss/console/twiddle/Twiddle.java
===================================================================
--- src/main/org/jboss/console/twiddle/Twiddle.java    (revision 94201)
+++ src/main/org/jboss/console/twiddle/Twiddle.java    (working copy)
@@ -24,8 +24,10 @@
 import gnu.getopt.Getopt;
 import gnu.getopt.LongOpt;

+import java.io.BufferedReader;
 import java.io.File;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -41,7 +43,6 @@
 import javax.naming.Context;
 import javax.naming.InitialContext;
 import javax.naming.NamingException;
-
 import org.jboss.console.twiddle.command.Command;
 import org.jboss.console.twiddle.command.CommandContext;
 import org.jboss.console.twiddle.command.CommandException;
@@ -148,7 +149,7 @@
 }
 };
 }
-
+
 public Command createCommand(final String name)
 throws NoSuchCommandException, Exception
 {
@@ -383,7 +384,7 @@

 out.println("A JMX client to 'twiddle' with a remote JBoss server.");
 out.println();
-      out.println("usage: " + PROGRAM_NAME + " [options] <command> [command_arguments]");
+      out.println("usage: [echo <password> | ] " + PROGRAM_NAME + " [options] <command> [command_arguments]");
 out.println();
 out.println("options:");
 out.println("    -h, --help                Show this help message");
@@ -397,6 +398,10 @@
 out.println("    -u, --user=<name>         Specify the username for authentication");
 out.println("    -p, --password=<name>     Specify the password for authentication");
 out.println("    -q, --quiet               Be somewhat more quiet");
+      out.println();
+      out.println("A password should be passed in by echoing it and piping it to the command. If you");
+      out.println("use the -p (--password) option your password may be visible in clear text in a ");
+      out.println("process listing such as `ps -ef`.");
 out.flush();
 }

@@ -421,6 +426,28 @@
 Getopt getopt = new Getopt(PROGRAM_NAME, args, sopts, lopts);
 int code;

+        /* Get standard in if it's there - assume it's a password. This is to allow a password to be passed and
+         * prevent it showing in a process listing (e.g. ps -ef in Unix). The -p argument will be ignored if
+         * the password is passed through Standard In.
+         */
+        boolean passwordRetrievedFromStdIn = false;
+        if (System.in.available() > 0) {
+            InputStreamReader inp = new InputStreamReader(System.in);
+            BufferedReader br = new BufferedReader(inp);
+            String stdin = br.readLine();
+
+            if (stdin != null &amp;&amp; stdin.trim().length() > 0) {
+                String password = stdin.trim();
+                SecurityAssociation.setCredential(password);
+
+                passwordRetrievedFromStdIn = true;
+
+                if (log.isDebugEnabled()) {
+                    log.debug("Password retrieved from standard in. Ignoring -p argument.");
+                }
+            }
+        }
+
 PROCESS_ARGUMENTS:

 while ((code = getopt.getopt()) != -1)
@@ -531,8 +558,13 @@
 SecurityAssociation.setPrincipal(new SimplePrincipal(username));
 break;
 case 'p':
-                 String password = getopt.getOptarg();
-                 SecurityAssociation.setCredential(password);
+                  if (!passwordRetrievedFromStdIn) {
+                     String password = getopt.getOptarg();
+                     SecurityAssociation.setCredential(password);
+
+                     log.warn("Password retrieved from -p argument. Your password may be visible in cleartext in a process listing during execution. " +
+                             "Consider using Standard In to enter the password instead (i.e. echo \"password\" | twiddle ...)");
+                  }
 break;

 // Enable quiet operations

 light="true"

Passionate About Programming

Today I bought The Passionate Programmer from the Pragmatic Bookstore; this is the 2nd Edition of My Job Went to India: 52 Ways to Save Your Job and has been re-targeted more clearly at becoming an ‘awesome developer’ rather than ‘doing enough to not get fired’ which the earlier title implied. While buying this I was distracted by a post on The Pragmatic Life blog called Share Your Passion which inspired me to share what it is that makes us (the bloggers here) passionate about developing software. BTW: So far the book is great – thanks Chad.

There is synchronicity at play here; when we started this blog the other day we were toying with subtitles and one of the ones we considered seriously was a tongue in check ‘awesomeness codified’ (personally I still like this the best even though I didn’t come up with it :-P). Part of the reason we started this blog is to put stuff out in the public domain to get feedback. To reach out to people who know and understand more than us in the public domain and to share what we’ve found to those close behind us on the curve. We are hoping to get the sort of feedback that will help us move closer to ‘awesomeness’ in software development. We also want to have a place to whinge about things we find annoying :-P.

Each of us is near the top of the chain in our organisation; we have broad and deep skills in many areas of the Java and Java EE space and have been around the block many times in both successful and failed projects; we’ve been shouted at, we’ve worked all night, gotten depressed and received accolades and glory. Also, a large part of our experience has been in banking – which has it’s own world of pain points but can also be a glorious industry to work in for a software developer.

Obviously you take the good with the bad – but how have we kept our heads above water (psychologically) during the bad times – it is because we are passionate about what we do and deep down we are still enjoying the cut and thrust of software development it even when the poo is hitting the fan.

We were discussing recently how much we enjoyed one night a few years ago where we were in the office all night and most of the next day (after a full days work too) because of the intensity of the situation that the business was in. Basically we received in one night far more volume than was expected and we had to ‘massage’ it through systems that were in their infancy and in no way ready to scale to the level of data we had to process. Regardless of how we got into this situation (obviously in an ideal world we might have planned better) we had to now manage it and were on the critical path of a successful or failed year end process (i.e. make or lose lotsa money). This meant that we had some very senior executive director level people in the business right down to the current season of graduate interns and us all working as a unit, in the zone, to get over the line. It was stressful, difficult and tiring but we felt a part of something; we were able to display skills and aptitudes in a very visible way and deliver results instantly, not just the results in managing overburdened systems but in joining business decisions using peripheral skills gained in building software for the business we were a part of. It was an environment of mutual trust and respect with everybody intensely focused on a positive outcome regardless of position or role in the business. This is awesomeness codified.

Anyway, back to the point – we want to become ‘awesome developers’. This doesn’t mean ‘they who know the most api calls in the java.lang package’ or ‘they who can make JBoss sing the national anthem – in a language of your choice (while washing the dishes)’*; it means we want to love what we are doing and to inspire others (in the space) to love what they are doing; it means we want to be able to deliver robust, reusable, reliable and ‘awesome’ solutions better and better every time; it means we accept that someone will always know more than us and that we will strive to meet those people that we might incorporate what they know into delivering better and better solutions; it means we want to be a part of and understand the businesses we work with and within, again so we can deliver better and better solutions; it means we want colleagues (it & business) to say ‘wow, they really care about what they do’.

So this is why we blog. We want the feedback; we want to attract developers who are already awesome – though they may not know it – to help us improve. However, to be brutally honest maybe we just want to be famous :).

* we can though, well – maybe not the dishes bit.

MS Word for Mac – Hate the Toolbox

Is it just me or is the toolbox in MS Word 2008 for Mac ridiculously small (read: horrid). I’m battling with a document with many styles at the moment and am finding myself scrolling up and down, up and down endlessly in a scroll window that displays 5 styles at a time. I’ve got RSI just thinking about it.

On a lighter note – I’m lovin’ the new Ribbon concept in the Windows version. Who ever designed that deserves a pat on the back (and a big bonus). It takes a little getting used to but is just great when your up the learning curve.

If there is some friendly competition between the Word for Mac and the Word for Windows UI teams then I think the Windows team well and truly wins this round.

Jon

PS: If anyone knows how to increase the size of the toolbox or dock it please tell me how. Please – I’m dying here.