You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by ja...@apache.org on 2017/12/23 10:39:44 UTC

svn commit: r1819133 - in /ofbiz/ofbiz-framework/trunk/framework: catalina/src/main/java/org/apache/ofbiz/catalina/container/ common/servicedef/ common/src/main/java/org/apache/ofbiz/common/login/ security/config/ webapp/src/main/java/org/apache/ofbiz/...

Author: jamesyong
Date: Sat Dec 23 10:39:44 2017
New Revision: 1819133

URL: http://svn.apache.org/viewvc?rev=1819133&view=rev
Log:
Implemented: Tomcat SSO
(OFBIZ-10047)

This allow developers the option to use Tomcat SSO, instead of externalLoginKey, for SSO.

Thanks: Jacques and Michael for the reviews

Added:
    ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/HashedCredentialHandler.java   (with props)
    ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/OFBizRealm.java   (with props)
    ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/SimpleCredentialHandler.java   (with props)
Modified:
    ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/CatalinaContainer.java
    ofbiz/ofbiz-framework/trunk/framework/common/servicedef/services.xml
    ofbiz/ofbiz-framework/trunk/framework/common/src/main/java/org/apache/ofbiz/common/login/LoginServices.java
    ofbiz/ofbiz-framework/trunk/framework/security/config/security.properties
    ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java

Modified: ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/CatalinaContainer.java
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/CatalinaContainer.java?rev=1819133&r1=1819132&r2=1819133&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/CatalinaContainer.java (original)
+++ ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/CatalinaContainer.java Sat Dec 23 10:39:44 2017
@@ -42,6 +42,7 @@ import org.apache.catalina.Globals;
 import org.apache.catalina.Host;
 import org.apache.catalina.LifecycleException;
 import org.apache.catalina.Valve;
+import org.apache.catalina.authenticator.SingleSignOn;
 import org.apache.catalina.connector.Connector;
 import org.apache.catalina.core.StandardContext;
 import org.apache.catalina.core.StandardEngine;
@@ -75,6 +76,7 @@ import org.apache.ofbiz.base.start.Start
 import org.apache.ofbiz.base.util.Debug;
 import org.apache.ofbiz.base.util.UtilValidate;
 import org.apache.ofbiz.base.util.UtilXml;
+import org.apache.ofbiz.entity.util.EntityUtilProperties;
 import org.apache.tomcat.JarScanner;
 import org.apache.tomcat.util.IntrospectionUtils;
 import org.apache.tomcat.util.descriptor.web.FilterDef;
@@ -108,6 +110,19 @@ public class CatalinaContainer implement
         Engine engine = prepareTomcatEngine(tomcat, engineConfig);
         Host host = prepareHost(tomcat, null);
 
+        // add realm and valve for Tomcat SSO
+        if (EntityUtilProperties.propertyValueEquals("security", "security.login.tomcat.sso", "true")){
+            boolean useEncryption = EntityUtilProperties.propertyValueEquals("security", "password.encrypt", "true");
+            OFBizRealm ofBizRealm = new OFBizRealm();
+            if (useEncryption){
+                ofBizRealm.setCredentialHandler(new HashedCredentialHandler());
+            } else {
+                ofBizRealm.setCredentialHandler(new SimpleCredentialHandler());
+            }
+            host.setRealm(ofBizRealm);
+            ((StandardHost)host).addValve(new SingleSignOn());
+        }
+
         // clustering, valves and connectors setup
         Property clusterProps = prepareTomcatClustering(host, engineConfig);
         prepareTomcatEngineValves(engineConfig).forEach(valve -> ((StandardEngine)engine).addValve(valve));

Added: ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/HashedCredentialHandler.java
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/HashedCredentialHandler.java?rev=1819133&view=auto
==============================================================================
--- ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/HashedCredentialHandler.java (added)
+++ ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/HashedCredentialHandler.java Sat Dec 23 10:39:44 2017
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *******************************************************************************/
+package org.apache.ofbiz.catalina.container;
+
+import org.apache.catalina.CredentialHandler;
+import org.apache.ofbiz.base.crypto.HashCrypt;
+import org.apache.ofbiz.common.login.LoginServices;
+
+public class HashedCredentialHandler implements CredentialHandler {
+    @Override
+    public boolean matches(String inputCredentials, String storedCredentials) {
+        return LoginServices.checkPassword(storedCredentials, true, inputCredentials);
+    }
+
+    @Override
+    public String mutate(String inputCredentials) {
+        return HashCrypt.cryptUTF8(LoginServices.getHashType(), null, inputCredentials);
+    }
+}

Propchange: ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/HashedCredentialHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/HashedCredentialHandler.java
------------------------------------------------------------------------------
    svn:keywords = Date Rev Author URL Id

