Tuesday, August 21, 2018

Articles You Should Read

Here are my current favorites articles, in no particular order. I've shared them all at work and now I'm sharing them with you.

The Guard: I've read this article at least nine times now. I identify most with being the Old Guard, which makes me cringe helplessly every time I read it. It is thoughtfully written and makes some excellent points about how a team starts to trust themselves. Key excerpt:
  • The Old Guard: "I feel empowered to fix everything."
  • The New Guard: "I don’t know how to fix anything."
Teaching Iteration: High schools around the world need to start teaching this topic now and it should be a mandatory course. The cool thing is that the core concept can be applied to just about any subject. Let the students pick the thing they have an interest in and teach them skills for "how to make it better". 

Don't Get Blocked: This may be the closest thing I have to a personal mantra. The anti-pattern is people who like putting up roadblocks. Those people should get (symbolically) run over.

Thursday, December 15, 2016

Sprint Review Best Practices

The sprint review is a critical checkpoint in agile development. It is the opportunity for the stakeholder to see your solution to their problems. Their feedback during the presentation leads to future work being defined and provides a common understand of thier pain points to the development team.

From personal observation, I noticed a few things that detract from the effectiveness of a sprint review. Particularity, new team members don't know what to expect, so I think having a short set of guidelines helps set expectations.

The best case scenario is that you are sitting in the same room with your client. However, some of the points below consider the challenges of a remote team conducting a sprint reviews via telecon and screen-sharing.


  • Have a compelling narrative with demonstrable stories flowing into each other
    • Use a common scenario or theme as much as possible
  • Role-play as a specific stakeholder role, demonstrating new functionality within context of their daily tempo
    • Use their team names, role titles and domain language to inspire confidence that you know their processes and how the implemented stories help them
    • Shun words and phrases like "lorem ipsum" and "foo/bar" as they show you don't understand the problem or care enough to use stakeholder specific terms
  • Focus on new functionality, unless a review of previous functionality helps understand the context
    • Minimize UI components that don't contribute to demonstrating the new story
    • Maximize the UI so that background elements don't detract from the story focus
  • Know the audience and understand if they have previously seen the functional area you are talking about. There could be new people listening in or specially invited VIPs.
    • Give reminders of what acronyms stand for before using them
  • Know your project and its capabilities so that you can react to customer confusion and answer questions during the live demonstration
  • Allow "space" during the presentation for feedback. Remember, a good sprint review is not a monologue, it is a conversation.

  • The stakeholder always has precedence during conversations; don't over-talk them. Keep side conversations at a low volume so everyone can hear stakeholder feedback.
  • Mute your telecon microphone if you are not actively involved in a conversation. What seems like low background noise to you can come through loud and clear over the telcon.
  • Turn off cell phone ringers
  • Presenter should close all applications, such as email, IM and team chat apps, that could display popup notifications during the presentation

I hope these points help you during your next sprint review.

And if you think these are all common sense, stay tuned for my next blog post!

Wednesday, November 16, 2016

Agile Story Done Criteria Template

As an agile development team lead, I assisted our solution owner by explaining the intent and direction of our backlog stories to the team.  Normally this happened during a weekly team "backlog grooming" session. The purpose of the session was to fully understand the story, scope out the done criteria to match a fairly solid implementation plan and to estimate a story WAG. 

I found that the extra planning and team discussion before the story was accepted at backlog selection a valuable time investment. To help focus the grooming session discussion, I created a standard template for the story Done Criteria section. The concept of the template is to encourage team participation, scope the full expectations of the story, and document important discussions and ideas that will prevent confusion during the implementing sprint.

I'll present my template below and then follow that with a more detailed explanation for each section of the done criteria.

Story Done Criteria Template:

User Acceptance:

  1. User can save a new map scene composed of a map background layer, a lat/lon center point and a zoom level.
  2. User can only delete a map scene if the user was the creator.
  3. ...

Team Definition of Done (derived requirements, quality, standards):

  1. Approved by UI team
  2. Must create a supporting release notes task documenting manual installation steps
  3. Remove unused database entries for "system.map.*" properties.
  4. ...


  1. Users cannot rename map scenes. This is covered by a future backlog story.

Discussion Answers:

  1. TBD

Template Explanation:

User Acceptance:
User-facing requirements that must be complete for the solution owner to accept the story. Typically thought of as hard requirements that would necessitate direct negotiation with the solution owner (or users) if an problem were discovered during implementation or testing.

