-
Notifications
You must be signed in to change notification settings - Fork 532
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improved: Add uri shortener function (OFBIZ-13154) (#841)
This improvement offer the possibility to use a shortener url to call ofbiz when it render a url. The origin requirement is to send by email a url to contact OFBiz without any information on technical or functionnal context like JWToken, userLogin, orderId, partyId and so on. OFBiz forward only a short reference that match the actual uri wanted. Example : * ecommerce/myaccount/order/ORD10034 -> s/tiozerzaze * ecommerce/myaccount?token=JWT[more..than..100]axdr&userLoginId=Me@ofbiz.org -> s/epsserlner When a request arrive in OFBiz with the pattern s/{shortener}, the request handler forward to matched uri. To generate a shortener on freemarker template just use it like it : <@ofbizUrl pathShortener="true">${MyBigUriToSecure}</@ofbizUrl> For email template it's ugly recommand to use webSiteId and fullPath <@ofbizUrl webSiteId="MyWebSite" fullPath="true" pathShortener="true">${MyBigUriToSecure}</@ofbizUrl> With this you can have a url like this : https://mywebsite.mydomain/s/rytedqzdfd At this time only <@ofbizUrl macro freemarker support it.
- Loading branch information
Showing
12 changed files
with
341 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
framework/webapp/src/main/groovy/org/apache/ofbiz/webapp/test/OfbizPathShortenerTests.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/******************************************************************************* | ||
* 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.webapp.test | ||
|
||
import org.apache.ofbiz.service.testtools.OFBizTestCase | ||
import org.apache.ofbiz.webapp.OfbizPathShortener | ||
|
||
class OfbizPathShortenerTests extends OFBizTestCase { | ||
|
||
OfbizPathShortenerTests(String name) { | ||
super(name) | ||
} | ||
void testComputeLongUrlToShortUrl() { | ||
String longUri = "passwordChange?USERNAME=admin&TOKEN=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxML" + | ||
"LL.eyJ1c2VyTG9naW5JZCI6Imx1Y2lsZS5wZWxsZXRpZXJAZWRsbi5vcmciLCJpc3MiOiJBcGFjaGVPRkJpeiIsImV4cCI6MTcyNTU" + | ||
"0MjM0OSwiaWF0IjoxNzI1NTQwNTQLLL.Rycl_L-u4ZeWkx82pWWGu7gycfsHQxIxE8zu1nQ5oueGDBeOXALL-SJzMuvSARbpxCwF9A" + | ||
"jl4rTxgoEYuRMoHg&JavaScriptEnabled=Y&Albert=Yoda" | ||
assert OfbizPathShortener.resolveShortenedPath(this.getDelegator(), longUri).length() < 11 | ||
} | ||
void testResolveLongUrlComputedFromShort() { | ||
String longUri = "passwordChange?USERNAME=admin&TOKEN=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxML" + | ||
"LL.eyJ1c2VyTG9naW5JZCI6Imx1Y2lsZS5wZWxsZXRpZXJAZWRsbi5vcmciLCJpc3MiOiJBcGFjaGVPRkJpeiIsImV4cCI6MTcyNTU" + | ||
"0MjM0OSwiaWF0IjoxNzI1NTQwNTQLLL.Rycl_L-u4ZeWkx82pWWGu7gycfsHQxIxE8zu1nQ5oueGDBeOXALL-SJzMuvSARbpxCwF9A" + | ||
"jl4rTxgoEYuRMoHg&JavaScriptEnabled=Y" | ||
String shortUri = OfbizPathShortener.resolveShortenedPath(this.getDelegator(), longUri) | ||
assert longUri == OfbizPathShortener.resolveOriginalPathFromShortened(this.getDelegator(), shortUri) | ||
} | ||
void testResolveLongUrlComputedFromShortAlreadyStored() { | ||
String longUri = "passwordChange?USERNAME=admin&TOKEN=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxML" + | ||
"LL.eyJ1c2VyTG9naW5JZCI6Imx1Y2lsZS5wZWxsZXRpZXJAZWRsbi5vcmciLCJpc3MiOiJBcGFjaGVPRkJpeiIsImV4cCI6MTcyNTU" + | ||
"0MjM0OSwiaWF0IjoxNzI1NTQwNTQLLL.Rycl_L-u4ZeWkx82pWWGu7gycfsHQxIxE8zu1nQ5oueGDBeOXALL-SJzMuvSARbpxCwF9A" + | ||
"jl4rTxgoEYuRMoHg&JavaScriptEnabled=Y&And=Again" | ||
String shortUriFirst = OfbizPathShortener.resolveShortenedPath(this.getDelegator(),longUri) | ||
String shortUriSecond = OfbizPathShortener.resolveShortenedPath(this.getDelegator(),longUri) | ||
assert shortUriSecond == shortUriFirst | ||
} | ||
|
||
} |
176 changes: 176 additions & 0 deletions
176
framework/webapp/src/main/java/org/apache/ofbiz/webapp/OfbizPathShortener.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
/******************************************************************************* | ||
* 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.webapp; | ||
|
||
import java.util.Map; | ||
import javax.transaction.Transaction; | ||
import org.apache.commons.lang.RandomStringUtils; | ||
import org.apache.ofbiz.base.crypto.HashCrypt; | ||
import org.apache.ofbiz.base.util.UtilDateTime; | ||
import org.apache.ofbiz.base.util.UtilProperties; | ||
import org.apache.ofbiz.entity.Delegator; | ||
import org.apache.ofbiz.entity.GenericEntityException; | ||
import org.apache.ofbiz.entity.GenericValue; | ||
import org.apache.ofbiz.entity.transaction.GenericTransactionException; | ||
import org.apache.ofbiz.entity.transaction.TransactionUtil; | ||
import org.apache.ofbiz.entity.util.EntityQuery; | ||
|
||
public class OfbizPathShortener { | ||
public static final String SHORTENED_PATH = "s/"; | ||
public static final String RESTORE_PATH = "../"; | ||
|
||
/** | ||
* For an ofbiz path, return a shortened url that will be linked to the given path | ||
* example : orderview?orderId=HA1023 -> s/izapnreiis | ||
* @param delegator | ||
* @param path to shorten | ||
* @return a shortened key corresponding to the path | ||
* @throws GenericEntityException | ||
*/ | ||
public static String shortenPath(Delegator delegator, String path) throws GenericEntityException { | ||
return SHORTENED_PATH + resolveShortenedPath(delegator, path); | ||
} | ||
|
||
/** | ||
* For the given path, check if a shortened path already exists otherwise generate a new one | ||
* @param delegator | ||
* @param path | ||
* @return a shortened path corresponding to the given path | ||
* @throws GenericEntityException | ||
*/ | ||
public static String resolveShortenedPath(Delegator delegator, String path) throws GenericEntityException { | ||
String shortenedPath = resolveExistingShortenedPath(delegator, path); | ||
int nbLoop = 0; | ||
if (shortenedPath == null) { | ||
do { | ||
shortenedPath = generate(); | ||
nbLoop++; | ||
} while (!recordPathMapping(delegator, path, shortenedPath) || nbLoop > 10); | ||
} | ||
return shortenedPath; | ||
} | ||
|
||
/** | ||
* Try to resolve the original path, if failed, return to the webapp root. Use views request for that define on common-controller | ||
* @param delegator | ||
* @param shortenedPath | ||
* @return the origin path corresponding to the given shortened path, webapp root otherwise | ||
* @throws GenericEntityException | ||
*/ | ||
public static String restoreOriginalPath(Delegator delegator, String shortenedPath) throws GenericEntityException { | ||
String originalPath = resolveOriginalPathFromShortened(delegator, shortenedPath); | ||
return RESTORE_PATH + (originalPath != null ? originalPath : "views"); | ||
} | ||
|
||
/** | ||
* From a shortened path, resolve the origin path | ||
* @param delegator | ||
* @param shortenedPath path | ||
* @return the original path corresponding to the shortened path | ||
* @throws GenericEntityException | ||
*/ | ||
public static String resolveOriginalPathFromShortened(Delegator delegator, String shortenedPath) throws GenericEntityException { | ||
return readPathMapping(delegator, shortenedPath); | ||
} | ||
|
||
/** | ||
* For a path, function tried to resolve if it already presents in database | ||
* For performance issue the function use the hash to resolve it | ||
* @param delegator | ||
* @param path | ||
* @return the shortened path if found, null otherwise | ||
* @throws GenericEntityException | ||
*/ | ||
private static String resolveExistingShortenedPath(Delegator delegator, String path) throws GenericEntityException { | ||
GenericValue existingPath = EntityQuery.use(delegator) | ||
.from("ShortenedPath") | ||
.where("originalPathHash", generateHash(path)) | ||
.cache() | ||
.queryFirst(); | ||
return existingPath != null ? existingPath.getString("shortenedPath") : null; | ||
} | ||
|
||
/** | ||
* generate a random shortened path, the size can be set on property : security. | ||
* @return shortened path | ||
*/ | ||
private static String generate() { | ||
int shortenerSize = UtilProperties.getPropertyAsInteger("security", "path.shortener.size", 10); | ||
return RandomStringUtils.randomAlphabetic(shortenerSize); | ||
} | ||
|
||
/** | ||
* Create the mapping between an origin map and the shortened path | ||
* This will be executed on dedicate transaction to be sure to not rollback it after. | ||
* @param delegator | ||
* @param path | ||
* @param shortenedPath | ||
* @return true if it's create with success | ||
*/ | ||
private static boolean recordPathMapping(Delegator delegator, String path, String shortenedPath) { | ||
Transaction trans = null; | ||
try { | ||
try { | ||
trans = TransactionUtil.suspend(); | ||
TransactionUtil.begin(); | ||
delegator.create("ShortenedPath", Map.of("shortenedPath", shortenedPath, | ||
"originalPath", path, | ||
"originalPathHash", generateHash(path), | ||
"createdDate", UtilDateTime.nowTimestamp(), | ||
"createdByUserLogin", "system")); | ||
TransactionUtil.commit(); | ||
} catch (GenericEntityException e) { | ||
TransactionUtil.rollback(); | ||
return false; | ||
} finally { | ||
TransactionUtil.resume(trans); | ||
} | ||
} catch (GenericTransactionException e) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
/** | ||
* @param path | ||
* @return a hash of the given path | ||
*/ | ||
private static String generateHash(String path) { | ||
return HashCrypt.digestHash("SHA", path.getBytes()); | ||
} | ||
|
||
/** | ||
* Find the origin path corresponding to the shorter in database | ||
* @param delegator | ||
* @param shortenedPath | ||
* @return the original path corresponding to shortened path given, null if not found | ||
* @throws GenericEntityException | ||
*/ | ||
private static String readPathMapping(Delegator delegator, String shortenedPath) throws GenericEntityException { | ||
GenericValue existingPath = EntityQuery.use(delegator) | ||
.from("ShortenedPath") | ||
.where("shortenedPath", shortenedPath) | ||
.cache() | ||
.queryOne(); | ||
return existingPath != null | ||
? existingPath.getString("originalPath") | ||
: null; | ||
} | ||
|
||
} |
Oops, something went wrong.