You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by jl...@apache.org on 2018/03/22 20:57:26 UTC

svn commit: r1827528 - in /ofbiz/ofbiz-framework/branches/release17.12: ./ framework/common/webcommon/WEB-INF/ framework/security/config/ framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/

Author: jleroux
Date: Thu Mar 22 20:57:26 2018
New Revision: 1827528

URL: http://svn.apache.org/viewvc?rev=1827528&view=rev
Log:
Reverted: Token Based Authentication
(OFBIZ-9833)

This was a new feature committed the 2017-10-29 and has completely changed since.
It should not stay as is in R17.12


Modified:
    ofbiz/ofbiz-framework/branches/release17.12/   (props changed)
    ofbiz/ofbiz-framework/branches/release17.12/build.gradle
    ofbiz/ofbiz-framework/branches/release17.12/framework/common/webcommon/WEB-INF/common-controller.xml
    ofbiz/ofbiz-framework/branches/release17.12/framework/security/config/security.properties
    ofbiz/ofbiz-framework/branches/release17.12/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ExternalLoginKeysManager.java

Propchange: ofbiz/ofbiz-framework/branches/release17.12/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Mar 22 20:57:26 2018
@@ -10,4 +10,4 @@
 /ofbiz/branches/json-integration-refactoring:1634077-1635900
 /ofbiz/branches/multitenant20100310:921280-927264
 /ofbiz/branches/release13.07:1547657
-/ofbiz/ofbiz-framework/trunk:1819499,1819598,1819800,1819805,1819811,1820038,1820262,1820374-1820375,1820441,1820457,1820644,1820658,1820790,1820823,1820949,1820966,1821012,1821036,1821112,1821115,1821144,1821186,1821219,1821226,1821230,1821386,1821600,1821613,1821628,1821965,1822125,1822310,1822377,1822383,1822393,1822882,1823324,1823467,1823562,1823876,1824260,1824314,1824316,1824732,1824803,1824847,1824855,1825192,1825211,1825216,1825233,1825450,1826374,1826502,1826592,1826671,1826674,1826805,1826938,1826997,1827439,1827441
+/ofbiz/ofbiz-framework/trunk:1819499,1819598,1819800,1819805,1819811,1820038,1820262,1820374-1820375,1820441,1820457,1820644,1820658,1820790,1820823,1820949,1820966,1821012,1821036,1821112,1821115,1821144,1821186,1821219,1821226,1821230,1821386,1821613,1821628,1821965,1822125,1822310,1822377,1822383,1822393,1823467,1823562,1823876,1824314,1824316,1824732,1824803,1824847,1824855,1825192,1825211,1825216,1825233,1825450,1826374,1826502,1826592,1826671,1826674,1826805,1826938,1826997,1827439