Propchange: ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/HashedCredentialHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/OFBizRealm.java
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/OFBizRealm.java?rev=1819133&view=auto
==============================================================================
--- ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/OFBizRealm.java (added)
+++ ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/OFBizRealm.java Sat Dec 23 10:39:44 2017
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *******************************************************************************/
+package org.apache.ofbiz.catalina.container;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.catalina.realm.GenericPrincipal;
+import org.apache.catalina.realm.RealmBase;
+import org.apache.ofbiz.base.util.Debug;
+import org.apache.ofbiz.entity.Delegator;
+import org.apache.ofbiz.entity.DelegatorFactory;
+import org.apache.ofbiz.entity.GenericEntityException;
+import org.apache.ofbiz.entity.GenericValue;
+import org.apache.ofbiz.entity.util.EntityQuery;
+
+public class OFBizRealm extends RealmBase
+{
+    public static final String module = OFBizRealm.class.getName();
+
+    @Override
+    protected String getName() {
+        return "OFBizRealm";
+    }
+
+    @Override
+    protected String getPassword(String username) {
+        Delegator delegator = DelegatorFactory.getDelegator(null);
+        try {
+            GenericValue userLogin = EntityQuery.use(delegator).from("UserLogin").where("userLoginId", username).queryOne();
+            if (userLogin!=null){
+                return userLogin.getString("currentPassword");
+            }
+        } catch (GenericEntityException e) {
+            Debug.logError(e, module);
+        }
+        return null;
+    }
+
+    @Override
+    protected Principal getPrincipal(String username) {
+        List<String> roles = new ArrayList<>();
+        return new GenericPrincipal(username,
+                getPassword(username),
+                roles);
+    }
+
+}
\ No newline at end of file

Propchange: ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/OFBizRealm.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/OFBizRealm.java
------------------------------------------------------------------------------
    svn:keywords = Date Rev Author URL Id

Propchange: ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/OFBizRealm.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/SimpleCredentialHandler.java
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/SimpleCredentialHandler.java?rev=1819133&view=auto
==============================================================================
--- ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/SimpleCredentialHandler.java (added)
+++ ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/SimpleCredentialHandler.java Sat Dec 23 10:39:44 2017
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *******************************************************************************/
+package org.apache.ofbiz.catalina.container;
+
+import org.apache.catalina.CredentialHandler;
+import org.apache.ofbiz.common.login.LoginServices;
+
+
+public class SimpleCredentialHandler implements CredentialHandler {
+    @Override
+    public boolean matches(String inputCredentials, String storedCredentials) {
+        return LoginServices.checkPassword(storedCredentials, false, inputCredentials);
+    }
+
+    @Override
+    public String mutate(String inputCredentials) {
+        // when password.encrypt=false, password is stored as clear text in the database.
+        // no need to encrypt this input password.
+        return null;
+    }
+}

Propchange: ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/SimpleCredentialHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/SimpleCredentialHandler.java
------------------------------------------------------------------------------
    svn:keywords = Date Rev Author URL Id

Propchange: ofbiz/ofbiz-framework/trunk/framework/catalina/src/main/java/org/apache/ofbiz/catalina/container/SimpleCredentialHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: ofbiz/ofbiz-framework/trunk/framework/common/servicedef/services.xml
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/common/servicedef/services.xml?rev=1819133&r1=1819132&r2=1819133&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/framework/common/servicedef/services.xml (original)
+++ ofbiz/ofbiz-framework/trunk/framework/common/servicedef/services.xml Sat Dec 23 10:39:44 2017
@@ -379,6 +379,7 @@ under the License.
     <service name="userLogin" engine="java" location="org.apache.ofbiz.common.login.LoginServices" invoke="userLogin">
         <description>Used to Automatically Authenticate a username/password; create a UserLogin object</description>
         <implements service="authenticationInterface"/>
+        <attribute name="request" mode="IN" type="javax.servlet.http.HttpServletRequest" optional="true"/>
     </service>
     <service name="createUserLogin" engine="java" auth="false"
         location="org.apache.ofbiz.common.login.LoginServices" invoke="createUserLogin">

Modified: ofbiz/ofbiz-framework/trunk/framework/common/src/main/java/org/apache/ofbiz/common/login/LoginServices.java
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/common/src/main/java/org/apache/ofbiz/common/login/LoginServices.java?rev=1819133&r1=1819132&r2=1819133&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/framework/common/src/main/java/org/apache/ofbiz/common/login/LoginServices.java (original)
+++ ofbiz/ofbiz-framework/trunk/framework/common/src/main/java/org/apache/ofbiz/common/login/LoginServices.java Sat Dec 23 10:39:44 2017
@@ -28,6 +28,8 @@ import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
 import javax.transaction.Transaction;
 
 import org.apache.ofbiz.base.crypto.HashCrypt;
@@ -58,6 +60,8 @@ import org.apache.ofbiz.service.ModelSer
 import org.apache.ofbiz.service.ServiceUtil;
 import org.apache.ofbiz.webapp.control.LoginWorker;
 
+import org.apache.tomcat.util.res.StringManager;
+
 /**
  * <b>Title:</b> Login Services
  */
@@ -209,10 +213,18 @@ public class LoginServices {
                             authFatalError = true;
 
                         }