Team Definition of Done:
Derived requirements that influence the team's implementation.  These could represent functionality that a user would notice, but that does not impact the user's intent of the story.  This category also encompasses criteria that the implementation team values for internal quality, consistency or project standards reasons. Items in the section can be contributed by anyone on the team: developers, designers or quality control, for example.

Note that these specific criteria typically represent areas of high risk and otherwise important tasks that have not yet become a normal habit of a high performing team. For example, we don't call out typical story tasks such as unit testing, peer reviews or required documentation updates.

This important category complements the positive criteria of the story by documenting good ideas for future backlog stories. Having this section seemed to encourage team members to contribute ideas on stories while allowing a place to record the ideas without bloating the scope of the story being discussed.

The other important reason for this section is that by being explicit here, we can avoid mid-story confusion when someone asks: What is the expected functionality when the user does X? Did we forget to consider this functionality or did we talk about it and arrive at a decision that it was not covered by this story?

Discussion Answers:
This section is for use AFTER the story has been accepted by the team and is under development. If any mid-sprint issues are discovered where the expectations are not clearly covered by user criteria, the team will work out a plan with the solution owner AND record the decision here. All such answers should be recorded here as the source of the requirements. This avoids having important story criteria being discussed in email threads, or on the phone, but not transcribed here for full team visibility.

Typically, these answers will be translated into criteria for user story acceptance tests (USAT) and become part of the official application specification.

Miscellaneous Helpful Ideas:
  • The criteria should use numbered bullets for quick, unambiguous verbal reference during the team grooming session.
  • Out-of-Scope items should have a POC assigned so that the ideas get translated into new stories or suggested to the users during the sprint review presentation.

Wednesday, April 27, 2016

Workplace Strife Advice

This post is a second chance.  A respected coworker asked me for advice on a heated personal office conflict, and while I think I gave a good answer, he was unconvinced.  In hindsight, I did not do a good job explaining some good reasons for the answer I gave, which summarized, would be:
Take the easy out and move on as quickly as possible.
While I suspect there is professional pride involved in the disagreement, it is in the interest of everyone in the office to get over it and put it all in the rear view mirror so that work can progress.

My second chance advice on the nature of the conflict derives from what I know about my coworkers:

  • They are both experienced team leads
  • Both teams work on the same software project; developers and quality control
  • They work in geographically separated offices 
  • Neither has met the other in person
  • They do work together on a daily basis via team chat, emails and morning scrum

I have an long drive home from work, so I naturally started to reflect on that conversation and the difficult situation that my friends were in.  I came up with the following points that may help someone else who is experiencing a difficult personal interaction that is seemingly at an impasse.
The very best solution, of course, would be for both people to meet (or call because of being on a distributed team) and work through the differences so they can continue together as a high functioning team.
But short of that, I believe all of the points below are helpful.  They are not meant to be used all at once as a big fire-hose solution to extinguish a workplace fire.  Rather, I'm hoping one or more of these register as a well made point that makes sense and helps someone through a similar conflict.

I also hope these points are not taken as being callous, as any one of them would resonate with me if I was in the same situation (seemingly stuck without chance of agreement nor common ground reached), and someone offered me an outside view of my situation.

  1. Your future self does not care about this argument as much as you do. Look back on this situation in 10 years and realize that it simply was not that important.
  2. As a team lead, you need to consider that time spent extending a conflict is time taken away from your leadership responsibilities owed to your junior team members
  3. Being wrong can be a drastic side effect of choosing your Perfection over their Very Good.
  4. The thing you are arguing over may be of-value, but the argument itself is valueless. You were hired for your life experiences and professional skill set, neither of which are being put to use to solve the problems you should be working on. You expect to be paid for excessive time spent arguing?
  5. So, you've been challenged to a High Noon showdown and you're asking for advice on which ammunition to use instead of how to avoid a public gunfight?
  6. If you're mutually blocking each others progress, does it matter who gets credit for standing their ground the longest? There is no absolute right or wrong in matters of opinion.
  7. Don't get blocked! It IS within your power to move forward. 
  8. Is your professional ego more important than your human interactions? What is the point of being "right" if you are causing, or prolonging, a painful situation when both of you are literally losing sleep over it? Conflict is natural, but suffering is not.

What advice would you give a coworker in a heated, ongoing situation?

Wednesday, November 13, 2013

Always, Never and Context

It sure would be nice to work for a client that knew exactly what they wanted and why they wanted it. Then again, if that were the case, I probably wouldn't have a job because well defined problems are easier to solve and don't pay as much.

