CRL checking for inbound SSL connexions to IS

Hello, everyone, I’ve been searching in the documentation and also on this forum, but I can’t find a definite answer to my question.

What I’m wondering is, when an external client tries to connect to an IS through an HTTPS port configured to require client certificate authentication, does the IS make use of any CRL checking mechanism by default?

From what I’ve read in the webMethods doc, the only part where there is any mention of CRLs is in the part about the PKI adapter. I’m not sure how this is supposed to work nor what exactly it is supposed to do, but I would like to know if it is the only way to use CRL checking mechanisms for inbound SSL connexions to an IS before plunging deeper into this.

Thanks in advance to all who take time to give me any hint on this!

Thats correct, it’s only supported by package WmPKI and you need to setup PKI profiles.

For this you need third party software or hardware, thus is not common and you won’t find many answers.

This is quite well documented http://techcommunity.softwareag.com/ecosystem/documentation/webmethods/wmsuite8_ga/Integration_Server_and_Process_Engine/8-0-SP1_Administering_Integration_Server.pdf pages 281 ahead.

Page 300 explains the CRL stuff.

If you manage to set up the environment, would be nice if you post the results :smiley:

Additionally you can achive this by implementing your own auth module via JaaS. Check page 260. The bad side this needs extra coding and is hard!!

Good luck!

Thank you for your help!

I forgot to mention that we are using version 7.1.2 of Integration Server, sorry about that.

The JAAS chapter looks interesting, but I’m not sure if our version implements it.

I looked up the webMethods Integration Server Administrator’s Guide 7.1.1 and the webMethods Integration Server and webMethods Developer Documentation Supplement 7.1.2 and the chapter about JAAS doesn’t seem to be there. Neither is there any mention of PAMs (Pluggable Authentication Modules), which makes me think neither are supported.

Yet in the doc you pointed me to, the PAM mechanism is mentionned as a way of customizing authentication in previous versions of IS, being superseded by JAAS in version 8.0.

So I’m wondering if version 7.1.2 does support JAAS or at least PAM, version 8.0 being the next one up right after 7.1.2.

I believe advantage had some examples how to do CRL checking for some basic KPI, but that means you have to code something your selves, is not an out of the box solution.

If you come with a solution I would like to “read” :slight_smile:

I asked webMethods support if 7.1.2 implemented CRL checking, and they answered that PAMs are indeed a way of achieving this, but are not fully supported like the wmPKI solution.
They pointed me to some documentation, and I also got a sample package AuthCert which helped me understand more precisely how an Authentication Module works. I think I can see my way to the solution of this problem, but there are still some issues that I have trouble with.

Let me explain (it’s a bit long, sorry…):

I think I can manage the complete certificate verification, along with CRL checking and all, in the Authentication Module, and I think I can get it up and running instead of the standard authentication mechanism used by the IS.

The problem I have now is that once the certificate is correctly verified, I still need to map it to a user in the IS for the Module to return a UserID so the client can connect. The IS has a client certificate mapping feature, and I’d like to use that rather than redoing something similar myself, which would be redundant and a waste of time.
Trouble is, I can’t find how to get the information about certificate mappings in the IS from a java service.

I also thought of performing CRL checking on the certificate in the Module, and in case of success, let the IS take over the rest of the authentication. But apparently, a Module replaces completely the IS authentication process, and cannot be used to simply perform an additionnal check, so I gave up on this idea.

I looked up the wm.server.security.certificate.getDetailedInfo service, which takes an Issuer and a SerialNumber as inputs and returns the corresponding user, but I couldn’t get it to work. The Issuer input is somewhat ambiguous, and although I tried several inputs, none yielded any results. All I get is an Exception with this message “No map entry exists for the specified information”. I checked and there is an entry with that issuer and that serialnumber, but lacking documentation on this service, I don’t know exactly what is expected for the Issuer input field.

Then I also happened to find a post on this forum mentionning a pdf entitled “Buidling Custom Authentication Modules”, which seems to contain valuable information about what I’m trying to do, but I couldn"t find it on Advantage or Empower or softwareAG documentation website. If anyone knows where to look, or even better, can give me a direct link to the document, I would be very grateful.

I think once I can map the certificate to its corresponding user, I will be able to complete my Authentication Module and test it, so any information on how to do this is welcome.

Thanks again.

