Sunday 10 February 2013

Securing SOA 11g Environment:Part 2

This post continuation of my previous one http://shrikworld.blogspot.in/2011/07/securing-soa-11g-environment.html entry.So I’ve SSL enabled admin and managed server and I want to start all managed server from node manager, that requires some tweak in nodemanager.properties file. Below is the sample one,

#Fri Feb 08 20:18:43 IST 2013
#Sun Oct 28 16:39:51 IST 2012
DomainsFile=C\:\\shrik\\SOA11116\\WLSERV~1.3\\common\\NODEMA~1\\nodemanager.domains
LogLimit=0
PropertiesVersion=10.3
DomainsDirRemoteSharingEnabled=false
javaHome=C\:\\PROGRA~1\\Java\\JROCKI~1.0
AuthenticationEnabled=true
NodeManagerHome=C\:\\shrik\\SOA11116\\WLSERV~1.3\\common\\NODEMA~1
JavaHome=C\:\\PROGRA~1\\Java\\JROCKI~1.0\\jre
LogLevel=INFO
DomainsFileEnabled=true
StartScriptName=startWebLogic.cmd
ListenAddress=
NativeVersionEnabled=true
ListenPort=5556
LogToStderr=true
SecureListener=true
LogCount=1
DomainRegistrationEnabled=true
StopScriptEnabled=false
QuitEnabled=true
LogAppend=true
StateCheckInterval=500
CrashRecoveryEnabled=false
StartScriptEnabled=true
LogFile=C\:\\shrik\\SOA11116\\WLSERV~1.3\\common\\NODEMA~1\\nodemanager.log
LogFormatter=weblogic.nodemanager.server.LogFormatter
ListenBacklog=50
KeyStores=CustomIdentityAndCustomTrust
CustomIdentityAlias=shrikistore
CustomIdentityKeyStoreFileName=C:\\shrik\\SOAWork\\WeblogicCerts\\shrikIS.jks
CustomIdentityKeyStorePassPhrase=<Enter keysrote password>
CustomIdentityKeyStoreType=JKS
CustomIdentityPrivateKeyPassPhrase=<Enter private key password>

At runtime node manager will encrypt the hard coded pass phrase.Check the node manager status from weblogic console , it should be running fine and reachable.

In last post we disabled host name verification in SSL configuration of weblogic which is not advisable for production box.Ideally the certificate issued to weblogic server should match the host name where it’s running. For simplicity check out my cert configuration for SSL enablement of Admin and managed server.

image

Though leaf cert’s CN Shreekanta does not match  hostname localhost , it will fail definitely at Host name checker if I try to  open Admin console from browser which acts as a client.So in my custom hostname verifier code I’ve to add my cert’s CN validation and allow access. For that you have to select custom hostname verifier like below and you need to key in the class name start from your custom package,

image

My code is like below [copied from Oracle site] where I allowed My CN’S request,

package com.shrik.weblogic;

import java.io.ByteArrayInputStream;

import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.net.ssl.SSLSession;

public class TestHostnameVerifier implements weblogic.security.SSL.HostnameVerifier {

    private final static Logger log = Logger.getLogger(TestHostnameVerifier.class.getCanonicalName());

    @Override
    public boolean verify(String hostname, SSLSession session) {


        try {
            Certificate cert = session.getPeerCertificates()[0];

            byte[] encoded = cert.getEncoded();

            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            ByteArrayInputStream bais = new ByteArrayInputStream(encoded);

            X509Certificate xcert = (X509Certificate)cf.generateCertificate(bais);

            String cn = getCanonicalName(xcert.getSubjectDN().getName());

            log.info("CN: '" + cn + "'" + " HOSTNAME: '" + hostname + "'");


            // If CN is equals to Hostname then it is approved
           //added my cert
           if (cn.equals(hostname)||(cn.equals("Shreekanta"))) {
                return true;
            }

            // Compile regular expression
            // here we set the wildcard and the rest of the URL inside, could be more generic too.
            // String patternStr = cn;//  "[-.*aA-zZ0-9]+\\.qa.go2broadband\\.com";
            cn = cn.replace(".", "\\.");
            cn = cn.replace("-", "\\-");
            cn = cn.replace("*", "[-.*aA-zZ0-9]+");

            Pattern pattern = Pattern.compile(cn);

            // Determine if there is an exact match
            CharSequence inputStr = hostname;
            Matcher matcher = pattern.matcher(inputStr);
            boolean matchFound = matcher.matches();

            if (matchFound == false) {
                log.info("pattern doesn't match hostname");
            }

            //return boolean value
            return matchFound;

        } catch (Exception e) {
            e.printStackTrace();
        }

        return true;
    }

    /**
     * Returns just the canonical name from the distinguishedName on the cert.
     *
     *
     */
    private String getCanonicalName(String subjectDN) {

        Pattern pattern = Pattern.compile("CN=([-.*aA-zZ0-9]*)");
        Matcher matcher = pattern.matcher(subjectDN);

        if (matcher.find()) {
            return matcher.group(1);
        }

        log.info("Couldn't find match for CN in subject");
        return subjectDN;

    }

}


Do jar it and place it at <Domain_Home>/lib directory and <WL_HOME>/server/lib directory. At setDomainEnv.sh file add the following entry,

set CLASSPATH=%WL_HOME%\server\lib\HostNameVerifier.jar;%CLASSPATH%

Check out the order, for my case if I add custom jar file at end of classpath it always give me error and add the below entry ar server startup to debug.

set JAVA_OPTIONS=%JAVA_OPTIONS% -Djavax.net.debug=all -Dssl.debug=true -Dweblogic.StdoutDebugEnabled=true

That’s all , bounce the serer and verify the same from any browser accessing https URL of server.