svn commit: r527718 - in /ofbiz/trunk/framework: base/config/ base/src/base/org/ofbiz/base/util/ webapp/dtd/ webapp/src/org/ofbiz/webapp/control/

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r527718 - in /ofbiz/trunk/framework: base/config/ base/src/base/org/ofbiz/base/util/ webapp/dtd/ webapp/src/org/ofbiz/webapp/control/

jaz-3
Author: jaz
Date: Wed Apr 11 16:36:50 2007
New Revision: 527718

URL: http://svn.apache.org/viewvc?view=rev&rev=527718
Log:
implemented x509 certificate security for specific requests (define with security attribute x509=true)

Modified:
    ofbiz/trunk/framework/base/config/ofbiz-containers.xml
    ofbiz/trunk/framework/base/src/base/org/ofbiz/base/util/KeyStoreUtil.java
    ofbiz/trunk/framework/webapp/dtd/site-conf.xsd
    ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/ConfigXMLReader.java
    ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/LoginWorker.java
    ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java
    ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestManager.java

Modified: ofbiz/trunk/framework/base/config/ofbiz-containers.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/config/ofbiz-containers.xml?view=diff&rev=527718&r1=527717&r2=527718
==============================================================================
--- ofbiz/trunk/framework/base/config/ofbiz-containers.xml (original)
+++ ofbiz/trunk/framework/base/config/ofbiz-containers.xml Wed Apr 11 16:36:50 2007
@@ -229,7 +229,7 @@
             <property name="threadPriority" value="java.lang.Thread#NORM_PRIORITY"/>
             <!-- SSL connector attributes -->
             <property name="algorithm" value="SunX509"/>
-            <property name="clientAuth" value="false"/>
+            <property name="clientAuth" value="want"/>
             <property name="keystoreFile" value="framework/base/config/ofbizssl.jks"/>
             <property name="keystorePass" value="changeit"/>
             <property name="keystoreType" value="JKS"/>

Modified: ofbiz/trunk/framework/base/src/base/org/ofbiz/base/util/KeyStoreUtil.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/base/org/ofbiz/base/util/KeyStoreUtil.java?view=diff&rev=527718&r1=527717&r2=527718
==============================================================================
--- ofbiz/trunk/framework/base/src/base/org/ofbiz/base/util/KeyStoreUtil.java (original)
+++ ofbiz/trunk/framework/base/src/base/org/ofbiz/base/util/KeyStoreUtil.java Wed Apr 11 16:36:50 2007
@@ -40,6 +40,7 @@
 import java.security.spec.PKCS8EncodedKeySpec;
 import java.security.spec.X509EncodedKeySpec;
 import java.util.Collection;
+import java.net.URL;
 
 import javax.crypto.KeyAgreement;
 import javax.crypto.SecretKey;
@@ -100,6 +101,12 @@
         KeyStore ks = KeyStore.getInstance(getTrustStoreType());
         ks.load(fis, getTrustStorePassword().toCharArray());
         fis.close();
+        return ks;
+    }
+
+    public static KeyStore getTrustStore(URL url, String password) throws IOException, GeneralSecurityException {
+        KeyStore ks = KeyStore.getInstance(getTrustStoreType());
+        ks.load(url.openStream(), password.toCharArray());
         return ks;
     }
 

Modified: ofbiz/trunk/framework/webapp/dtd/site-conf.xsd
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/webapp/dtd/site-conf.xsd?view=diff&rev=527718&r1=527717&r2=527718
==============================================================================
--- ofbiz/trunk/framework/webapp/dtd/site-conf.xsd (original)
+++ ofbiz/trunk/framework/webapp/dtd/site-conf.xsd Wed Apr 11 16:36:50 2007
@@ -161,6 +161,15 @@
                 </xs:restriction>
             </xs:simpleType>
         </xs:attribute>
+        <xs:attribute name="x509" default="false">
+            <xs:simpleType>
+                <xs:restriction base="xs:token">
+                    <xs:enumeration value="true"/>
+                    <xs:enumeration value="false"/>
+                </xs:restriction>
+            </xs:simpleType>
+        </xs:attribute>
+        <xs:attribute name="keystore" type="xs:string" use="optional"/>
         <xs:attribute name="external-view" default="true">
             <xs:simpleType>
                 <xs:restriction base="xs:token">