+
+                        // check whether to sign in with Tomcat SSO
+                        boolean useTomcatSSO = EntityUtilProperties.propertyValueEquals("security", "security.login.tomcat.sso", "true");
+                        HttpServletRequest request = (javax.servlet.http.HttpServletRequest) context.get("request");
+                        // when request is not supplied, we will treat that SSO is not required as
+                        // in the usage of userLogin service in ICalWorker.java and XmlRpcEventHandler.java.
+                        useTomcatSSO = useTomcatSSO && (request!=null);
+
                         // if the password.accept.encrypted.and.plain property in security is set to true allow plain or encrypted passwords
                         // if this is a system account don't bother checking the passwords
                         // if externalAuth passed; this is run as well
-                        if ((!authFatalError && externalAuth) || checkPassword(userLogin.getString("currentPassword"), useEncryption, password)) {
+                        if ((!authFatalError && externalAuth) || (useTomcatSSO ? TomcatSSOLogin(request, username, password) : checkPassword(userLogin.getString("currentPassword"), useEncryption, password) )) {
                             Debug.logVerbose("[LoginServices.userLogin] : Password Matched", module);
 
                             // update the hasLoggedOut flag
@@ -1016,7 +1028,7 @@ public class LoginServices {
         return hashType;
     }
 
-    private static boolean checkPassword(String oldPassword, boolean useEncryption, String currentPassword) {
+    public static boolean checkPassword(String oldPassword, boolean useEncryption, String currentPassword) {
         boolean passwordMatches = false;
         if (oldPassword != null) {
             if (useEncryption) {
@@ -1030,4 +1042,20 @@ public class LoginServices {
         }
         return passwordMatches;
     }
+
+    private static boolean TomcatSSOLogin(HttpServletRequest request, String userName, String currentPassword) {
+        try {
+            request.login(userName, currentPassword);
+        } catch (ServletException e) {
+
+            StringManager sm = StringManager.getManager("org.apache.catalina.connector");
+            if (sm.getString("coyoteRequest.alreadyAuthenticated").equals(e.getMessage())){
+                return true;
+            } else {
+                Debug.logError(e, module);
+                return false;
+            }
+        }
+        return true;
+    }
 }

Modified: ofbiz/ofbiz-framework/trunk/framework/security/config/security.properties
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/security/config/security.properties?rev=1819133&r1=1819132&r2=1819133&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/framework/security/config/security.properties (original)
+++ ofbiz/ofbiz-framework/trunk/framework/security/config/security.properties Sat Dec 23 10:39:44 2017
@@ -116,6 +116,9 @@ security.login.cert.allow=true
 # -- pattern for the userlogin id in CN section of certificate
 security.login.cert.pattern=^(\\w*\\s?\\w*)\\W*.*$
 
+# -- use Tomcat SingleSignOn valve
+security.login.tomcat.sso=false
+
 # -- Hours after which EmailAdressVerification should expire
 email_verification.expire.hours=48
 

Modified: ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java?rev=1819133&r1=1819132&r2=1819133&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java (original)
+++ ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java Sat Dec 23 10:39:44 2017
@@ -34,6 +34,7 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -330,7 +331,7 @@ public class LoginWorker {
         String username = request.getParameter("USERNAME");
         String password = request.getParameter("PASSWORD");
         String forgotPwdFlag = request.getParameter("forgotPwdFlag");
-        
+
         // password decryption
         EntityCrypto entityDeCrypto = null;
         try {
@@ -435,7 +436,7 @@ public class LoginWorker {
         try {
             // get the visit id to pass to the userLogin for history
             String visitId = VisitHandler.getVisitId(session);
-            result = dispatcher.runSync("userLogin", UtilMisc.toMap("login.username", username, "login.password", password, "visitId", visitId, "locale", UtilHttp.getLocale(request)));
+            result = dispatcher.runSync("userLogin", UtilMisc.toMap("login.username", username, "login.password", password, "visitId", visitId, "locale", UtilHttp.getLocale(request), "request", request));
         } catch (GenericServiceException e) {
             Debug.logError(e, "Error calling userLogin service", module);
             Map<String, String> messageMap = UtilMisc.toMap("errorMessage", e.getMessage());
@@ -665,6 +666,15 @@ public class LoginWorker {
         session.invalidate();
         session = request.getSession(true);
 
+        if (EntityUtilProperties.propertyValueEquals("security", "security.login.tomcat.sso", "true")){
+            try {
+                // log out from Tomcat SSO
+                request.logout();
+            } catch (ServletException e) {
+                Debug.logError(e, module);
+            }
+        }
+
         // setup some things that should always be there
         UtilHttp.setInitialRequestInfo(request);
 
@@ -872,6 +882,20 @@ public class LoginWorker {
                 }
             }
         }
+        Boolean useTomcatSSO = EntityUtilProperties.propertyValueEquals("security", "security.login.tomcat.sso", "true");
+        if (useTomcatSSO) {
+
+            // make sure the user isn't already logged in
+            if (!LoginWorker.isUserLoggedIn(request)) {
+                String remoteUserId = request.getRemoteUser();
+                if (UtilValidate.isNotEmpty(remoteUserId)) {
+                    return LoginWorker.loginUserWithUserLoginId(request, response, remoteUserId);
+                } else {
+                    // user is/has logged out at this point
+                    return "success";
+                }
+            }
+        }
 
         return "success";
     }