The more challenging case is when I'm helping them by delivering an iterative solution that works for them in two important ways: 1) It alleviates pain and 2) It actually clarifies the domain problem. It is the software equivalent of a picture is worth a thousand words. Since we deliver software every 30 days, the relative cost is low enough to have confidence to take a step in generally right direction instead of standing still waiting for a concrete requirement to materialize.

A logical consequence of being in this situation is that when architecting the system to support the "known knowns", there is simply not enough information to declare "Always" or "Never". The reason being that the problem itself or a solution to the problem is not yet fully understood. It is the context that is missing. This is actually OK because an implementation can evolve as does the business case. One example of this could be that users are "misusing" your application in unanticipated ways, leading to an an opportunity to "pave the bare spots".

During each iteration of the solution, there should be enough of a cost/benefit analysis to help arrive at an appropriate implementation. Part of this analysis could take into account concepts like "simple as possible, but no simpler" and Behavior-Driven Development to define the progression.  I can say with more confidence, however, that the one input that must always be present is domain Context.

Which leads me to a more concrete example: "An N+1 query is never correct". This is certainly a well known performance antipattern. But the problem here is one of context. This statement has no insight into the domain problem it is part of solving. There is no business driver inputs that allow such a statement to be true in all cases.

Consider that your stakeholder has provided you with what they know to be currently true that lets you derive:
  • N maxes out at 2.
  • N, at an order of magnitude bigger than the largest known business case, executes < 1ms.
  • An AOP slice needs access to each N for required non-repudiation auditing.
  • A sql solution is not testable at a necessary confidence level that the DAO language can provide.
  • Only one developer on your team has expertise to write and maintain an optimized query.
  • As you build out a backlog of functionality, it is very likely that a near future refactor will negate time spent developing a more performant solution. 
Without such inputs setting the stage, you are flying blind in a way where absolutes tend to become negative attributes. Solve the problem given what you know, stay loose and don't be afraid to refactor when the context changes.

To borrow a phrase, Context is King.

Wednesday, January 2, 2013

The Marketplace Of Ideas Should Be Brutal

I think this wisdom applies to everything in life, beyond software development. You really don't know if your idea is superior until honest feedback is received and it is compared to competing ideas. I thought this was summarized nicely as:
"Ideas are meant to be attacked, torn apart, and put back together again. You may well want to shield your idea from the harsh sunlight at first, but by the time it’s ready to meet the world, it should also be ready for rain or shine. Bad ideas are supposed to wither under the stress of criticism."
-- Via David's post at 37Signals

Tuesday, November 9, 2010

Mutual PKI Authentication With a Java-based Application

I recently added certificate based authentication to an application I have been working on for awhile. It took longer to get done than I would have thought primarily because the number of moving pieces and most advice and guidance I found online was incomplete. I hope that documenting the complete setup I used will save someone else some time and frustration.

The requirements were:
  • Wiring together two Java applications via SOAP, using CXF framework
  • The producing application needed a valid server certificate
  • The consuming application needed to present a valid client certificate to the server
  • These certificates needed to be signed by a trusted root and share the same certificate authority
  • For authentication purposes, no custom code within the application itself
  • Use the Java keytool program to create keypairs and generate signing requests

The broad strokes:
  1. Create the necessary certificates
  2. Setup tomcat on the producing side to accept only https connections and require client authentication
  3. Setup the consuming application to present client certs that can satisfy the secure authentication handshake

Creating and signing the certificates

I have previously created a CA setup using strictly openssl, but for this project, I needed to lean more heavily on keytool to originate the keypairs and openssl to do the certificate signing. The keytool program comes with the JDK. I used a windows based openssl binaries from SLP.

Setup a directory structure as recommended by openssl installation and set an environment variable, %SSLDIR%, to point to your CA directory.

Create CA and RA
# Create the CA's keypair and self-signed certificate
# -x509 means create self-sign cert
# -keyout means generate keypair
# -nodes means do not encrypt private key.
# -set_serial sets the serial number of the certificate
openssl req -verbose -x509 -new -nodes -set_serial 1234 -subj "/CN=codebeneathCA/OU=project/O=company/ST=MO/C=US" -days 7300 -out %SSLDIR%/certs/cacert.pem -keyout %SSLDIR%/private/caprivkey.pem -config %SSLDIR%/openssl.config