Modified: ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/ConfigXMLReader.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/ConfigXMLReader.java?view=diff&rev=527718&r1=527717&r2=527718
==============================================================================
--- ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/ConfigXMLReader.java (original)
+++ ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/ConfigXMLReader.java Wed Apr 11 16:36:50 2007
@@ -107,6 +107,8 @@
     public static final String SECURITY = "security";
     public static final String SECURITY_HTTPS = "https";
     public static final String SECURITY_AUTH = "auth";
+    public static final String SECURITY_CERT = "x509";
+    public static final String SECURITY_KEYSTORE = "keystore";
     public static final String SECURITY_EXTVIEW = "external-view";
     public static final String SECURITY_DIRECT = "direct-request";
 
@@ -207,10 +209,14 @@
             if (securityElement != null) {
                 String securityHttps = securityElement.getAttribute(SECURITY_HTTPS);
                 String securityAuth = securityElement.getAttribute(SECURITY_AUTH);
+                String securityCert = securityElement.getAttribute(SECURITY_CERT);
+                String securityKeystore = securityElement.getAttribute(SECURITY_KEYSTORE);
                 String securityExtView = securityElement.getAttribute(SECURITY_EXTVIEW);
                 String securityDirectRequest = securityElement.getAttribute(SECURITY_DIRECT);
                 uriMap.put(SECURITY_HTTPS, securityHttps);
                 uriMap.put(SECURITY_AUTH, securityAuth);
+                uriMap.put(SECURITY_CERT, securityCert);
+                uriMap.put(SECURITY_KEYSTORE, securityKeystore);
                 uriMap.put(SECURITY_EXTVIEW, securityExtView);
                 uriMap.put(SECURITY_DIRECT, securityDirectRequest);
             }

Modified: ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/LoginWorker.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/LoginWorker.java?view=diff&rev=527718&r1=527717&r2=527718
==============================================================================
--- ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/LoginWorker.java (original)
+++ ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/LoginWorker.java Wed Apr 11 16:36:50 2007
@@ -18,10 +18,8 @@
  *******************************************************************************/
 package org.ofbiz.webapp.control;
 
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+import java.security.cert.X509Certificate;
 
 import javax.servlet.ServletContext;
 import javax.servlet.ServletRequest;
@@ -35,12 +33,7 @@
 import javolution.util.FastList;
 
 import org.ofbiz.base.component.ComponentConfig;
-import org.ofbiz.base.util.Debug;
-import org.ofbiz.base.util.UtilFormatOut;
-import org.ofbiz.base.util.UtilHttp;
-import org.ofbiz.base.util.UtilMisc;
-import org.ofbiz.base.util.UtilProperties;
-import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.base.util.*;
 import org.ofbiz.entity.GenericDelegator;
 import org.ofbiz.entity.GenericEntityException;
 import org.ofbiz.entity.GenericValue;
@@ -62,6 +55,7 @@
     public static final String resourceWebapp = "WebappUiLabels";
 
     public static final String EXTERNAL_LOGIN_KEY_ATTR = "externalLoginKey";
+    public static final String X509_CERT_ATTR = "SSLx509Cert";
 
     /** This Map is keyed by the randomly generated externalLoginKey and the value is a UserLogin GenericValue object */
     public static Map externalLoginKeys = new HashMap();
@@ -512,6 +506,52 @@
             request.setAttribute("_AUTO_LOGIN_LOGOUT_", Boolean.TRUE);
             return logout(request, response);
         }
+        return "success";
+    }
+
+    public static String check509CertLogin(HttpServletRequest request, HttpServletResponse response) {
+        GenericDelegator delegator = (GenericDelegator) request.getAttribute("delegator");
+        HttpSession session = request.getSession();
+        GenericValue currentUserLogin = (GenericValue) session.getAttribute("userLogin");
+        if (currentUserLogin != null) {
+            if (LoginWorker.isFlaggedLoggedOut(currentUserLogin)) {
+                currentUserLogin = null;
+            }
+        }
+
+        if (currentUserLogin == null) {
+            X509Certificate[] clientCerts = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate"); // 2.2 spec
+            if (clientCerts == null) {
+                clientCerts = (X509Certificate[]) request.getAttribute("javax.net.ssl.peer_certificates"); // 2.1 spec
+            }
+
+            if (clientCerts != null) {
+                for (int i = 0; i < clientCerts.length; i++) {
+                    String certHex = StringUtil.toHexString(clientCerts[i].getPublicKey().getEncoded());
+                    List userLogins = null;
+                    try {
+                        userLogins = delegator.findByAnd("UserLogin", UtilMisc.toMap("x509Cert", certHex));
+                    } catch (GenericEntityException e) {
+                        Debug.logError(e, module);
+                    }
+
+                    if (userLogins != null && userLogins.size() > 0) {
+                        Debug.log("Found [" + userLogins.size() + "] possible UserLogin records.", module);
+                        Iterator it = userLogins.iterator();
+                        while (it.hasNext()) {
+                            GenericValue ul = (GenericValue) it.next();
+                            String enabled = ul.getString("enabled");
+                            if (enabled == null || "Y".equals(enabled)) {
+                                Debug.log("Found x.509 cert for login; logging in as [" + ul.getString("userLoginId") + "]", module);
+                                doBasicLogin(ul, request);
+                                return "success";
+                            }
+                        }
+                    }
+                }
+            }            
+        }
+
         return "success";
     }
 

