Author: jleroux
Date: Thu Jun 14 14:37:24 2018 New Revision: 1833510 URL: http://svn.apache.org/viewvc?rev=1833510&view=rev Log: Reverted: Navigate from a domain to another with automated signed in authentication (OFBIZ-10307) This reverts the work done previously for OFBIZ-9833 and OFBIZ-10206 Most parts of it will actually be reused later in a patch. By reverting it will allow to provide a patch for others to review Modified: ofbiz/ofbiz-framework/trunk/build.gradle ofbiz/ofbiz-framework/trunk/framework/common/webcommon/WEB-INF/common-controller.xml ofbiz/ofbiz-framework/trunk/framework/security/config/security.properties ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ExternalLoginKeysManager.java Modified: ofbiz/ofbiz-framework/trunk/build.gradle URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/build.gradle?rev=1833510&r1=1833509&r2=1833510&view=diff ============================================================================== --- ofbiz/ofbiz-framework/trunk/build.gradle (original) +++ ofbiz/ofbiz-framework/trunk/build.gradle Thu Jun 14 14:37:24 2018 @@ -149,7 +149,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/trunk/framework/common/webcommon/WEB-INF/common-controller.xml URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/common/webcommon/WEB-INF/common-controller.xml?rev=1833510&r1=1833509&r2=1833510&view=diff ============================================================================== --- ofbiz/ofbiz-framework/trunk/framework/common/webcommon/WEB-INF/common-controller.xml (original) +++ ofbiz/ofbiz-framework/trunk/framework/common/webcommon/WEB-INF/common-controller.xml Thu Jun 14 14:37:24 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/trunk/framework/security/config/security.properties URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/security/config/security.properties?rev=1833510&r1=1833509&r2=1833510&view=diff ============================================================================== --- ofbiz/ofbiz-framework/trunk/framework/security/config/security.properties (original) +++ ofbiz/ofbiz-framework/trunk/framework/security/config/security.properties Thu Jun 14 14:37:24 2018 @@ -134,12 +134,3 @@ security.login.externalLoginKey.enabled= # -- 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=Y -# -- 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/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ExternalLoginKeysManager.java URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ExternalLoginKeysManager.java?rev=1833510&r1=1833509&r2=1833510&view=diff ============================================================================== --- ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ExternalLoginKeysManager.java (original) +++ ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ExternalLoginKeysManager.java Thu Jun 14 14:37:24 2018 @@ -18,38 +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.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. */ @@ -58,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,159 +151,4 @@ public class ExternalLoginKeysManager { 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(); - - try { - String userLoginId = null; - String authorizationHeader = request.getHeader("Authorization"); - if (authorizationHeader != null) { - Claims claims = returnsClaims(authorizationHeader); - userLoginId = getSourceUserLoginId(claims ); - boolean jwtOK = checkJwt(authorizationHeader, userLoginId, "", ""); - 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); - } - - // make sure the autoUserLogin is set to the same and that the client cookie has the correct userLoginId - LoginWorker.autoLoginSet(request, response); - - 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; - } - } |
Free forum by Nabble | Edit this page |