# Create the Root Authority's keypair and Certificate Request
# without -x509, we generate an x509 cert request.
# -keyout means generate keypair
# -nodes means do not encrypt private key.
openssl req -verbose -new -nodes -subj "/CN=codebeneathRoot/OU=project/O=company/ST=MO/C=US" -days 7300 -out %SSLDIR%/certs/csrra.pem -keyout %SSLDIR%/private/raprivkey.pem -config %SSLDIR%/openssl.config

# Have the CN=codebeneathCA issue a certificate for the CN=codebeneathRoot
# We need -extfile exts -extenstions x509_extensions to make sure
# CN=TheRA can be a Certificate Authority.
openssl ca -batch -days 7300 -cert %SSLDIR%/certs/cacert.pem -keyfile %SSLDIR%/private/caprivkey.pem -in %SSLDIR%/certs/csrra.pem -out %SSLDIR%/certs/ra-ca-cert.pem -extfile exts -extensions x509_extensions -config %SSLDIR%/openssl.config

Create Server Cert

# Create keypairs and Cert Request for a certificate for server
# This procedure must be done in JKS, because we need to use a JKS keystore.
# The current version of CXF using PCKS12 will not work for a number of
# internal CXF reasons.
keytool -genkey -alias codebeneath-server -dname "CN=,OU=codebeneath-server,O=company,ST=MO,C=US" -keystore C:/certs/server-keystore.jks -storetype jks -storepass password -keypass password -validity 365
keytool -certreq -alias codebeneath-server -keystore C:/certs/server-keystore.jks -storetype jks -storepass password -keypass password -file codebeneath-server-csr.pem

# Have the CN=codebeneathRoot issue a certificate for server via the Certificate Requests.
openssl ca -batch -days 7300 -cert %SSLDIR%/certs/ra-ca-cert.pem -keyfile %SSLDIR%/private/raprivkey.pem -in %SSLDIR%/requests/codebeneath-server-csr.pem -out %SSLDIR%/requests/codebeneath-server-ra.pem -config %SSLDIR%/openssl.config

# Rewrite the certificates in PEM only format. This allows us to concatenate them into chains.
openssl x509 -in %SSLDIR%/certs/cacert.pem -out %SSLDIR%/certs/cacert.pem -outform PEM
openssl x509 -in %SSLDIR%/certs/ra-ca-cert.pem -out %SSLDIR%/certs/ra-ca-cert.pem -outform PEM
openssl x509 -in %SSLDIR%/requests/codebeneath-server-ra.pem -out %SSLDIR%/requests/codebeneath-server-ra.pem -outform PEM

# Create a chain readable by CertificateFactory.getCertificates.
type %SSLDIR%\requests\codebeneath-server-ra.pem %SSLDIR%\certs\ra-ca-cert.pem %SSLDIR%\certs\cacert.pem > %SSLDIR%\requests\codebeneath-server.chain

# Replace the certificate in the server keystore with their respective full chains.
keytool -import -file codebeneath-server.chain -alias codebeneath-server -keystore C:/certs/server-keystore.jks -storetype jks -storepass password -keypass password -noprompt

# Create the server Truststore file containing the CA cert.
keytool -import -file cacert.pem -alias codebeneathCA -keystore C:/certs/server-truststore.jks -storepass password -noprompt

Create Client Cert

# Create keypairs and Cert Request for a certificate for client (codebeneath)
# This procedure must be done in JKS, because we need to use a JKS keystore.
# The current version of CXF using PCKS12 will not work for a number of
# internal CXF reasons.
keytool -genkey -alias codebeneath -dname "CN=,OU=codebeneath-client,O=company,ST=MO,C=US" -keystore C:/certs/client-keystore.jks -storetype jks -storepass password -keypass password -validity 365
keytool -certreq -alias codebeneath -keystore C:/certs/client-keystore.jks -storetype jks -storepass password -keypass password -file codebeneath-csr.pem

# Have the CN=codebeneathRoot issue a certificate for client via the Certificate Requests.
openssl ca -batch -days 7300 -cert %SSLDIR%/certs/ra-ca-cert.pem -keyfile %SSLDIR%/private/raprivkey.pem -in %SSLDIR%/requests/codebeneath-csr.pem -out %SSLDIR%/requests/codebeneath-ra.pem -config %SSLDIR%/openssl.config

# Rewrite the certificates in PEM only format. This allows us to concatenate them into chains.
openssl x509 -in %SSLDIR%/requests/codebeneath-ra.pem -out %SSLDIR%/requests/codebeneath-ra.pem -outform PEM