Modified: ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java?view=diff&rev=527718&r1=527717&r2=527718
==============================================================================
--- ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java (original)
+++ ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java Wed Apr 11 16:36:50 2007
@@ -21,11 +21,12 @@
 import java.io.IOException;
 import java.io.Serializable;
 import java.io.UnsupportedEncodingException;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
+import java.util.*;
+import java.security.cert.X509Certificate;
+import java.security.KeyStore;
+import java.security.GeneralSecurityException;
+import java.security.KeyStoreException;
+import java.net.URL;
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -33,13 +34,7 @@
 
 import javolution.util.FastMap;
 
-import org.ofbiz.base.util.Debug;
-import org.ofbiz.base.util.StringUtil;
-import org.ofbiz.base.util.UtilHttp;
-import org.ofbiz.base.util.UtilMisc;
-import org.ofbiz.base.util.UtilObject;
-import org.ofbiz.base.util.UtilProperties;
-import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.base.util.*;
 import org.ofbiz.entity.GenericDelegator;
 import org.ofbiz.entity.GenericEntityException;
 import org.ofbiz.entity.GenericValue;
@@ -87,6 +82,7 @@
     public void doRequest(HttpServletRequest request, HttpServletResponse response, String chain,
             GenericValue userLogin, GenericDelegator delegator) throws RequestHandlerException {
 
+        HttpSession session = request.getSession();
         String eventType;
         String eventPath;
         String eventMethod;
@@ -139,9 +135,70 @@
                 }
             }
 