EDIT: Well, right after I posted this, I tried something else for the “Issuer” input field, and it worked!! :smiley:
What I did was I ran a Java program from Eclipse which printed to the console the result of the getIssuerDN() method from the X509Certificate class, and I copy-pasted it as the input value for “Issuer”, and it got me the user mapped to that certificate! Good to know, for future reference. Now I’m on to code and test the Module!
I’ll let you know how it turns out.

I’m still interested if anyone can point me to the “Buidling Custom Authentication Modules” doc, as it is bound to have some enlightening info in it (or so I believe).

Nice update, thanks. Yes the downside for this approach is you have to build all the auth module. If you succeed with those services it will be a solution.

Some news:

I’ve completed my Authentication Module, I tested the authentication logic in itself, and it works as expected. When presented with a valid certificate, it returns the corresponding user, when the certificate does not validate or is not mapped to any user, it returns null.

I’ve also deployed the package on the IS, complete with startup and shutdown services. The startup service creates a log file on the file system, I checked and the log file is there with some lines in it, showing that the Module is active.

I’ve also put the associated properties file in the config directory of the package, with all the data needed for the module to run.

And yet, when I try to connect to the IS through an HTTPS port which requires client certificates, it looks like the Module is never called.
The IS presents its certificate, I accept it, then Firefox asks me which certificate I want to authenticate with, I choose one, and if it’s a good one, I’m authenticated as usual, and if it’s not a valid one, I’m rejected as usual.
But when I look in the log file, there isn’t any line mentionning the failed attempt or the successful login, which makes me think that the Module never came into play, and all that took place was just the standard webMethods authentication process.

So now I’m wondering how to make my module override the standard IS authentication mechanism, or at least make my module the first mechanism to be used, falling back on the standard one, rather than the other way around.

The package has the following structure:
[PACKAGE_NAME] (package)
+[PACKAGE_NAME] (folder)
++AuthModuleFactory (folder)
+++AuthModuleFactory (empty java service)
++AuthModule (folder)
+++startup (java service)
+++shutdown (java service)

Here’s the code, may be there’s something wrong in it?
(I took away the names of some packages because they contained the name of the project, and it’s top secret!:p:)

The ModuleFactory: (this code is in the Source section under the Shared tab of the AuthModuleFactory folder)

protected Module instance;

public AuthModuleFactory(){
        instance = new AuthModule();
}

public Module getInstance() {
        return instance;
}

The Module:(this code is in the Source section under the Shared tab of the AuthModule folder)

/** Log stream, initialized during call to startup service */
public static LogOutputStream authlog = null;

/** set to TRUE to enable more logging */
public static boolean DEBUG = true;

/** CRL directory */
private static String crlDir;

/** Intermediate CAs directory */
private static String intermediateCADir;

/** Trusted certificates directory */
private static String trustedCertsDir;

/** maxPathLength parameter */
private static String maxPathLength;

/** Write a message to the module log
* @param s message to log
*/
public static void log(String s) {
    if (authlog != null) {
        authlog.write(s);
    }
}

/** Write a message to the module log if DEBUG flag is true
* @param s message to log
*/
public static void debug(String s) {
    if (DEBUG) log(s);
}