# Create a chain readable by CertificateFactory.getCertificates.
type %SSLDIR%\requests\codebeneath-ra.pem %SSLDIR%\certs\ra-ca-cert.pem %SSLDIR%\certs\cacert.pem > %SSLDIR%\requests\codebeneath.chain

# Replace the certificate in the client keystore with their respective full chains.
keytool -import -file codebeneath.chain -alias codebeneath -keystore C:/certs/client-keystore.jks -storetype jks -storepass password -keypass password -noprompt

# Create the client Truststore file containing the CA cert and server cert.
keytool -import -file cacert.pem -alias codebeneathCA -keystore C:/certs/client-truststore.jks -storepass password -noprompt
keytool -import -file codebeneath-server-ra.pem -alias codebeneath-server -keystore C:/certs/client-truststore.jks -storepass password -noprompt

Create trust for the server to know the client

# Import the client cert into the server Truststore.
keytool -import -file codebeneath-ra.pem -alias codebeneath -keystore C:/certs/client-truststore.jks -storepass password -noprompt

Export client cert from keystore for browser import

The keytool program cannot export private keys in any format, so use portecle to do these steps so that we can verify the setup using a browser without involving the actual client application.
  1. Start portecle: java -jar ./portecle.jar
  2. File... Open keystore file... select the ./client-keystore.jks file. Type the password.
  3. Right-client the "codebeneath" certificate name. Select Export...
  4. Export Type: Private Key and Certificates. Export Format: PKCS #12. Click OK. Type the password.
  5. For the PKCS #12 password, it must be non-blank value or else the browser will not import it correctly.
  6. In the browser, import the certificate as a "Personal" certificate.
  7. In the browser, import the CA certificate as a trusted authoritative certificate.

Double check the results so far...

On the server machine:

keytool -list -keystore ./server-keystore.jks
  • one signed certificate chain, PrivateKeyEntry, alias="codebeneath-server"
keytool -list -keystore ./server-truststore.jks
  • CA certificate, trustedCertEntry, alias="codebeneathca",
  • client certificate,trustedCertEntry, alias="codebeneath"

On the client machine:

keytool -list -keystore ./client-keystore.jks
  • one signed certificate chain, PrivateKeyEntry, alias="codebeneath"
keytool -list -keystore ./client-truststore.jks
  • CA certificate, trustedCertEntry, alias="codebeneathca",
  • server certificate, trustedCertEntry, alias="codebeneath-server"

Server setup using tomcat

