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) { |
Free forum by Nabble | Edit this page |