Modified: ofbiz/ofbiz-framework/branches/release17.12/build.gradle
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/branches/release17.12/build.gradle?rev=1827528&r1=1827527&r2=1827528&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/branches/release17.12/build.gradle (original)
+++ ofbiz/ofbiz-framework/branches/release17.12/build.gradle Thu Mar 22 20:57:26 2018
@@ -144,7 +144,6 @@ dependencies {
     compile 'org.zapodot:jackson-databind-java-optional:2.6.1'
     compile 'oro:oro:2.0.8'
     compile 'wsdl4j:wsdl4j:1.6.3'
-    compile 'io.jsonwebtoken:jjwt:0.9.0'
     compile 'org.jsoup:jsoup:1.11.2'
 
     // ofbiz unit-test compile libs

Modified: ofbiz/ofbiz-framework/branches/release17.12/framework/common/webcommon/WEB-INF/common-controller.xml
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/branches/release17.12/framework/common/webcommon/WEB-INF/common-controller.xml?rev=1827528&r1=1827527&r2=1827528&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/branches/release17.12/framework/common/webcommon/WEB-INF/common-controller.xml (original)
+++ ofbiz/ofbiz-framework/branches/release17.12/framework/common/webcommon/WEB-INF/common-controller.xml Thu Mar 22 20:57:26 2018
@@ -31,7 +31,6 @@ under the License.
         <event name="checkRequestHeaderLogin" type="java" path="org.apache.ofbiz.webapp.control.LoginWorker" invoke="checkRequestHeaderLogin"/>
         <event name="checkServletRequestRemoteUserLogin" type="java" path="org.apache.ofbiz.webapp.control.LoginWorker" invoke="checkServletRequestRemoteUserLogin"/>
         <event name="checkExternalLoginKey" type="java" path="org.apache.ofbiz.webapp.control.ExternalLoginKeysManager" invoke="checkExternalLoginKey"/>
-        <event name="externalServerLoginCheck" type="java" path="org.apache.ofbiz.webapp.control.ExternalLoginKeysManager" invoke="externalServerLoginCheck"/>
         <event name="checkProtectedView" type="java" path="org.apache.ofbiz.webapp.control.ProtectViewWorker" invoke="checkProtectedView"/>
         <event name="extensionConnectLogin" type="java" path="org.apache.ofbiz.webapp.control.LoginWorker" invoke="extensionConnectLogin"/>
     </preprocessor>

Modified: ofbiz/ofbiz-framework/branches/release17.12/framework/security/config/security.properties
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/branches/release17.12/framework/security/config/security.properties?rev=1827528&r1=1827527&r2=1827528&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/branches/release17.12/framework/security/config/security.properties (original)
+++ ofbiz/ofbiz-framework/branches/release17.12/framework/security/config/security.properties Thu Mar 22 20:57:26 2018
@@ -131,15 +131,3 @@ default.error.response.view=view:viewBlo
 
 # -- If false, then no externalLoginKey parameters will be added to cross-webapp urls
 security.login.externalLoginKey.enabled=true
-
-# -- Security key used to encrypt and decrypt the autogenerated password in forgot password functionality.
-login.secret_key_string=Secret Key
-
-### To have this working, an example of the change needed on the source server is available in OFBIZ-10206-external-server-test-example.patch
-# -- If true, then it's possible to connect to another webapp on another server w/o signing in
-# -- This needs to be changed on both the source server and the target server
-use-external-server=N
-# -- Name of the external server (DNS) ex: demo-trunk.ofbiz.apache.org where the port is not needed, or localhost:8443 (default) for local tests (not using the same webapp)
-external-server-name=demo-trunk.ofbiz.apache.org
-# -- Time To Live of the token send to the external server in seconds
-external-server-token-duration=30

Modified: ofbiz/ofbiz-framework/branches/release17.12/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ExternalLoginKeysManager.java
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/branches/release17.12/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ExternalLoginKeysManager.java?rev=1827528&r1=1827527&r2=1827528&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/branches/release17.12/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ExternalLoginKeysManager.java (original)
+++ ofbiz/ofbiz-framework/branches/release17.12/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ExternalLoginKeysManager.java Thu Mar 22 20:57:26 2018
@@ -18,39 +18,21 @@
  */
 package org.apache.ofbiz.webapp.control;
 
-import java.security.Key;
-import java.util.Date;
 import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 
-import javax.crypto.spec.SecretKeySpec;
-import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
-import javax.xml.bind.DatatypeConverter;
 
 import org.apache.ofbiz.base.util.Debug;
-import org.apache.ofbiz.base.util.UtilHttp;
 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;
-import org.apache.ofbiz.entity.util.EntityUtilProperties;
 import org.apache.ofbiz.service.LocalDispatcher;
 import org.apache.ofbiz.webapp.WebAppUtil;
 
-import io.jsonwebtoken.Claims;
-import io.jsonwebtoken.ExpiredJwtException;
-import io.jsonwebtoken.JwtBuilder;
-import io.jsonwebtoken.Jwts;
-import io.jsonwebtoken.MalformedJwtException;
-import io.jsonwebtoken.SignatureAlgorithm;
-import io.jsonwebtoken.SignatureException;
-import io.jsonwebtoken.UnsupportedJwtException;
-
 /**
  * This class manages the authentication tokens that provide single sign-on authentication to the OFBiz applications.
  */
@@ -59,19 +41,6 @@ public class ExternalLoginKeysManager {
     private static final String EXTERNAL_LOGIN_KEY_ATTR = "externalLoginKey";
     // This Map is keyed by the randomly generated externalLoginKey and the value is a UserLogin GenericValue object
     private static final Map<String, GenericValue> externalLoginKeys = new ConcurrentHashMap<>();
-    public static final String SOURCE_SERVER_WEBAPP_NAME = "sourceServerWebappName";
-    // This works the same way than externalLoginKey but between 2 servers, not 2 webapps on the same server. 
-    // The Single Sign On (SSO) is ensured by a JWT token, then all is handled as normal by a session on the reached server. 
-    // The servers may or may not share a database but the 2 loginUserIds must be the same.
-    
-    // OOTB the JWT masterSecretKey is not properly initialised and can not be OOTB.
-    // As we sign on on several servers, so have different sessions, we can't use the externalLoginKey way to create the JWT masterSecretKey.
-    // IMO the best way to create the JWT masterSecretKey is to use a temporary way to load in a static final key when compiling. 
-    // This is simple and most secure. See OFBIZ-9833 for more, notably https://s.apache.org/cFeK
-    
-    // Because it will contain the ExternalServerJwtMasterSecretKey value; 
-    // you should not let the ExternalLoginKeysManager.java file on a production server after its compilation 
-    private static final String ExternalServerJwtMasterSecretKey = "ExternalServerJwtMasterSecretKey";
 
     /**
      * Gets (and creates if necessary) an authentication token to be used for an external login parameter.
@@ -181,162 +150,5 @@ public class ExternalLoginKeysManager {
     private static boolean isAjax(HttpServletRequest request) {
        return "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
     }
-    
-    public static String externalServerLoginCheck(HttpServletRequest request, HttpServletResponse response) {
-        Delegator delegator = (Delegator) request.getAttribute("delegator");
-        HttpSession session = request.getSession();
-
-        // The target server does not allow external login by default
-        boolean useExternalServer = EntityUtilProperties.getPropertyAsBoolean("security", "use-external-server", false);
-        String sourceWebappName = request.getParameter(SOURCE_SERVER_WEBAPP_NAME); 
-        if (!useExternalServer || sourceWebappName == null) return "success"; // Nothing to do here
-
-        try {
-            String userLoginId = null;
-            String authorizationHeader = request.getHeader("Authorization");
-            if (authorizationHeader != null) {
-                Claims claims = returnsClaims(authorizationHeader);
-                userLoginId = getSourceUserLoginId(claims );
-                boolean jwtOK = checkJwt(authorizationHeader, userLoginId, getTargetServerUrl(request), UtilHttp.getApplicationName(request));
-                if (!jwtOK) {
-                    // Something unexpected happened here
-                    Debug.logWarning("*** There was a problem with the JWT token, not signin in the user login " + userLoginId, module);
-                    return "success";
-                }
-            } else {
-                // Nothing to do here
-                return "success";
-            }
-
-            
-            GenericValue userLogin = EntityQuery.use(delegator).from("UserLogin").where("userLoginId", userLoginId).queryOne();
-            if (userLogin != null) {
-                // Check it's the right tenant in case username and password are the same in different tenants
-                // Not sure this is really useful in the case of external server, should not hurt anyway
-                LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher");
-                String oldDelegatorName = delegator.getDelegatorName();
-                ServletContext servletContext = session.getServletContext();
-                if (!oldDelegatorName.equals(userLogin.getDelegator().getDelegatorName())) {
-                    delegator = DelegatorFactory.getDelegator(userLogin.getDelegator().getDelegatorName());
-                    dispatcher = WebAppUtil.makeWebappDispatcher(servletContext, delegator);
-                    LoginWorker.setWebContextObjects(request, response, delegator, dispatcher);
-                }
-                String enabled = userLogin.getString("enabled");
-                if (enabled == null || "Y".equals(enabled)) {
-                    userLogin.set("hasLoggedOut", "N");
-                    userLogin.store();
-                }
-            } else {
-                Debug.logWarning("*** There was a problem with the JWT token. Could not find userLogin " + userLoginId, module);
-            }
-            LoginWorker.doBasicLogin(userLogin, request);
-        } catch (GenericEntityException e) {
-            Debug.logError(e, "Cannot get autoUserLogin information: " + e.getMessage(), module);
-        }
-
-        return "success";
-    }
-    
-    /**
-     * Generate and return a JWT key
-     * 
-     * @param id is an Id, I suggest userLoginId
-     * @param issuer is who/what issued the token. I suggest the server DNS
-     * @param subject is the subject of the token. I suggest the destination webapp
-     * @param ttlMillis the expiration time
-     * @return a JWT token
-     */
-    public static String createJwt(String id, String issuer, String subject, long ttlMillis) {
-        //The JWT signature algorithm we will be using to sign the token
-        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS512;
-
-        long nowMillis = System.currentTimeMillis();
-        Date now = new Date(nowMillis);
-
-        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(ExternalServerJwtMasterSecretKey);
-        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
-        //Let's set the JWT Claims
-        JwtBuilder builder = Jwts.builder().setId(id)
-                .setIssuedAt(now)
-                .setSubject(subject)
-                .setIssuer(issuer)
-                .setIssuedAt(now)
-                .signWith(signatureAlgorithm, signingKey);
-
-        //if it has been specified, let's add the expiration date, this should always be true
-        if (ttlMillis >= 0) {
-            long expMillis = nowMillis + ttlMillis;
-            Date exp = new Date(expMillis);
-            builder.setExpiration(exp);
-        }
-
-        //Builds the JWT and serialises it to a compact, URL-safe string
-        return builder.compact();
-    }
-    
-    /**
-     * Reads and validates a JWT token
-     * Throws a SignatureException if it is not a signed JWS (as expected) or has been tampered
-     * @param jwt a JWT token
-     * @param id is an Id, I suggest userLoginId
-     * @param issuer is who/what issued the token. I suggest the server DNS
-     * @param subject is the subject of the token. I suggest the destination webapp
-     * @return true if the JWT token corresponds to the one sent and is not expired
-     */
-    private static boolean checkJwt(String jwt, String id, String issuer, String subject) {
-        //The JWT signature algorithm is using this to sign the token
-        Claims claims = returnsClaims(jwt);
-
-        long nowMillis = System.currentTimeMillis();
-        Date now = new Date(nowMillis);
-
-        return claims.getId().equals(id) 
-                && claims.getIssuer().equals(issuer)
-                && claims.getSubject().equals(subject)
-                && claims.getExpiration().after(now);
-    }
-
-    /**
-     * @param jwt a JWT token
-     * @return claims the claims
-     * @throws ExpiredJwtException
-     * @throws UnsupportedJwtException
-     * @throws MalformedJwtException
-     * @throws SignatureException
-     * @throws IllegalArgumentException
-     */
-    private static Claims returnsClaims(String jwt) throws ExpiredJwtException, UnsupportedJwtException,
-            MalformedJwtException, SignatureException, IllegalArgumentException {
-        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS512;
-
-        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(ExternalServerJwtMasterSecretKey);
-        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
-
-        //This line will throw a SignatureException if it is not a signed JWS (as expected) or has been tampered
-        Claims claims = Jwts.parser()
-           .setSigningKey(signingKey)
-           .parseClaimsJws(jwt).getBody();
-        return claims;
-    }
-
-    private static String getSourceUserLoginId(Claims claims) {
-        return claims.getId();
-    }
-    
-    public static String getTargetServerUrl(HttpServletRequest request) {
-        String targetServerUrl = "";
-        Delegator delegator = (Delegator) request.getAttribute("delegator");
-        if (delegator != null && "Y".equals(EntityUtilProperties.getPropertyValue("security", "use-external-server", "N", delegator))) {
-            targetServerUrl = EntityUtilProperties.getPropertyValue("security", "external-server-name", "localhost:8443", delegator);
-            targetServerUrl = "https://" + targetServerUrl;
-        }
-        return targetServerUrl;
-    }
-    
-    public static long getJwtTokenTimeToLive(HttpServletRequest request) {
-        Delegator delegator = (Delegator) request.getAttribute("delegator");
-        if (delegator != null) return 1000 * Long.parseLong(EntityUtilProperties.getPropertyValue("security", "external-server-token-duration", "30", delegator));
-        else return 1000 * 30;
-    }
 
 }