To accomplish the required mutual authentication (server is trusted https:// and client presents a valid certificate) requires setup within tomcat and the server war web.xml file. There is no code involved, it is strictly the setup of the servlet container to handle the security handshaking.

Tomcat server.xml file

Note that the clientAuth attribute must be "true" for things to work properly, even though the specification says that each war may individually be setup to require/not require client auth.
<Connector port=\"8443\" protocol=\"HTTP/1.1\" SSLEnabled=\"true\"
maxThreads=\"150\" scheme=\"https\" secure=\"true\"
clientAuth=\"true\" sslProtocol=\"TLS\"

Tomcat tomcat-users.xml file

Each username must match a client certificate subject line. Use portecle to open the client cert and cut-and-paste the "Subject:" line to this file's username value. So, even though the client certificate is valid given the truststore requirements, each client must also be specifically listed in this file to have access to the server application.
<role rolename=\"codebeneathRole\">
<user username=\"CN=, OU=project, O=company, ST=MO, C=US\" password=\"password\" roles=\"codebeneathRole\">

Server war web.xml file

Both "role-name" elements must match the tomcat-users.xml defined rolename. The "auth-method" value of "CLIENT-CERT" will require a client certificate for authentication. The "transport-guarentee" value of "CONFIDENTIAL" will redirect all requests

Debug SSL

In the event that the mutual authentication fails, we can enable specific debugging on the server side. In the catalina.bat file, add the switch -Djavax.net.debug=ssl,handshake

Client Setup

Since the project used SOAP WS-*, including WS-Security, on the client side we used the CXF project to handle the wsdl-to-java code generation and to create the client port. My project uses CXF version 2.2.11, with the additional "cxf-rt-ws-security" dependency jar.

Client java code
package com.codebeneath;

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
//import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.ws.security.handler.WSHandlerConstants;

import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.xml.ws.BindingProvider;

* Client a SOAP WS client for the service. Handles logging support, WS-Security and PKI certificates
public final class Client {

private static final String DEFAULT_PASSWORD = "password";
private static final String KEYSTORE_FILENAME = "/client-keystore.jks";
private static final String TRUSTSTORE_FILENAME = "/client-truststore.jks";

private Client() {

* Create a new WS client
* @param serviceUrl, the service URL endpoint
* @param sigPropFile, the properties file for client PKI. Must be on the classpath at runtime
* @return client port
public static TroubleTicketServiceSoap createClient(URL serviceUrl, String sigPropFile, String keystoreDir) {

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();

// request and response traces in the server.log

// SOAP WS-Security header
addSecurityHeaders(factory, sigPropFile);

// create the client
TroubleTicketServiceSoap port = (TroubleTicketServiceSoap) factory.create();
((BindingProvider) port).getRequestContext().put("schema-validation-enabled", Boolean.TRUE.toString());

// handle trust of server certificates
addCertificateHandling(port, serviceUrl, keystoreDir);

return port;

private static void addLogging(JaxWsProxyFactoryBean factory) {
factory.getOutInterceptors().add(new LoggingOutInterceptor()); // SOAP Request
// factory.getInInterceptors().add(new LoggingInInterceptor()); // SOAP Response

private static void addSecurityHeaders(JaxWsProxyFactoryBean factory, String sigPropFile) {

// setup the properties for WS-Security. This is PKI signed. The SIG_PROP_FILE must be on the classpath
Map wss4jOutProps = new HashMap();
wss4jOutProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.SIGNATURE);
wss4jOutProps.put(WSHandlerConstants.USER, "client");
wss4jOutProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordCallback.class.getName());
wss4jOutProps.put(WSHandlerConstants.SIG_PROP_FILE, sigPropFile);
wss4jOutProps.put(WSHandlerConstants.SIG_KEY_ID, "DirectReference");

// add required security interceptors
factory.getOutInterceptors().add(new SAAJOutInterceptor());
factory.getOutInterceptors().add(new WSS4JOutInterceptor(wss4jOutProps));

private static void addCertificateHandling(TroubleTicketServiceSoap port, URL serviceUrl, String keystoreDir) {
Client proxy = ClientProxy.getClient(port);
HTTPConduit conduit = (HTTPConduit) proxy.getConduit();
TLSClientParameters tcp = new TLSClientParameters();

try {
KeyStore trustStore = KeyStore.getInstance("JKS");
KeyStore keyStore = KeyStore.getInstance("JKS");

// accept all self-signed server certs
// tcp.setTrustManagers(CertificateAcceptorCXF.acceptAllCerts());

File truststoreFile = new File(keystoreDir + TRUSTSTORE_FILENAME);
trustStore.load(new FileInputStream(truststoreFile), DEFAULT_PASSWORD.toCharArray());
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
TrustManager[] tm = trustFactory.getTrustManagers();

// enable client certs for authentication
File keystoreFile = new File(keystoreDir + KEYSTORE_FILENAME);
keyStore.load(new FileInputStream(keystoreFile), DEFAULT_PASSWORD.toCharArray());
KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyFactory.init(keyStore, DEFAULT_PASSWORD.toCharArray());
KeyManager[] km = keyFactory.getKeyManagers();

} catch (KeyStoreException kse) {
System.out.println("Security configuration failed with the following: " + kse.getCause());
} catch (NoSuchAlgorithmException nsa) {
System.out.println("Security configuration failed with the following: " + nsa.getCause());
} catch (FileNotFoundException fnfe) {
System.out.println("Security configuration failed with the following: " + fnfe.getCause());
} catch (UnrecoverableKeyException uke) {
System.out.println("Security configuration failed with the following: " + uke.getCause());
} catch (CertificateException ce) {
System.out.println("Security configuration failed with the following: " + ce.getCause());
} catch (GeneralSecurityException gse) {
System.out.println("Security configuration failed with the following: " + gse.getCause());
} catch (IOException ioe) {
System.out.println("Security configuration failed with the following: " + ioe.getCause());

if (serviceUrl.getProtocol().trim().equalsIgnoreCase("https")) {
LOG.info("GSTv3 Web Service protocol is 'https' so " + "set the TLSClientParameters on the "
+ "HTTPConduit. This should cause the" + " request to accept all certificates "
+ "and disable the CN Check.");
} else {
LOG.info("GSTv3 Web Service url did was not 'https' so did NOT " + "set the TLSClientParameters "
+ "on the HTTPConduit.");

Client client-sign.properties

# Do not change these two properties
# Set your keystore location and password here!


I hope that this complete picture of mutual PKI certificate authentication helps. If anything is not clear, let me know and I will try to clarify.