/** Check a X.509 certificate and map it to an Integration Server userid
* @return Integration Server userid.
*/
public String processToken(Token token) {

    log("Authentication request");

    if (token == null) return null;
        String id = null;
        try {
            X509Token xt = (X509Token) token;
            X509Certificate[] chain = xt.getCertificateChain();
            X509Certificate clientCert = chain[0];

            Session session = Service.getSession();

            IDataFactory factory = new IDataFactory();

            IData pipelineIn = factory.create();

            IDataCursor cursorIn = pipelineIn.getCursor();

            IDataUtil.put(cursorIn,"certificate",clientCert.getEncoded());
            IDataUtil.put(cursorIn,"authoritiesDirectory",intermediateCADir);
            IDataUtil.put(cursorIn,"trustSource",trustedCertsDir);
            IDataUtil.put(cursorIn,"CRLsDirectory",crlDir);
            IDataUtil.put(cursorIn,"maxPathLength",maxPathLength);

            IData pipelineOut = Service.doInvoke(NSName.create("XXXXXXXXX.XXXXX:validateCertificate"),session,pipelineIn);
//this service is a standalone Java service which is used to validate a 
//certificate against a list of CAs and trusted authorities, with CRL checking

            cursorIn.destroy();

            IDataCursor cursorOut = pipelineOut.getCursor();
            cursorOut.first("validity");

            boolean valid = IDataUtil.getBoolean(cursorOut);

            String error = null;

            if (cursorOut.next("error")) {

                error = IDataUtil.getString(cursorOut);
                if (error!=null){
                    log("ERROR:"+error);
                }

            }

            cursorOut.destroy();

            if (valid) {

                IData pipelineIn_1 = factory.create();

                IDataCursor cursorIn_1 = pipelineIn_1.getCursor();

                IDataUtil.put(cursorIn_1,"issuer",clientCert.getIssuerDN().toString());
                IDataUtil.put(cursorIn_1,"serialNum",clientCert.getSerialNumber().toString());

                IData pipelineOut_1 = Service.doInvoke(NSName.create("wm.server.security.certificate:getDetailedInfo"),session,pipelineIn_1);

                cursorIn_1.destroy();

                IDataCursor cursorOut_1 = pipelineOut_1.getCursor();
                cursorOut_1.first("user");

                id = IDataUtil.getString(cursorOut_1);

                cursorOut_1.destroy();

            }

        } catch (ClassCastException cce) {
            log("class cast exception: " + cce); // Should never get this!
        } catch (Exception e){
            log(""+e);
        }
        if (id!=null){
            log("User "+id+" successfully logged in");
        }else{
            log("Authentication failed");
        }

        return id;

}

The startup service:

// Setup a log file for the module
authlog = ServerAPI.getLogStream("AuthModule.log");

log("Authentication Module initializing");

// Load package configuration file.
File authconfig;
try {
    authconfig = new File(Server.getResources().
    getPackageConfigDir("XXXXXXXX"), "AuthModule.properties");
} catch (NullPointerException npe) {
    throw new ServiceException("Could not get resources for Package XXXXXXX");
}

Properties authprop = new Properties();
try {
    FileInputStream fis;
    if (authconfig.exists()) {
        fis = new FileInputStream(authconfig);
    }else{
        throw new ServiceException("Could not locate AuthModule config file");
    }
    authprop.load(fis);
    fis.close();
}catch (IOException e){
    throw new ServiceException("Could not load AuthModule.properties file: " + e);
}

String dbg = authprop.getProperty("debug", "false");
DEBUG = dbg.equals("true");

crlDir = authprop.getProperty("crlDirectory");

intermediateCADir = authprop.getProperty("intermediateCAcerts");

trustedCertsDir = authprop.getProperty("trustedAuthorities");

maxPathLength = authprop.getProperty("maxPathLength");

AuthenticationManager.registerMechanism(AuthModuleFactory.getMechanismName(),new AuthModuleFactory());

log("Authentication Module started");

The shutdown service:

log("Authentication Module shutting down");

AuthenticationManager.unregisterMechanism(AuthModuleFactory.getMechanismName());

log("Authentication Module disabled");

As I told you before you begun, using WmPKI and paying 3rd party software was the “quicker” way.

The problem with what you are doing (and I would do the same in case CRL is a requirement for me!), is that you have to maintain the module in future upgrades, once you get it to run.

Thanks for posting your progress! I might copy you :smiley:

Some further news…

I have had little time to investigate the subject during recent weeks, but something occured which allowed me to make some progress.

Apparently, when the HTTPS port on the IS is called via pub.client.http by another IS the module does come into play and perform its task, whereas when the call is done through Firefox (didn’t try with another browser), the module is ignored. No idea why is that, and I would be really glad if someone could explain it to me.

Then I have a new problem : as a result of the module being called, I’ve been able to detect an ACL problem when trying to use Service.doInvoke with the wm.server.security.certificate:getDetailedInfo from inside the module. I get an AccessDenied exception. I looked up the ACLs for this service and here is how it is configured:

List ACL (inherited)
Read ACL
(inherited)
Write ACL
(inherited)
Execute ACL (inherited)
Enforce ACL on Internal Invokes
Off

I tried setting the User as “Administrator” for the Session within the module, but still got the same exception. So now I have two remaining questions:

why is the module ignored when calling IS from a web browser (at least from Firefox)?

why can’t I access the wm.server.security.getDetailedInfo service from my module?

Any help on these topics is welcome!