-            // If its the first visit run the first visit events.
-            HttpSession session = request.getSession();
+            // Check for HTTPS client (x.509) security
+            if (request.isSecure() && requestManager.requiresHttpsClientCert(requestUri)) {            
+                X509Certificate[] clientCerts = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate"); // 2.2 spec
+                if (clientCerts == null) {
+                    clientCerts = (X509Certificate[]) request.getAttribute("javax.net.ssl.peer_certificates"); // 2.1 spec
+                }
+
+                // check if the client has a valid certificate (in our db store)
+                String keyStorePass = requestManager.get509CertKeyStorePass(requestUri);
+                URL keyStoreUrl = requestManager.get509CertKeyStore(requestUri);    
+                boolean foundValidCert = false;
+
+                if (clientCerts == null) {
+                    throw new RequestHandlerException("Unknown request [" + requestUri + "]; this request does not exist or cannot be called directly.");
+                } else {
+                    // key the trust store info
+
 
+                    // load the trust store
+                    KeyStore keyStore;
+                    try {
+                        keyStore = KeyStoreUtil.getTrustStore(keyStoreUrl, keyStorePass);
+                    } catch (IOException e) {
+                       throw new RequestHandlerException("Unable to open keystore", e);
+                    } catch (GeneralSecurityException e) {
+                        throw new RequestHandlerException("Keystore security problem", e);
+                    }
+
+                    // get all cert aliases
+                    Enumeration en;
+                    try {
+                        en = keyStore.aliases();
+                    } catch (KeyStoreException e) {
+                        throw new RequestHandlerException("Unable to read keystore aliases", e);
+                    }
+
+                    // check for valid client cert
+                    while (en.hasMoreElements() && !foundValidCert) {
+                        String alias = (String) en.nextElement();
+                        X509Certificate trustedCert;
+                        try {
+                            trustedCert = (X509Certificate) keyStore.getCertificate(alias);
+                        } catch (KeyStoreException e) {
+                            throw new RequestHandlerException("Unable to read certificate from keystore", e);
+                        }
+
+                        for (int i = 0; i < clientCerts.length; i++) {
+                            if (!foundValidCert && trustedCert.equals(clientCerts[i])) {
+                                byte[] publicKey = clientCerts[i].getPublicKey().getEncoded();
+                                session.setAttribute(LoginWorker.X509_CERT_ATTR, StringUtil.toHexString(publicKey));
+                                //Debug.log("Cert Hex: " + session.getAttribute(LoginWorker.X509_CERT_ATTR));
+                                foundValidCert = true;
+                            }
+                        }
+                    }
+                }
+
+                if (!foundValidCert) {
+                    Debug.logWarning("No client certification found for request [" + requestUri + "] : " + keyStoreUrl.toExternalForm(), module);
+                    throw new RequestHandlerException("Unknown request [" + requestUri + "]; this request does not exist or cannot be called directly.");
+                }
+            }
+
+            // If its the first visit run the first visit events.
             if (session.getAttribute("visit") == null) {
                 Debug.logInfo("This is the first request in this visit." + " sessionId=" + UtilHttp.getSessionId(request), module);
                 // This isn't an event because it is required to run. We do not want to make it optional.

Modified: ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestManager.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestManager.java?view=diff&rev=527718&r1=527717&r2=527718
==============================================================================
--- ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestManager.java (original)
+++ ofbiz/trunk/framework/webapp/src/org/ofbiz/webapp/control/RequestManager.java Wed Apr 11 16:36:50 2007
@@ -20,6 +20,7 @@
 
 import java.io.Serializable;
 import java.net.URL;
+import java.net.MalformedURLException;
 import java.util.Collection;
 import java.util.Map;
 import java.util.List;
@@ -28,6 +29,7 @@
 
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.base.util.KeyStoreUtil;
 
 /**
  * RequestManager - Manages request, config and view mappings.
@@ -39,12 +41,14 @@
     public static final int EVENT_HANDLER_KEY = 0;
 
     private URL configFileUrl;
+    private URL webInfUrl;
 
     public RequestManager(ServletContext context) {
 
         /** Loads the site configuration from servlet context parameter. */
         try {
             configFileUrl = context.getResource("/WEB-INF/controller.xml");
+            webInfUrl = context.getResource("/WEB-INF");
         } catch (Exception e) {
             Debug.logError(e, "[RequestManager.constructor] Error Finding XML Config File: " +
                 "/WEB-INF/controller.xml", module);
@@ -296,6 +300,65 @@
             return "true".equalsIgnoreCase(value);
         } else
             return false;
+    }
+
+    public boolean requiresHttpsClientCert(String uriStr) {
+        Map uri = getRequestMapMap(uriStr);
+
+        if (uri != null) {
+            String value = (String) uri.get(ConfigXMLReader.SECURITY_CERT);
+
+            //if (Debug.verboseOn()) Debug.logVerbose("Requires x.509 Cert: " + value, module);
+            return "true".equalsIgnoreCase(value);
+        } else
+            return false;
+
+    }
+
+    public URL get509CertKeyStore(String uriStr) {
+        String defaultTrustStore = KeyStoreUtil.getTrustStoreFileName();
+        Map uri = getRequestMapMap(uriStr);
+
+        if (uri != null) {
+            String value = (String) uri.get(ConfigXMLReader.SECURITY_KEYSTORE);
+            if (UtilValidate.isNotEmpty(value)) {
+                if (value.indexOf(";") > -1) {
+                    value = value.substring(0, value.indexOf(";"));
+                }
+                if (value.indexOf(".") == -1) {
+                    value = value + ".jks"; // append .jks if no extension is set
+                }
+
+                try {
+                    return new URL(webInfUrl.toExternalForm() + "/" + value);
+                } catch (MalformedURLException e) {
+                    Debug.logError(e, module);
+                }
+            }
+        }
+
+        // make a url from the default
+        URL url = null;
+        try {
+            url = new URL(defaultTrustStore);
+        } catch (MalformedURLException e) {
+            Debug.logError(e, module);
+        }
+
+        return url;
+    }
+
+    public String get509CertKeyStorePass(String uriStr) {
+        Map uri = getRequestMapMap(uriStr);
+
+        if (uri != null) {
+            String value = (String) uri.get(ConfigXMLReader.SECURITY_KEYSTORE);
+            if (value.indexOf(";") > -1) {            
+                return value.substring(value.indexOf(";") + 1);
+            }
+        }
+
+        return KeyStoreUtil.getTrustStorePassword();
     }
 
     public boolean allowExtView(String uriStr) {