From 416c3b5ecac427c12f54ccd8d62c7afdf1155938 Mon Sep 17 00:00:00 2001 From: iroqueta Date: Fri, 12 May 2023 10:42:48 -0300 Subject: [PATCH 1/4] Refactor to move FrontEnd classes to gxweb module from gxclassR module. This allow run non FrontEnd object without Frontend support classes. Issue:102619 --- .../java/com/genexus/db/DynamicExecute.java | 2 +- .../internet/GXWebProgressIndicator.java | 123 ++ .../internet/GXWebProgressIndicatorInfo.java | 122 ++ .../com/genexus/internet/HttpAjaxContext.java | 1792 +++++++++++++++++ .../com/genexus/security/web/SecureToken.java | 37 + .../security/web/SecureTokenHelper.java | 79 + .../genexus/security/web/WebSecureToken.java | 121 ++ .../security/web/WebSecurityHelper.java | 51 + .../security/web/jose/jwt/Algorithm.java | 31 + .../web/jose/jwt/JWTAlgorithmException.java | 18 + .../web/jose/jwt/JWTAudienceException.java | 35 + .../web/jose/jwt/JWTExpiredException.java | 23 + .../web/jose/jwt/JWTIssuerException.java | 22 + .../security/web/jose/jwt/JWTSigner.java | 381 ++++ .../security/web/jose/jwt/JWTVerifier.java | 234 +++ .../web/jose/jwt/JWTVerifyException.java | 18 + .../web/jose/jwt/pem/PemFileReader.java | 42 + .../web/jose/jwt/pem/PemFileWriter.java | 31 + .../security/web/jose/jwt/pem/PemReader.java | 66 + .../security/web/jose/jwt/pem/PemWriter.java | 28 + .../web/jose/jwt/pem/X509CertUtils.java | 61 + .../webpanels/DynAjaxEventContext.java | 48 + .../com/genexus/webpanels/GXMasterPage.java | 5 +- .../genexus/webpanels/GXStaticWebPanel.java | 155 -- .../com/genexus/webpanels/GXUserControl.java | 7 +- .../java/com/genexus/webpanels/GXWebGrid.java | 3 +- .../genexus/webpanels/GXWebObjectBase.java | 288 +++ .../com/genexus/webpanels/GXWebPanel.java | 234 ++- .../com/genexus/webpanels/GXWebPanelStub.java | 33 + .../java/com/genexus/webpanels/GXWebRow.java | 5 +- .../genexus/webpanels/GXWebStdMethods.java | 8 +- .../webpanels/IDynAjaxEventContext.java | 11 + .../com/genexus/webpanels/NoneMasterPage.java | 22 +- .../genexus/webpanels/WebFrontendUtils.java | 13 + .../main/java/com/genexus/GXObjectBase.java | 203 ++ .../main/java/com/genexus/GXWebReport.java | 185 ++ java/src/main/java/com/genexus/GXutil.java | 13 +- .../main/java/com/genexus/GxRestService.java | 44 +- .../com/genexus/internet/HttpContext.java | 941 +-------- .../com/genexus/internet/HttpContextNull.java | 11 +- .../java/com/genexus/reports/GXReport.java | 12 +- .../com/genexus/reports/GXReportText.java | 28 +- .../genexus/webpanels/GXOAuthAccessToken.java | 8 +- .../com/genexus/webpanels/GXOAuthLogout.java | 2 +- .../genexus/webpanels/GXOAuthUserInfo.java | 2 +- .../webpanels/GXObjectUploadServices.java | 6 +- .../com/genexus/webpanels/GXWebException.java | 30 - .../genexus/webpanels/GXWebObjectStub.java | 36 +- .../com/genexus/webpanels/GXWebProcedure.java | 3 +- .../com/genexus/webpanels/HttpContextWeb.java | 193 +- .../java/com/genexus/webpanels/WebUtils.java | 2 +- pom.xml | 4 +- 52 files changed, 4506 insertions(+), 1366 deletions(-) create mode 100644 gxweb/src/main/java/com/genexus/internet/GXWebProgressIndicator.java create mode 100644 gxweb/src/main/java/com/genexus/internet/GXWebProgressIndicatorInfo.java create mode 100644 gxweb/src/main/java/com/genexus/internet/HttpAjaxContext.java create mode 100644 gxweb/src/main/java/com/genexus/security/web/SecureToken.java create mode 100644 gxweb/src/main/java/com/genexus/security/web/SecureTokenHelper.java create mode 100644 gxweb/src/main/java/com/genexus/security/web/WebSecureToken.java create mode 100644 gxweb/src/main/java/com/genexus/security/web/WebSecurityHelper.java create mode 100644 gxweb/src/main/java/com/genexus/security/web/jose/jwt/Algorithm.java create mode 100644 gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTAlgorithmException.java create mode 100644 gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTAudienceException.java create mode 100644 gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTExpiredException.java create mode 100644 gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTIssuerException.java create mode 100644 gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTSigner.java create mode 100644 gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTVerifier.java create mode 100644 gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTVerifyException.java create mode 100644 gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/PemFileReader.java create mode 100644 gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/PemFileWriter.java create mode 100644 gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/PemReader.java create mode 100644 gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/PemWriter.java create mode 100644 gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/X509CertUtils.java create mode 100644 gxweb/src/main/java/com/genexus/webpanels/DynAjaxEventContext.java delete mode 100644 gxweb/src/main/java/com/genexus/webpanels/GXStaticWebPanel.java create mode 100644 gxweb/src/main/java/com/genexus/webpanels/GXWebObjectBase.java create mode 100644 gxweb/src/main/java/com/genexus/webpanels/GXWebPanelStub.java create mode 100644 gxweb/src/main/java/com/genexus/webpanels/IDynAjaxEventContext.java create mode 100644 java/src/main/java/com/genexus/GXObjectBase.java create mode 100644 java/src/main/java/com/genexus/GXWebReport.java delete mode 100644 java/src/main/java/com/genexus/webpanels/GXWebException.java diff --git a/common/src/main/java/com/genexus/db/DynamicExecute.java b/common/src/main/java/com/genexus/db/DynamicExecute.java index cd0c4dda3..0d7203731 100644 --- a/common/src/main/java/com/genexus/db/DynamicExecute.java +++ b/common/src/main/java/com/genexus/db/DynamicExecute.java @@ -26,7 +26,7 @@ public static String dynamicWebExecute(ModelContext context, int handle, Class s if (SpecificImplementation.DynamicExecute != null) isWebContext = SpecificImplementation.DynamicExecute.getIsWebContext(context); - if (isWebContext && c.getSuperclass().equals(SpecificImplementation.Application.getGXWebObjectStubClass())) + if (isWebContext && c.getSuperclass().getSuperclass().equals(SpecificImplementation.Application.getGXWebObjectStubClass())) { // Es un call a un webpanel String objetName; diff --git a/gxweb/src/main/java/com/genexus/internet/GXWebProgressIndicator.java b/gxweb/src/main/java/com/genexus/internet/GXWebProgressIndicator.java new file mode 100644 index 000000000..46aebaffc --- /dev/null +++ b/gxweb/src/main/java/com/genexus/internet/GXWebProgressIndicator.java @@ -0,0 +1,123 @@ +package com.genexus.internet; + +import com.genexus.ModelContext; + +public class GXWebProgressIndicator + { + private static String ID = "GX_PROGRESS_BAR"; + private GXWebNotification notification; + private GXWebProgressIndicatorInfo info; + private ModelContext context; + + public GXWebProgressIndicator(ModelContext gxContext) + { + context = gxContext; + notification = new GXWebNotification(gxContext); + info = new GXWebProgressIndicatorInfo(0,gxContext,""); + } + + public void show() + { + setAction("0"); + updateProgress(); + } + + private void updateProgress() + { + GXWebNotificationInfo notif = new GXWebNotificationInfo(0,context,""); + notif.setId(GXWebProgressIndicator.ID); + notif.setGroupName(GXWebProgressIndicator.ID); + notif.setMessage(info); + notification.notify(notif); + } + + public void showWithTitle(String title) + { + setTitle(title); + setAction("1"); + updateProgress(); + } + + public void showWithTitleAndDescription(String title, String desc) + { + setTitle(title); + setDescription(desc); + setAction("2"); + updateProgress(); + } + + public void hide() + { + setAction("3"); + updateProgress(); + } + + private String getAction() { + return info.getAction(); + } + + private void setAction(String action) { + info.setAction(action); + } + + private String getProgressMessage() + { + return info.toJSonString(); + } + + public String getCssClass() { + return info.getCssClass(); + } + + public void setCssClass(String cssClass) { + info.setCssClass(cssClass); + updateProgress(); + } + + public String getTitle() { + return info.getTitle(); + } + + public void setTitle(String title) { + info.setTitle(title); + updateProgress(); + } + + + public String getDescription() { + return info.getDescription(); + } + + public void setDescription(String description) { + info.setDescription(description); + updateProgress(); + } + + public int getMaxValue() { + return info.getMaxValue(); + } + + public void setMaxValue(int maxValue) { + info.setMaxValue(maxValue); + } + + public int getValue() { + return info.getValue(); + } + + public void setValue(int value) { + info.setValue(value); + updateProgress(); + } + + public byte getType() { + return info.getType(); + } + + public void setType(byte type) { + info.setType(type); + } + + + } + diff --git a/gxweb/src/main/java/com/genexus/internet/GXWebProgressIndicatorInfo.java b/gxweb/src/main/java/com/genexus/internet/GXWebProgressIndicatorInfo.java new file mode 100644 index 000000000..70dd62357 --- /dev/null +++ b/gxweb/src/main/java/com/genexus/internet/GXWebProgressIndicatorInfo.java @@ -0,0 +1,122 @@ +package com.genexus.internet; + +import com.genexus.ModelContext; +import com.genexus.xml.GXXMLSerializable; +import com.genexus.xml.XMLReader; +import com.genexus.xml.XMLWriter; + + + public final class GXWebProgressIndicatorInfo extends GXXMLSerializable + { + private String action; /* 0: Show, 1:ShowWithTitle, 2: ShowWithTitleAndDesc, 3:Hide */ + private String cssClass; + private String title; + private String description; + private int maxValue; + private int value; + private byte type; + + public GXWebProgressIndicatorInfo(int arg0, ModelContext arg1, + String arg2) { + super(arg0, arg1, arg2); + // TODO Auto-generated constructor stub + } + + public void tojson( boolean includeState ) + { + AddObjectProperty("Action", action); + AddObjectProperty("Class", cssClass); + AddObjectProperty("Title", title); + AddObjectProperty("Description", description); + AddObjectProperty("MaxValue", maxValue); + AddObjectProperty("Value", value); + AddObjectProperty("Type", type); + } + + public void tojson( ) + { + tojson( true) ; + } + + public String getJsonMap(String value) {return null;} + + public void initialize() { + // TODO Auto-generated method stub + } + + + public short readxml(XMLReader arg0, String arg1) { + // TODO Auto-generated method stub + return 0; + } + + + public void writexml(XMLWriter arg0, String arg1, String arg2) { + // TODO Auto-generated method stub + + } + + + public void writexml(XMLWriter arg0, String arg1, String arg2, + boolean arg3) { + // TODO Auto-generated method stub + + } + + public String getCssClass() { + return cssClass; + } + + public void setCssClass(String cssClass) { + this.cssClass = cssClass; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public int getMaxValue() { + return maxValue; + } + + public void setMaxValue(int maxValue) { + this.maxValue = maxValue; + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public byte getType() { + return type; + } + + public void setType(byte type) { + this.type = type; + } + } + diff --git a/gxweb/src/main/java/com/genexus/internet/HttpAjaxContext.java b/gxweb/src/main/java/com/genexus/internet/HttpAjaxContext.java new file mode 100644 index 000000000..12d84d2af --- /dev/null +++ b/gxweb/src/main/java/com/genexus/internet/HttpAjaxContext.java @@ -0,0 +1,1792 @@ +package com.genexus.internet; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Array; +import java.util.*; + +import com.genexus.*; +import com.genexus.common.interfaces.IGXWebGrid; +import com.genexus.common.interfaces.IGXWindow; +import com.genexus.diagnostics.core.ILogger; +import com.genexus.diagnostics.core.LogManager; +import com.genexus.servlet.IServletContext; +import com.genexus.servlet.http.IHttpServletRequest; +import com.genexus.servlet.http.IHttpServletResponse; +import com.genexus.util.Codecs; +import com.genexus.util.Encryption; +import com.genexus.util.ThemeHelper; +import com.genexus.webpanels.DynAjaxEventContext; +import com.genexus.common.interfaces.IGXWebRow; + +import com.genexus.webpanels.HttpContextWeb; +import com.genexus.webpanels.WebUtils; +import json.org.json.IJsonFormattable; +import json.org.json.JSONArray; +import json.org.json.JSONException; +import json.org.json.JSONObject; + +public class HttpAjaxContext extends HttpContextWeb +{ + private static String GX_AJAX_REQUEST_HEADER = "GxAjaxRequest"; + + public static final int TYPE_RESET = 0; + public static final int TYPE_SUBMIT = 1; + public static final int TYPE_BUTTON = 2; + + public static final ILogger logger = LogManager.getLogger(HttpAjaxContext.class); + private JSONArray AttValues = new JSONArray(); + private JSONArray PropValues = new JSONArray(); + protected JSONObject HiddenValues = new JSONObject(); + protected JSONObject Messages = new JSONObject(); + private JSONObject WebComponents = new JSONObject(); + private Hashtable LoadCommands = new Hashtable<>(); + private ArrayList Grids = new ArrayList(); + private Hashtable DicGrids = new Hashtable(); + private JSONObject ComponentObjects = new JSONObject(); + protected GXAjaxCommandCollection commands = new GXAjaxCommandCollection(); + protected IGXWebRow _currentGridRow = null; + protected JSONArray StylesheetsToLoad = new JSONArray(); + private Vector styleSheets = new Vector<>(); + private boolean validEncryptedParm = true; + private Vector javascriptSources = new Vector<>(); + private Vector deferredFragments = new Vector(); + private HashSet deferredJavascriptSources = new HashSet(); + private String themekbPrefix; + private String themestyleSheet; + private String themeurlBuildNumber; + private Vector userStyleSheetFiles = new Vector(); + private String serviceWorkerFileName = "service-worker.js"; + private Boolean isServiceWorkerDefinedFlag = null; + private String webAppManifestFileName = "manifest.json"; + private Boolean isWebAppManifestDefinedFlag = null; + private boolean encryptionKeySended = false; + private boolean htmlHeaderClosed = false; + public boolean drawingGrid = false; + private static String CACHE_INVALIDATION_TOKEN; + + protected boolean bCloseCommand = false; + protected String formCaption = ""; + private Object[] returnParms = new Object[] {}; + private Object[] returnParmsMetadata = new Object[] {}; + + private Stack cmpContents = new Stack<>(); + + private String _ajaxOnSessionTimeout = "Ignore"; + public void setAjaxOnSessionTimeout( String ajaxOnSessionTimeout){ this._ajaxOnSessionTimeout = ajaxOnSessionTimeout;} + public String ajaxOnSessionTimeout(){ return _ajaxOnSessionTimeout;} + + DynAjaxEventContext dynAjaxEventContext = new DynAjaxEventContext(); + + public DynAjaxEventContext getDynAjaxEventContext() { + return dynAjaxEventContext; + } + + private boolean isJsOutputEnabled = true; + + public HttpAjaxContext(String requestMethod, IHttpServletRequest req, IHttpServletResponse res, + IServletContext servletContext) throws IOException { + super(requestMethod, req, res, servletContext); + } + + public HttpContext copy() { + try { + HttpAjaxContext ctx = new HttpAjaxContext(requestMethod, request, response, servletContext); + super.copyCommon(ctx); + + return ctx; + } catch (java.io.IOException e) { + return null; + } + } + + public void ajax_sending_grid_row(IGXWebRow row) { + if (isAjaxCallMode()) { + _currentGridRow = row; + } + else { + _currentGridRow = null; + } + } + + private void AddStyleSheetFile(String styleSheet, String urlBuildNumber, boolean isGxThemeHidden) + { + AddStyleSheetFile( styleSheet, urlBuildNumber, isGxThemeHidden, false); + } + + private void AddStyleSheetFile(String styleSheet, String urlBuildNumber, boolean isGxThemeHidden, boolean isDeferred) + { + if (!styleSheets.contains(styleSheet)) + { + styleSheets.add(styleSheet); + String sUncachedURL = oldConvertURL(styleSheet) + urlBuildNumber; + String sLayerName = styleSheet.replace("/", "_").replace(".","_"); + if (!this.getHtmlHeaderClosed() && this.isEnabled) + { + String sRelAtt = (isDeferred ? "rel=\"preload\" as=\"style\" " : "rel=\"stylesheet\""); + if (isGxThemeHidden) + writeTextNL(" @import url(\"" + sUncachedURL + "\") layer(" + sLayerName + ");"); + } + else + { + writeTextNL(" 0) + { + return true; + } + return false; + } + + private String getAjaxEncryptionKey() + { + if(getSessionValue(Encryption.AJAX_ENCRYPTION_KEY) == null) + { + if (!recoverEncryptionKey()) + { + webPutSessionValue(Encryption.AJAX_ENCRYPTION_KEY, Encryption.getRijndaelKey()); + } + } + return (String)getSessionValue(Encryption.AJAX_ENCRYPTION_KEY); + } + + private boolean recoverEncryptionKey() + { + if (getSessionValue(Encryption.AJAX_ENCRYPTION_KEY) == null) + { + String clientKey = getRequest().getHeader(Encryption.AJAX_SECURITY_TOKEN); + if (clientKey != null && clientKey.trim().length() > 0) + { + boolean candecrypt[]=new boolean[1]; + clientKey = Encryption.decryptRijndael(Encryption.GX_AJAX_PRIVATE_IV + clientKey, Encryption.GX_AJAX_PRIVATE_KEY, candecrypt); + if (candecrypt[0]) + { + webPutSessionValue(Encryption.AJAX_ENCRYPTION_KEY, clientKey); + return true; + }else + { + return false; + } + } + } + return false; + } + + public String DecryptAjaxCall(String encrypted) + { + validEncryptedParm = false; + if (isGxAjaxRequest()) + { + String key = getAjaxEncryptionKey(); + boolean candecrypt[] = new boolean[1]; + String decrypted = Encryption.decryptRijndael(encrypted, key, candecrypt); + validEncryptedParm = candecrypt[0]; + if (!validEncryptedParm) + { + CommonUtil.writeLogln( String.format("403 Forbidden error. Could not decrypt Ajax parameter: '%s' with key: '%s'", encrypted, key)); + sendResponseStatus(403, "Forbidden action"); + return ""; + } + if (validEncryptedParm && !getRequestMethod().equalsIgnoreCase("post")) + { + setQueryString(decrypted); + decrypted = GetNextPar(); + } + return decrypted; + } + return encrypted; + } + + public boolean IsValidAjaxCall() + { + return IsValidAjaxCall(true); + } + + public boolean IsValidAjaxCall(boolean insideAjaxCall) + { + if (insideAjaxCall && !validEncryptedParm) + { + CommonUtil.writeLogln( "Failed IsValidAjaxCall 403 Forbidden action"); + sendResponseStatus(403, "Forbidden action"); + return false; + } + else if (!insideAjaxCall && isGxAjaxRequest() && !isFullAjaxMode() && ajaxOnSessionTimeout().equalsIgnoreCase("Warn")) + { + sendResponseStatus(440, "Session timeout"); + return false; + } + return true; + } + + protected void ajax_addCmpContent( String content) + { + if (nCmpDrawLvl > 0) + (cmpContents.peek()).addContent(content); + } + + public void ajax_rspStartCmp( String CmpId) + { + if (isJsOutputEnabled) + { + try + { + WebComponents.put(CmpId, ""); + } + catch (JSONException ex) { } + } + nCmpDrawLvl++; + cmpContents.push(new GXCmpContent(CmpId)); + } + + public void ajax_rspEndCmp() + { + nCmpDrawLvl--; + try + { + GXCmpContent cmp = cmpContents.pop(); + WebComponents.put(cmp.getId(), cmp.getContent()); + if (isSpaRequest()) + { + if (nCmpDrawLvl > 0) + (cmpContents.peek()).addContent(cmp.getContent()); + } + } + catch (JSONException ex) + { + } + } + + private void sendReferer() + { + ajax_rsp_assign_hidden("sCallerURL", org.owasp.encoder.Encode.forUri(getReferer())); + } + + protected void addNavigationHidden() + { + if (this.isLocalStorageSupported()) + { + try { + HiddenValues.put("GX_CLI_NAV", "true"); + } catch (JSONException e) { + } + GXNavigationHelper nav = this.getNavigationHelper(); + if (nav.count() > 0) + { + String sUrl = this.getRequestNavUrl().trim(); + String popupLevel = nav.getUrlPopupLevel(sUrl); + try { + HiddenValues.put("GX_NAV", nav.toJSonString(popupLevel)); + } catch (JSONException e) { + } + nav.deleteStack(popupLevel); + } + } + } + + public void SendWebComponentState() + { + AddStylesheetsToLoad(); + } + + public void SendState() + { + sendReferer(); + sendWebSocketParms(); + addNavigationHidden(); + AddThemeHidden(this.getTheme()); + AddStylesheetsToLoad(); + if (isSpaRequest()) + { + writeTextNL(""); + } + else + { + if (drawGridsAtServer()) + { + writeTextNL(""); + } + skipLines(1); + String value = HiddenValues.toString(); + if (useBase64ViewState()) + { + try{ + value = Codecs.base64Encode(value, "UTF8"); + }catch(Exception ex){} + writeTextNL(""); + } + writeText("
"); + } + } + + private void sendWebSocketParms() + { + if (!this.isAjaxRequest() || isSpaRequest()) + { + ajax_rsp_assign_hidden("GX_WEBSOCKET_ID", clientId); + } + } + + public void AddDeferredJavascriptSource(String jsSrc, String urlBuildNumber) + { + deferredJavascriptSources.add(oldConvertURL(jsSrc) + urlBuildNumber); + } + + + private String FetchCustomCSS() + { + String cssContent; + cssContent = ApplicationContext.getcustomCSSContent().get(getRequest().getServletPath()); + if (cssContent == null) + { + String path = getRequest().getServletPath().replaceAll(".*/", "") + ".css"; + try(InputStream istream = context.packageClass.getResourceAsStream(path)) + { + + if (istream == null) + { + cssContent = ""; + } + else { + //BOMInputStream bomInputStream = new BOMInputStream(istream);// Avoid using BOMInputStream because of runtime error (java.lang.NoSuchMethodError: org.apache.commons.io.IOUtils.length([Ljava/lang/Object;)I) issue 94611 + //cssContent = IOUtils.toString(bomInputStream, "UTF-8"); + cssContent = PrivateUtilities.BOMInputStreamToStringUTF8(istream); + } + } + catch ( Exception e) { + cssContent = ""; + } + ApplicationContext.getcustomCSSContent().put(getRequest().getServletPath(), cssContent); + } + return cssContent; + } + + public void CloseStyles() + { + String cssContent = FetchCustomCSS(); + boolean bHasCustomContent = ! cssContent.isEmpty(); + if (bHasCustomContent && !styleSheets.contains(getRequest().getServletPath())) + { + writeTextNL(""); + styleSheets.add(getRequest().getServletPath()); + } + String[] referencedFiles = ThemeHelper.getThemeCssReferencedFiles(PrivateUtilities.removeExtension(themestyleSheet)); + for (int i=0; i vEnum = deferredFragments.elements(); + while(vEnum.hasMoreElements()) + { + writeTextNL(vEnum.nextElement()); + } + } + + public void ClearJavascriptSources() { + javascriptSources.clear(); + } + + public void AddJavascriptSource(String jsSrc, String urlBuildNumber, boolean userDefined, boolean isInlined) + { + if(!javascriptSources.contains(jsSrc)) + { + urlBuildNumber = getURLBuildNumber(jsSrc, urlBuildNumber); + javascriptSources.add(jsSrc); + String queryString = urlBuildNumber; + String attributes = ""; + if (userDefined) + { + queryString = ""; + attributes = "data-gx-external-script"; + } + String fragment = "" ; + if (isAjaxRequest() || isInlined || jsSrc == "jquery.js" || jsSrc == "gxcore.js") + { + writeTextNL(fragment); + } + else + { + deferredFragments.add(fragment); + } + // After including jQuery, include all the deferred Javascript files + if (jsSrc.equals("jquery.js")) + { + for (String deferredJsSrc : deferredJavascriptSources) + { + AddJavascriptSource(deferredJsSrc, "", false, true); + } + } + // After including gxgral, set the Service Worker Url if one is defined + if (jsSrc.equals("gxgral.js") && isServiceWorkerDefined()) + { + writeTextNL(""); + } + } + } + + public void addWebAppManifest() + { + if (isWebAppManifestDefined()) + { + writeTextNL(""); + } + } + + private boolean isServiceWorkerDefined() + { + if (isServiceWorkerDefinedFlag == null) + { + isServiceWorkerDefinedFlag = Boolean.valueOf(checkFileExists(serviceWorkerFileName)); + } + return isServiceWorkerDefinedFlag == Boolean.valueOf(true); + } + + private boolean isWebAppManifestDefined() + { + if (isWebAppManifestDefinedFlag == null) + { + isWebAppManifestDefinedFlag = Boolean.valueOf(checkFileExists(webAppManifestFileName)); + } + return isWebAppManifestDefinedFlag == Boolean.valueOf(true); + } + + private boolean checkFileExists(String fileName) + { + boolean fileExists = false; + try + { + File file = new File(getDefaultPath() + staticContentBase + fileName); + fileExists = file.exists() && file.isFile(); + com.genexus.diagnostics.Log.info("Searching if file exists (" + fileName + "). Found: " + String.valueOf(fileExists)); + } + catch (Exception e) + { + fileExists = false; + com.genexus.diagnostics.Log.info("Failed searching for a file (" + fileName + ")"); + } + return fileExists; + } + + public void SendAjaxEncryptionKey() + { + if(!encryptionKeySended) + { + String key = getAjaxEncryptionKey(); + ajax_rsp_assign_hidden(Encryption.AJAX_ENCRYPTION_KEY, key); + ajax_rsp_assign_hidden(Encryption.AJAX_ENCRYPTION_IV, Encryption.GX_AJAX_PRIVATE_IV); + try + { + ajax_rsp_assign_hidden(Encryption.AJAX_SECURITY_TOKEN, Encryption.encryptRijndael(key, Encryption.GX_AJAX_PRIVATE_KEY)); + } + catch(Exception exc) {} + encryptionKeySended = true; + } + } + + public void SendServerCommands() + { + try { + if (!isAjaxRequest() && commands.getCount() > 0) + { + HiddenValues.put("GX_SRV_COMMANDS", commands.getJSONArray()); + } + } + catch (JSONException e) { + } + } + + public void ajax_req_read_hidden_sdt(String jsonStr, Object SdtObj) + { + try + { + IJsonFormattable jsonObj; + if (jsonStr.startsWith("[")) + jsonObj = new JSONArray(jsonStr); + else + jsonObj = new JSONObject(jsonStr); + ((IGxJSONAble)SdtObj).FromJSONObject(jsonObj); + } + catch(JSONException exc) {} + } + + public void ajax_rsp_assign_prop_as_hidden(String Control, String Property, String Value) + { + if (!this.isAjaxRequest()) + { + ajax_rsp_assign_hidden(Control + "_" + Property.substring(0, 1) + Property.substring(1).toLowerCase(), Value); + } + } + + public boolean IsSameComponent(String oldName, String newName) + { + if(oldName.trim().equalsIgnoreCase(newName.trim())) + { + return true; + } + else + { + if(newName.trim().toLowerCase().startsWith(oldName.trim().toLowerCase() + "?")) + { + return true; + } + else + { + String packageName = context.getPackageName(); + String qoldName; + String qnewName; + + if ( (oldName.indexOf(packageName) != 0) || (newName.indexOf(packageName) != 0)) + { + qoldName = (oldName.indexOf(packageName) != 0) ? packageName + "." + oldName : oldName; + qnewName = (newName.indexOf(packageName) != 0) ? packageName + "." + newName : newName; + return IsSameComponent(qoldName, qnewName); + } + } + } + return false; + } + + private JSONObject getGxObject(JSONArray array, String CmpContext, boolean IsMasterPage) + { + try + { + JSONObject obj; + int len = array.length(); + for(int i=0; i= 0) + return; + } + if (Control.equals("FORM") && Property.equals("Caption")) + { + formCaption = Value; + } + JSONObject obj = getGxObject(PropValues, CmpContext, IsMasterPage); + if (obj != null) + { + JSONObject ctrlProps = getControlProps(obj, Control); + if (ctrlProps != null) + { + ctrlProps.put(Property, Value); + } + } + com.genexus.internet.HttpContext webContext = (HttpContext) com.genexus.ModelContext.getModelContext().getHttpContext(); + if (webContext != null && !webContext.isAjaxRequest()) + { + ajax_rsp_assign_hidden(Control + "_" + Property.substring(0, 1) + Property.substring(1).toLowerCase(), Value); + } + } + catch (JSONException e) { + } + } + } + } + + public void ajax_rsp_assign_uc_prop(String CmpContext, boolean IsMasterPage, String Control, String Property, String Value) + { + ajax_rsp_assign_prop(CmpContext, IsMasterPage, Control, Property, Value, true); + ajax_rsp_assign_prop_as_hidden(Control, Property, Value); + } + + public void ajax_rsp_assign_boolean_hidden(String Property, Boolean Value) + { + ajax_rsp_assign_hidden(Property, (Object)Value); + } + + public void ajax_rsp_assign_hidden(String Property, String Value) + { + ajax_rsp_assign_hidden(Property, (Object)Value); + } + + private void ajax_rsp_assign_hidden(String Property, Object Value) + { + try { + if (_currentGridRow != null) + _currentGridRow.AddHidden(Property, Value); + else + HiddenValues.put(Property, Value); + } + catch (JSONException e) { + } + } + + public void ajax_rsp_assign_hidden_sdt( String SdtName, Object SdtObj) + { + try { + if (SdtObj instanceof IGxJSONAble) + { + HiddenValues.put(SdtName, ((IGxJSONAble)SdtObj).GetJSONObject()); + } + else + { + if (SdtObj.getClass().isArray()) + { + try { + HiddenValues.put(SdtName, ObjArrayToJSONArray(SdtObj)); + } + catch(ClassCastException e){ + logger.error(String.format("Could not serialize Object '%s' to JSON", SdtName), e); + HiddenValues.put(SdtName, SdtObj); + } + } + } + } + catch (JSONException e) { + logger.error(String.format("Could not serialize Object '%s' to JSON", SdtName), e); + } + } + + public void ajax_rsp_assign_grid(String gridName, IGXWebGrid gridObj) + { + Object jsonObj = ((IGxJSONAble) gridObj).GetJSONObject(); + Grids.add(jsonObj); + } + + public void ajax_rsp_assign_grid(String gridName, IGXWebGrid gridObj, String Control) + { + Object jsonObj = ((IGxJSONAble) gridObj).GetJSONObject(); + if (DicGrids.containsKey(Control)) { + Grids.set(DicGrids.get(Control), jsonObj); + } + else + { + Grids.add(jsonObj); + DicGrids.put(Control, Grids.size() - 1); + } + } + + public void ajax_rsp_clear(){ + PropValues = new JSONArray(); + } + + private boolean shouldLogAjaxControlProperty(String property) + { + return isJsOutputEnabled || (isSpaRequest() && property == "Enabled"); + } + + @Deprecated + public void AddComponentObject(String cmpCtx, String objName) + { + AddComponentObject(cmpCtx, objName, true); + } + + public void AddComponentObject(String cmpCtx, String objName, boolean justCreated) + { + try { + com.genexus.internet.HttpContext webContext = (HttpContext) com.genexus.ModelContext.getModelContext().getHttpContext(); + if (justCreated) + { + try { + webContext.DeletePostValuePrefix(cmpCtx); + } + catch (Exception e) { + logger.error("Could not delete post value prefix", e); + } + } + ComponentObjects.put(cmpCtx, objName); + } + catch (JSONException e) { + } + } + + public void SendComponentObjects() + { + try { + HiddenValues.put("GX_CMP_OBJS", ComponentObjects); + } + catch (JSONException e) { + } + } + + protected void AddThemeHidden(String theme) + { + try { + HiddenValues.put("GX_THEME", theme); + } + catch (JSONException e) { + } + } + + public void AddStylesheetsToLoad() + { + if (StylesheetsToLoad.length() > 0) + { + try { + HiddenValues.put("GX_STYLE_FILES", StylesheetsToLoad); + } + catch (JSONException e) { + } + } + } + + public void SaveComponentMsgList( String sPrefix) + { + try { + Messages.put(sPrefix, GX_msglist.GetJSONObject()); + } + catch (JSONException e) { + } + } + + public String getJSONContainerResponse(IGxJSONAble Container) { + + GXJSONObject jsonCmdWrapper = new GXJSONObject(isMultipartContent()); + try + { + jsonCmdWrapper.put("gxHiddens", HiddenValues); + jsonCmdWrapper.put("gxContainer", Container.GetJSONObject()); + } + catch (JSONException e) + { + } + return jsonCmdWrapper.toString(); + } + + protected String getJSONResponsePrivate(String cmpContext) + { + GXJSONObject jsonCmdWrapper = new GXJSONObject(isMultipartContent()); + try + { + Collections.reverse(Arrays.asList(Grids)); + JSONArray JSONGrids = new JSONArray(Grids); + if (commands.AllowUIRefresh()) + { + if (cmpContext == null || cmpContext.equals("")) + { + cmpContext = "MAIN"; + } + SaveComponentMsgList(cmpContext); + jsonCmdWrapper.put("gxProps", PropValues); + jsonCmdWrapper.put("gxHiddens", HiddenValues); + jsonCmdWrapper.put("gxValues", AttValues); + jsonCmdWrapper.put("gxMessages", Messages); + jsonCmdWrapper.put("gxComponents", WebComponents); + jsonCmdWrapper.put("gxGrids", JSONGrids); + } + for(Enumeration loadCmds = LoadCommands.keys(); loadCmds.hasMoreElements();) + { + appendAjaxCommand("load", LoadCommands.get(loadCmds.nextElement())); + } + if (commands.getCount() > 0) + { + jsonCmdWrapper.put("gxCommands", commands.getJSONArray()); + } + } + catch (JSONException e) + { + } + return jsonCmdWrapper.toString(); + } + + public String getJSONResponse(String cmpContext) + { + if (isCloseCommand() || isRedirected()) + return ""; + return getJSONResponsePrivate(cmpContext); + } + + public String getJSONResponse() + { + return getJSONResponse(""); + } + + public static Object[] createArrayFromArrayObject(Object o) { + if(!o.getClass().getComponentType().isPrimitive()) + return (Object[])o; + + int element_count = Array.getLength(o); + Object elements[] = new Object[element_count]; + + for(int i = 0; i < element_count; i++){ + elements[i] = Array.get(o, i); + } + + return elements; + } + + public static JSONArray ObjArrayToJSONArray(Object parms) + { + return ObjArrayToJSONArray(createArrayFromArrayObject(parms)); + } + + public static JSONArray ObjArrayToJSONArray(Object[] parms) + { + JSONArray inputs = new JSONArray(); + for (int i = 0; i < parms.length; i++) + { + Object parm = parms[i]; + if (parm instanceof IGxJSONAble) + { + inputs.put(((IGxJSONAble)parm).GetJSONObject()); + } + else if (parm.getClass().isArray()) + { + inputs.put(ObjArrayToJSONArray((Object[])parm)); + } + else + { + inputs.put(parm); + } + } + return inputs; + } + + public String getWebReturnParmsJS() + { + return ObjArrayToJSONArray(this.getWebReturnParms()).toString(); + } + + public String getWebReturnParmsMetadataJS() + { + return ObjArrayToJSONArray(this.getWebReturnParmsMetadata()).toString(); + } + + public void writeText(String text) + { + if (getResponseCommited()) + return; + if (isEnabled == false) + { + ajax_addCmpContent(text); + return; + } + _writeText(text); + } + + public void writeValueComplete(String text) + { + writeValueComplete(text, true, true, true); + } + + public void writeValueSpace(String text) + { + writeValueComplete(text, false, false, true); + } + + public void writeValueEnter(String text) + { + writeValueComplete(text, false, true, false); + } + + /** Este writeValue tiene en consideracion los espacios consecutivos, + * los enter y los tabs + */ + public void writeValueComplete(String text, boolean cvtTabs, boolean cvtEnters, boolean cvtSpaces) + { + StringBuilder sb = new StringBuilder(); + boolean lastCharIsSpace = true; // Asumo que al comienzo el lastChar era space + for (int i = 0; i < text.length(); i++) + { + char currentChar = text.charAt(i); + switch (currentChar) + { + case (char) 34: + sb.append("""); + break; + case (char) 38: + sb.append("&"); + break; + case (char) 60: + sb.append("<"); + break; + case (char) 62: + sb.append(">"); + break; + case '\t': + sb.append(cvtTabs ? "    " : ("" + currentChar)); + break; + case '\r': + if (cvtEnters && text.length() > i + 1 && text.charAt(i+1) == '\n'){ + sb.append(cvtEnters ? "
" : ("" + currentChar)); + i++; + } + break; + case '\n': + sb.append(cvtEnters ? "
" : ("" + currentChar)); + break; + case ' ': + sb.append((lastCharIsSpace && cvtSpaces) ? " " : " "); + break; + default: + sb.append("" + currentChar); + } + lastCharIsSpace = currentChar == ' '; + } + writeText(sb.toString()); + } + + public void writeValue(String text) + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < text.length(); i++) + { + char currentChar = text.charAt(i); + + switch (currentChar) + { + case '"': + sb.append("""); + break; + case '&': + sb.append("&"); + break; + case '<': + sb.append("<"); + break; + case '>': + sb.append(">"); + break; + default: + sb.append(currentChar); + } + } + writeText(sb.toString()); + } + + public void skipLines(long num) + { + for(; num > 0; num --) + { + writeText("\n"); + } + } + + public void writeTextNL(String text) + { + writeText(text + "\n"); + } + + public void ajax_rsp_command_close() { + bCloseCommand = true; + try { + JSONObject closeParms = new JSONObject(); + closeParms.put("values", ObjArrayToJSONArray(this.getWebReturnParms())); + closeParms.put("metadata", ObjArrayToJSONArray(this.getWebReturnParmsMetadata())); + appendAjaxCommand("close", closeParms); + } catch (JSONException ex) { + } + } + + public boolean getHtmlHeaderClosed() { + return this.htmlHeaderClosed; + } + + public void closeHtmlHeader() { + this.htmlHeaderClosed = true; + this.writeTextNL(""); + } + + public void redirect_impl(String url, IGXWindow win) { + if (!isGxAjaxRequest() && !isAjaxRequest() && win == null) { + String popupLvl = getNavigationHelper(false).getUrlPopupLevel(getRequestNavUrl()); + String popLvlParm = ""; + if (popupLvl != "-1") { + popLvlParm = (url.indexOf('?') != -1) ? (useOldQueryStringFormat? "," : "&") : "?"; + popLvlParm += com.genexus.util.Encoder.encodeURL("gxPopupLevel=" + popupLvl + ";"); + } + + if (isSpaRequest(true)) { + pushUrlSessionStorage(); + getResponse().setHeader(GX_SPA_REDIRECT_URL, url + popLvlParm); + sendCacheHeaders(); + } else { + redirect_http(url + popLvlParm); + } + } else { + + try { + if (win != null) { + appendAjaxCommand("popup", win.GetJSONObject()); + } else if (!Redirected) { + JSONObject jsonCmd = new JSONObject(); + jsonCmd.put("url", url); + if (this.wjLocDisableFrm > 0) { + jsonCmd.put("forceDisableFrm", this.wjLocDisableFrm); + } + appendAjaxCommand("redirect", jsonCmd); + if (isGxAjaxRequest()) + dispatchAjaxCommands(); + Redirected = true; + } + } catch (JSONException e) { + redirect_http(url); + } + } + } + + public void dispatchAjaxCommands() { + Boolean isResponseCommited = getResponseCommited(); + if (!getResponseCommited()) { + String res = getJSONResponsePrivate(""); + if (!isMultipartContent()) { + response.setContentType("application/json"); + } + sendFinalJSONResponse(res); + setResponseCommited(); + } + } + + public void sendFinalJSONResponse(String json) { + boolean isMultipartResponse = !getResponseCommited() && isMultipartContent(); + if (isMultipartResponse) { + _writeText( + ""); + } + + public void setDrawingGrid(boolean drawingGrid) + { + this.drawingGrid = drawingGrid; + } + + public void windowClosed() + { + String popupLevel = getNavigationHelper().getUrlPopupLevel(getRequestNavUrl()); + if (popupLevel.equals("-1")) + popReferer(); + else + deleteReferer(popupLevel); + } + + public boolean isPopUpObject() + { + if (wrapped) + return false; + return !getNavigationHelper().getUrlPopupLevel(getRequestNavUrl()).equals("-1"); + } + + public int getButtonType() + { + if (drawGridsAtServer()) + { + return TYPE_SUBMIT; + } + return TYPE_BUTTON; + } + + public boolean drawGridsAtServer() + { + if (drawGridsAtServer == -1) + { + drawGridsAtServer = 0; + if( (getContext().getPreferences()).propertyExists("DrawGridsAtServer")) + { + String prop = (getContext().getPreferences()).getProperty("DrawGridsAtServer", "no"); + if (prop.equalsIgnoreCase("always")) + { + drawGridsAtServer = 1; + } + else if (prop.equalsIgnoreCase("ie6")) + { + if (getBrowserType() == BROWSER_IE) + { + if (getBrowserVersion().startsWith("6")) + { + drawGridsAtServer = 1; + } + } + } + } + } + return (drawGridsAtServer == 1); + } + + public String getCssProperty(String propName, String propValue) + { + int browserType = getBrowserType(); + if (propName.equalsIgnoreCase("align")) + { + if (browserType == BROWSER_FIREFOX) + { + return "-moz-" + propValue; + } + else if (browserType == BROWSER_CHROME || browserType == BROWSER_SAFARI) + { + return "-khtml-" + propValue; + } + } + return propValue; + } + + public byte isMobileBrowser() + { + String accept = getHeader("HTTP_ACCEPT"); + + return (accept.indexOf("wap") >= 0 || accept.indexOf("hdml") >= 0)?0: (byte) 1; + } + + public String htmlEndTag(HTMLElement element) + { + HTMLDocType docType = context.getClientPreferences().getDOCTYPE(); + if ((docType == HTMLDocType.HTML4 || docType == HTMLDocType.NONE || docType == HTMLDocType.HTML4S) && + (element == HTMLElement.IMG || + element == HTMLElement.INPUT || + element == HTMLElement.META || + element == HTMLElement.LINK)) + return ">"; + else if (element == HTMLElement.OPTION) + if (docType == HTMLDocType.XHTML1 || docType == HTMLDocType.HTML5) + return ""; + else + return ""; + else + return "/>"; + } + + public String htmlDocType() + { + HTMLDocType docType = context.getClientPreferences().getDOCTYPE(); + switch (docType) + { + case HTML4: + if (context.getClientPreferences().getDOCTYPE_DTD()) + return ""; + else + return ""; + case HTML4S: + if (context.getClientPreferences().getDOCTYPE_DTD()) + return ""; + else + return ""; + case XHTML1: + if (context.getClientPreferences().getDOCTYPE_DTD()) + return ""; + else + return ""; + case HTML5: return ""; + default: return ""; + } + } + + public void popReferer() + { + getNavigationHelper().popUrl(getRequestNavUrl()); + } + + public String getCacheInvalidationToken() + { + if (CACHE_INVALIDATION_TOKEN == null || CACHE_INVALIDATION_TOKEN.trim().length() == 0) + { + String token = (context.getPreferences()).getProperty("CACHE_INVALIDATION_TOKEN", ""); + if (token == null || token.trim().length() == 0) + { + CACHE_INVALIDATION_TOKEN = new java.text.DecimalFormat("#").format(CommonUtil.random() * 1000000); + } + else + { + CACHE_INVALIDATION_TOKEN = token; + } + } + return CACHE_INVALIDATION_TOKEN; + } + + class GXCmpContent + { + private String id; + private String content; + + public GXCmpContent(String id) + { + this.id = id; + this.content = ""; + } + + public String getId() + { + return id; + } + + public void addContent(String content) + { + this.content += content; + } + + public String getContent() + { + return content; + } + } + + class GXAjaxCommand + { + private String[] canManyCmds = new String[] { "print", "load", "popup", "refresh", "ucmethod", "cmp_refresh", "addlines", "set_focus", "calltarget", "exoprop", "exomethod", "refresh_form" }; + private String type; + private Object data; + + public GXAjaxCommand(String type) + { + this.type = type; + this.data = ""; + } + + public GXAjaxCommand(String type, Object data) + { + this.type = type; + this.data = data; + } + + public String getType() + { + return type; + } + + public void setData(Object data) + { + this.data = data; + } + + public Object getData() + { + return data; + } + + public JSONObject getJSONObject() + { + JSONObject jObj = new JSONObject(); + try { + jObj.put(type, data); + } catch (JSONException ex) { + } + return jObj; + } + + public boolean canHaveMany() + { + for (int i = 0; i < canManyCmds.length; i++) + { + if (type.equals(canManyCmds[i])) + { + return true; + } + } + return false; + } + + public boolean equals(Object obj) + { + if (obj instanceof GXAjaxCommand) + { + if (!canHaveMany()) + { + return (type.equalsIgnoreCase(((GXAjaxCommand)obj).getType())); + } + } + return super.equals(obj); + } + + public String toString() + { + return "{ type:" + type + ", data:" + data + " }"; + } + } + + public class GXUsercontrolMethod implements IGxJSONAble + { + JSONObject wrapper; + + public GXUsercontrolMethod(String CmpContext, boolean IsMasterPage, String containerName, String methodName, String output, Object[] parms) + { + wrapper = new JSONObject(); + AddObjectProperty("CmpContext", CmpContext); + AddObjectProperty("IsMasterPage", new Boolean(IsMasterPage)); + AddObjectProperty("Control", containerName); + AddObjectProperty("Method", methodName); + AddObjectProperty("Output", output); + AddObjectProperty("Parms", HttpAjaxContext.ObjArrayToJSONArray(parms)); + } + + public JSONArray GetParmsJArray(Object[] parms) + { + JSONArray inputs = new JSONArray(); + for (int i = 0; i < parms.length; i++) + { + Object parm = parms[i]; + if (parm instanceof IGxJSONAble) + { + inputs.put(((IGxJSONAble)parm).GetJSONObject()); + } + else + { + inputs.put(parm); + } + } + return inputs; + } + + public void AddObjectProperty(String name, Object prop) + { + try + { + wrapper.put(name, prop); + } catch (JSONException ex) { + } + } + + public Object GetJSONObject(boolean includeState) + { + return GetJSONObject(); + } + + public Object GetJSONObject() + { + return wrapper; + } + + public void FromJSONObject(IJsonFormattable obj) + { + } + + public String ToJavascriptSource() + { + return wrapper.toString(); + } + + public void tojson() + { + } + } + + class GXAjaxCommandCollection + { + private ArrayList commands; + private boolean allowUIRefresh; + + public GXAjaxCommandCollection() + { + commands = new ArrayList<>(); + allowUIRefresh = true; + } + + public int getCount() + { + return commands.size(); + } + + public boolean AllowUIRefresh() + { + return allowUIRefresh; + } + + public void AppendCommand(GXAjaxCommand cmd) + { + GXAjaxCommand cmd1 = GetCommand(cmd); + if (cmd1 == null) + { + if (allowUIRefresh) + { + allowUIRefresh = cmd.canHaveMany(); + } + commands.add(cmd); + } + else + { + cmd1.setData(cmd.getData()); + } + } + + private GXAjaxCommand GetCommand(GXAjaxCommand cmd) + { + int cIdx = commands.indexOf(cmd); + if (cIdx > 0) + { + return commands.get(cIdx); + } + return null; + } + + public JSONArray getJSONArray() + { + JSONArray jArr = new JSONArray(); + for(int i=0; i claims; + + try { + claims = new ObjectMapper().readValue(payload, Map.class); + } + catch (JsonProcessingException e) { + logger.error("Signature Error - Failed to serialize payload", e); + return ""; + } + + switch (mode) + { + case Sign: + try { + encoded = signer.sign(claims); + } catch (Exception e) { + logger.error("Signature Error", e); + } + break; + case SignEncrypt: + case None: + logger.warn(String.format("Signature Mode '%s' not implemented", mode)); + break; + } + return encoded; + } + + public static boolean verify(String jwtToken, SecureToken outToken, String secretKey) + { + JWTVerifier verifier = new JWTVerifier(secretKey); + boolean ok = false; + if (!StringUtils.isBlank(jwtToken)) + { + try { + Map mapObj = verifier.verify(jwtToken); + JSONObject jObj = new JSONObject(mapObj); + outToken.FromJSONObject(jObj); + ok = true; + } + catch (Exception e) + { + logger.debug(String.format("Web Token Encryption Exception for Token \nTOKEN: '%s'", jwtToken), e); + } + } + return ok; + } +} diff --git a/gxweb/src/main/java/com/genexus/security/web/WebSecureToken.java b/gxweb/src/main/java/com/genexus/security/web/WebSecureToken.java new file mode 100644 index 000000000..cece09808 --- /dev/null +++ b/gxweb/src/main/java/com/genexus/security/web/WebSecureToken.java @@ -0,0 +1,121 @@ +package com.genexus.security.web; + +import java.util.Date; + +import org.apache.commons.lang.StringUtils; + +import json.org.json.IJsonFormattable; +import json.org.json.JSONException; +import json.org.json.JSONObject; + +public class WebSecureToken extends SecureToken { + private static int TOKEN_DAYS_EXPIRATION = 15; + private static String JSON_ISSUER_NAME = "gx-issuer"; + private static String JSON_EXPIRATION_NAME = "gx-exp"; + private static String JSON_PGMNAME_NAME = "gx-pgm"; + private static String JSON_VALUE_NAME = "gx-val"; + + private String _issuer = ""; + private String _pgmName = ""; + private String _value = ""; + private Date _expiration; + + private JSONObject _jObj = new JSONObject(); + + public WebSecureToken(){ + _expiration = org.apache.commons.lang.time.DateUtils.addDays(new Date(), TOKEN_DAYS_EXPIRATION); + } + + public WebSecureToken(String pgmName, String issuer, String value) { + _expiration = org.apache.commons.lang.time.DateUtils.addDays(new Date(), TOKEN_DAYS_EXPIRATION); + _pgmName = pgmName; + _value = value; + _issuer = issuer; + } + + public String get_issuer() { + return _issuer; + } + public void set_issuer(String _issuer) { + this._issuer = _issuer; + } + public String get_pgmName() { + return _pgmName; + } + public void set_pgmName(String _pgmName) { + this._pgmName = _pgmName; + } + public String get_value() { + return _value; + } + public void set_value(String _value) { + this._value = _value; + } + public Date get_expiration() { + return _expiration; + } + public void set_expiration(Date _expiration) { + this._expiration = _expiration; + } + + public void tojson() + { + AddObjectProperty(WebSecureToken.JSON_ISSUER_NAME, _issuer); + AddObjectProperty(WebSecureToken.JSON_PGMNAME_NAME, _pgmName); + AddObjectProperty(WebSecureToken.JSON_VALUE_NAME, _value); + AddObjectProperty(WebSecureToken.JSON_EXPIRATION_NAME, Long.toString(_expiration.getTime())); + } + + public void AddObjectProperty(String name, Object prop) + { + String ptyValue = ((String)prop); + if (!StringUtils.isBlank(name) && !StringUtils.isBlank(ptyValue)) + { + try { + _jObj.put(name, ptyValue); + } + catch (JSONException e) { + } + } + } + + public Object GetJSONObject() + { + tojson(); + return _jObj; + } + + public Object GetJSONObject(boolean includeState) + { + return GetJSONObject(); + } + + public void FromJSONObject(IJsonFormattable obj) + { + JSONObject jObj = (JSONObject) obj; + this._issuer = getJsonPtyValueString(jObj, WebSecureToken.JSON_ISSUER_NAME); + this._value = getJsonPtyValueString(jObj, WebSecureToken.JSON_VALUE_NAME); + this._pgmName = getJsonPtyValueString(jObj, WebSecureToken.JSON_PGMNAME_NAME); + String expLong = getJsonPtyValueString(jObj, WebSecureToken.JSON_EXPIRATION_NAME); + if (!StringUtils.isBlank(expLong)){ + this._expiration.setTime(Long.parseLong(expLong)); + } + } + + public String ToJavascriptSource() + { + return GetJSONObject().toString(); + } + + private String getJsonPtyValueString(JSONObject jObj, String name) + { + if (jObj.has(name)) + try { + return jObj.getString(name); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return ""; + } +} diff --git a/gxweb/src/main/java/com/genexus/security/web/WebSecurityHelper.java b/gxweb/src/main/java/com/genexus/security/web/WebSecurityHelper.java new file mode 100644 index 000000000..ae7e393c6 --- /dev/null +++ b/gxweb/src/main/java/com/genexus/security/web/WebSecurityHelper.java @@ -0,0 +1,51 @@ +package com.genexus.security.web; + +import java.util.Date; + +import com.genexus.GXutil; +import org.apache.commons.lang.StringUtils; +import org.apache.logging.log4j.Logger; + +import com.genexus.security.web.SecureTokenHelper.SecurityMode; + +public class WebSecurityHelper { + + private static Logger log = org.apache.logging.log4j.LogManager.getLogger(WebSecurityHelper.class); + + public static String sign(String pgmName, String issuer, String value, SecurityMode mode, String key) + { + WebSecureToken token = new WebSecureToken(pgmName, issuer, GXutil.StripInvalidChars(value)); + return SecureTokenHelper.sign(token, mode, key); + } + + public static boolean verify(String pgmName, String issuer, String value, String jwtToken, String key) + { + WebSecureToken token = new WebSecureToken(); + if(!SecureTokenHelper.verify(jwtToken, token, key)) + return false; + boolean ret = !StringUtils.isBlank(pgmName) && token.get_pgmName().equals(pgmName) && issuer.equals(token.get_issuer()) && + GXutil.StripInvalidChars(value).equals(GXutil.StripInvalidChars(token.get_value())) && new Date().compareTo(token.get_expiration()) < 0; + if (!ret && log.isDebugEnabled()) { + String lsep = System.getProperty("line.separator"); + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("Verify: Invalid token" + lsep); + + if (!(token.get_pgmName().equals(pgmName))) { + stringBuilder.append(String.format("Verify: pgmName mismatch '%s' <> '%s' %s", token.get_pgmName(), pgmName, lsep)); + } + if (!(token.get_issuer().equals(issuer))) { + stringBuilder.append(String.format("Verify: issuer mismatch '%s' <> '%s' %s", token.get_issuer(), issuer, lsep)); + } + if (!GXutil.StripInvalidChars(value).equals(GXutil.StripInvalidChars(token.get_value()))) { + stringBuilder.append(String.format("Verify: value mismatch '%s' <> '%s' %s", token.get_value(), value, lsep)); + } + if (!(new Date().compareTo(token.get_expiration()) < 0)) { + stringBuilder.append("Verify: token expired "); + } + log.error(stringBuilder.toString()); + } + return ret; + } + +} diff --git a/gxweb/src/main/java/com/genexus/security/web/jose/jwt/Algorithm.java b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/Algorithm.java new file mode 100644 index 000000000..e69034c51 --- /dev/null +++ b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/Algorithm.java @@ -0,0 +1,31 @@ +package com.genexus.security.web.jose.jwt; + + +/** + * Supported Library Algorithms + * + * https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyPairGenerator + */ +public enum Algorithm { + + HS256("HmacSHA256"), HS384("HmacSHA384"), HS512("HmacSHA512"), RS256("SHA256withRSA"), RS384("SHA384withRSA"), RS512("SHA512withRSA"); + + private Algorithm(final String value) { + this.value = value; + } + + private String value; + + public String getValue() { + return value; + } + + public static Algorithm findByName(final String name) throws JWTAlgorithmException { + try { + return Algorithm.valueOf(name); + } catch (IllegalArgumentException e) { + throw new JWTAlgorithmException("Unsupported algorithm: " + name); + } + } + +} diff --git a/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTAlgorithmException.java b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTAlgorithmException.java new file mode 100644 index 000000000..42eef6e49 --- /dev/null +++ b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTAlgorithmException.java @@ -0,0 +1,18 @@ +package com.genexus.security.web.jose.jwt; + +/** + * Represents Exception related to Algorithm - for example JWT header algorithm is unsupported / missing + */ +public class JWTAlgorithmException extends JWTVerifyException { + public JWTAlgorithmException() {} + + public JWTAlgorithmException(final String message, final Throwable cause) { + super(message, cause); + } + + public JWTAlgorithmException(final String message) { + super(message); + } + +} + diff --git a/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTAudienceException.java b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTAudienceException.java new file mode 100644 index 000000000..974ab9a02 --- /dev/null +++ b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTAudienceException.java @@ -0,0 +1,35 @@ +package com.genexus.security.web.jose.jwt; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * Represents Exception related to Audience - for example illegal audience on JWT Verification + */ +public class JWTAudienceException extends JWTVerifyException { + + private JsonNode audienceNode; + + public JWTAudienceException(final JsonNode audienceNode) { + this.audienceNode = audienceNode; + } + + public JWTAudienceException(final String message, final JsonNode audienceNode) { + super(message); + this.audienceNode = audienceNode; + } + + public List getAudience() { + final ArrayList audience = new ArrayList(); + if (audienceNode.isArray()) { + for (final JsonNode jsonNode : audienceNode) { + audience.add(jsonNode.textValue()); + } + } else if (audienceNode.isTextual()) { + audience.add(audienceNode.textValue()); + } + return audience; + } +} diff --git a/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTExpiredException.java b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTExpiredException.java new file mode 100644 index 000000000..b2b6cba90 --- /dev/null +++ b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTExpiredException.java @@ -0,0 +1,23 @@ +package com.genexus.security.web.jose.jwt; + + +/** + * Represents Exception related to Expiration - for example JWT token has expired + */ +public class JWTExpiredException extends JWTVerifyException { + + private long expiration; + + public JWTExpiredException(final long expiration) { + this.expiration = expiration; + } + + public JWTExpiredException(final String message, final long expiration) { + super(message); + this.expiration = expiration; + } + + public long getExpiration() { + return expiration; + }; +} diff --git a/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTIssuerException.java b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTIssuerException.java new file mode 100644 index 000000000..97df0fdfd --- /dev/null +++ b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTIssuerException.java @@ -0,0 +1,22 @@ +package com.genexus.security.web.jose.jwt; + +/** + * Represents Exception related to Issuer - for example issuer mismatch / missing upon verification + */ +public class JWTIssuerException extends JWTVerifyException { + + private final String issuer; + + public JWTIssuerException(final String issuer) { + this.issuer = issuer; + } + + public JWTIssuerException(final String message, final String issuer) { + super(message); + this.issuer = issuer; + } + + public String getIssuer() { + return issuer; + } +} diff --git a/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTSigner.java b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTSigner.java new file mode 100644 index 000000000..3e66093f5 --- /dev/null +++ b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTSigner.java @@ -0,0 +1,381 @@ +package com.genexus.security.web.jose.jwt; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.Security; +import java.security.Signature; +import java.security.SignatureException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.apache.commons.lang.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang.Validate; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Handles JWT Sign Operation + * + * Default algorithm when none provided is HMAC SHA-256 ("HS256") + * + * See associated library test cases for clear examples on usage + * + */ +public class JWTSigner { + + static { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { + Security.addProvider(new BouncyCastleProvider()); + } + } + + private byte[] secret; + private PrivateKey privateKey; + private static Logger logger = LogManager.getLogger(JWTSigner.class); + + // Default algorithm HMAC SHA-256 ("HS256") + protected final static Algorithm DEFAULT_ALGORITHM = Algorithm.HS256; + + public JWTSigner(final String secret) { + this(secret.getBytes()); + } + + public JWTSigner(final byte[] secret) { + Validate.notNull(secret); + this.secret = secret; + } + + public JWTSigner(final PrivateKey privateKey) { + this.privateKey = privateKey; + } + + /** + * Generate a JSON Web Token. + * + * @param claims A map of the JWT claims that form the payload. Registered claims + * must be of appropriate Java datatype as following: + *
    + *
  • iss, sub: String + *
  • exp, nbf, iat, jti: numeric, eg. Long + *
  • aud: String, or Collection<String> + *
+ * All claims with a null value are left out the JWT. + * Any claims set automatically as specified in + * the "options" parameter override claims in this map. + * @param options Allow choosing the signing algorithm, and automatic setting of some registered claims. + */ + public String sign(final Map claims, final Options options) { + Validate.notNull(claims, "JWT claims cannot be null"); + final Algorithm algorithm = (options != null && options.algorithm != null) ? options.algorithm : DEFAULT_ALGORITHM; + final List segments = new ArrayList(); + try { + segments.add(encodedHeader(algorithm)); + segments.add(encodedPayload(claims, options)); + segments.add(encodedSignature(join(segments, "."), algorithm)); + return join(segments, "."); + } catch (Exception e) { + logger.error("JWT Sign error", e); + throw new RuntimeException(e.getCause()); + } + } + + /** + * Generate a JSON Web Token using the default algorithm HMAC SHA-256 ("HS256") + * and no claims automatically set. + */ + public String sign(final Map claims) { + Validate.notNull(claims); + return sign(claims, null); + } + + /** + * Generate the header part of a JSON web token. + */ + private String encodedHeader(final Algorithm algorithm) throws UnsupportedEncodingException { + Validate.notNull(algorithm); + // create the header + final ObjectNode header = JsonNodeFactory.instance.objectNode(); + header.put("typ", "JWT"); + header.put("alg", algorithm.name()); + return base64UrlEncode(header.toString().getBytes("UTF-8")); + } + + /** + * Generate the JSON web token payload string from the claims. + * + * @param options + */ + private String encodedPayload(final Map _claims, final Options options) throws IOException { + final Map claims = new HashMap(_claims); + enforceStringOrURI(claims, "iss"); + enforceStringOrURI(claims, "sub"); + enforceStringOrURICollection(claims, "aud"); + enforceIntDate(claims, "exp"); + enforceIntDate(claims, "nbf"); + enforceIntDate(claims, "iat"); + enforceString(claims, "jti"); + if (options != null) { + processPayloadOptions(claims, options); + } + final String payload = new ObjectMapper().writeValueAsString(claims); + return base64UrlEncode(payload.getBytes("UTF-8")); + } + + private void processPayloadOptions(final Map claims, final Options options) { + Validate.notNull(claims); + Validate.notNull(options); + final long now = System.currentTimeMillis() / 1000l; + if (options.expirySeconds != null) + claims.put("exp", now + options.expirySeconds); + if (options.notValidBeforeLeeway != null) + claims.put("nbf", now - options.notValidBeforeLeeway); + if (options.isIssuedAt()) + claims.put("iat", now); + if (options.isJwtId()) + claims.put("jti", UUID.randomUUID().toString()); + } + + // consider cleanup + private void enforceIntDate(final Map claims, final String claimName) { + Validate.notNull(claims); + Validate.notNull(claimName); + final Object value = handleNullValue(claims, claimName); + if (value == null) + return; + if (!(value instanceof Number)) { + throw new IllegalStateException(String.format("Claim '%s' is invalid: must be an instance of Number", claimName)); + } + final long longValue = ((Number) value).longValue(); + if (longValue < 0) + throw new IllegalStateException(String.format("Claim '%s' is invalid: must be non-negative", claimName)); + claims.put(claimName, longValue); + } + + // consider cleanup + private void enforceStringOrURICollection(final Map claims, final String claimName) { + final Object values = handleNullValue(claims, claimName); + if (values == null) + return; + if (values instanceof Collection) { + @SuppressWarnings({"unchecked"}) + final Iterator iterator = ((Collection) values).iterator(); + while (iterator.hasNext()) { + Object value = iterator.next(); + String error = checkStringOrURI(value); + if (error != null) + throw new IllegalStateException(String.format("Claim 'aud' element is invalid: %s", error)); + } + } else { + enforceStringOrURI(claims, "aud"); + } + } + + // consider cleanup + private void enforceStringOrURI(final Map claims, final String claimName) { + final Object value = handleNullValue(claims, claimName); + if (value == null) + return; + final String error = checkStringOrURI(value); + if (error != null) + throw new IllegalStateException(String.format("Claim '%s' is invalid: %s", claimName, error)); + } + + // consider cleanup + private void enforceString(final Map claims, final String claimName) { + final Object value = handleNullValue(claims, claimName); + if (value == null) + return; + if (!(value instanceof String)) + throw new IllegalStateException(String.format("Claim '%s' is invalid: not a string", claimName)); + } + + // consider cleanup + private Object handleNullValue(final Map claims, final String claimName) { + if (!claims.containsKey(claimName)) + return null; + final Object value = claims.get(claimName); + if (value == null) { + claims.remove(claimName); + return null; + } + return value; + } + + // consider cleanup + private String checkStringOrURI(final Object value) { + if (!(value instanceof String)) + return "not a string"; + final String stringOrUri = (String) value; + if (!stringOrUri.contains(":")) + return null; + try { + new URI(stringOrUri); + } catch (URISyntaxException e) { + return "not a valid URI"; + } + return null; + } + + /** + * Sign the header and payload + */ + private String encodedSignature(final String signingInput, final Algorithm algorithm) throws NoSuchAlgorithmException, InvalidKeyException, + NoSuchProviderException, SignatureException, JWTAlgorithmException { + Validate.notNull(signingInput); + Validate.notNull(algorithm); + switch (algorithm) { + case HS256: + case HS384: + case HS512: + return base64UrlEncode(signHmac(algorithm, signingInput, secret)); + case RS256: + case RS384: + case RS512: + return base64UrlEncode(signRs(algorithm, signingInput, privateKey)); + default: + throw new JWTAlgorithmException("Unsupported signing method"); + } + } + + /** + * Safe URL encode a byte array to a String + */ + private String base64UrlEncode(final byte[] str) { + Validate.notNull(str); + return new String(Base64.encodeBase64URLSafe(str)); + } + + /** + * Sign an input string using HMAC and return the encrypted bytes + */ + private static byte[] signHmac(final Algorithm algorithm, final String msg, final byte[] secret) throws NoSuchAlgorithmException, InvalidKeyException { + Validate.notNull(algorithm); + Validate.notNull(msg); + Validate.notNull(secret); + final Mac mac = Mac.getInstance(algorithm.getValue()); + mac.init(new SecretKeySpec(secret, algorithm.getValue())); + return mac.doFinal(msg.getBytes()); + } + + /** + * Sign an input string using RSA and return the encrypted bytes + */ + private static byte[] signRs(final Algorithm algorithm, final String msg, final PrivateKey privateKey) throws NoSuchProviderException, + NoSuchAlgorithmException, InvalidKeyException, SignatureException { + Validate.notNull(algorithm); + Validate.notNull(msg); + Validate.notNull(privateKey); + final byte[] messageBytes = msg.getBytes(); + final Signature signature = Signature.getInstance(algorithm.getValue(), "BC"); + signature.initSign(privateKey); + signature.update(messageBytes); + return signature.sign(); + } + + private String join(final List input, final String separator) { + Validate.notNull(input); + Validate.notNull(separator); + return StringUtils.join(input.iterator(), separator); + } + + /** + * An option object for JWT signing operation. Allow choosing the algorithm, and/or specifying + * claims to be automatically set. + */ + public static class Options { + + private Algorithm algorithm; + private Integer expirySeconds; + private Integer notValidBeforeLeeway; + private boolean issuedAt; + private boolean jwtId; + + public Algorithm getAlgorithm() { + return algorithm; + } + + /** + * Algorithm to sign JWT with. + */ + public Options setAlgorithm(final Algorithm algorithm) { + this.algorithm = algorithm; + return this; + } + + + public Integer getExpirySeconds() { + return expirySeconds; + } + + /** + * Set JWT claim "exp" to current timestamp plus this value. + * Overrides content of claims in sign(). + */ + public Options setExpirySeconds(final Integer expirySeconds) { + this.expirySeconds = expirySeconds; + return this; + } + + public Integer getNotValidBeforeLeeway() { + return notValidBeforeLeeway; + } + + /** + * Set JWT claim "nbf" to current timestamp minus this value. + * Overrides content of claims in sign(). + */ + public Options setNotValidBeforeLeeway(final Integer notValidBeforeLeeway) { + this.notValidBeforeLeeway = notValidBeforeLeeway; + return this; + } + + public boolean isIssuedAt() { + return issuedAt; + } + + /** + * Set JWT claim "iat" to current timestamp. Defaults to false. + * Overrides content of claims in sign(). + */ + public Options setIssuedAt(final boolean issuedAt) { + this.issuedAt = issuedAt; + return this; + } + + public boolean isJwtId() { + return jwtId; + } + + /** + * Set JWT claim "jti" to a pseudo random unique value (type 4 UUID). Defaults to false. + * Overrides content of claims in sign(). + */ + public Options setJwtId(final boolean jwtId) { + this.jwtId = jwtId; + return this; + } + + } + +} diff --git a/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTVerifier.java b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTVerifier.java new file mode 100644 index 000000000..bf8b23840 --- /dev/null +++ b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTVerifier.java @@ -0,0 +1,234 @@ +package com.genexus.security.web.jose.jwt; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PublicKey; +import java.security.Security; +import java.security.Signature; +import java.security.SignatureException; +import java.util.Map; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import org.apache.commons.codec.binary.Base64; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * Handles JWT Verification Operations + * + * Validates claims and signature + * + * See associated library test cases for clear examples on usage + * + */ +public class JWTVerifier { + + static { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { + Security.addProvider(new BouncyCastleProvider()); + } + } + + private byte[] secret; + private PublicKey publicKey; + private final String audience; + private final String issuer; + private final Base64 decoder = new Base64(true); + + private final ObjectMapper mapper; + + + public JWTVerifier(final String secret, final String audience, final String issuer) { + this(secret.getBytes(Charset.forName("UTF-8")), audience, issuer); + } + + public JWTVerifier(final String secret, final String audience) { + this(secret, audience, null); + } + + public JWTVerifier(final String secret) { + this(secret, null, null); + } + + public JWTVerifier(final byte[] secret, final String audience) { + this(secret, audience, null); + } + + public JWTVerifier(final byte[] secret) { + this(secret, null, null); + } + + public JWTVerifier(final byte[] secret, final String audience, final String issuer) { + if (secret == null || secret.length == 0) { + throw new IllegalArgumentException("Secret cannot be null or empty"); + } + mapper = new ObjectMapper(); + this.secret = secret; + this.audience = audience; + this.issuer = issuer; + } + + public JWTVerifier(final PublicKey publicKey, final String audience, final String issuer) { + mapper = new ObjectMapper(); + this.publicKey = publicKey; + this.audience = audience; + this.issuer = issuer; + } + + public JWTVerifier(final PublicKey publicKey, final String audience) { + this(publicKey, audience, null); + } + + public JWTVerifier(final PublicKey publicKey) { + this(publicKey, null, null); + } + + + /** + * Performs JWT validation + * + * @param token token to verify + * @throws SignatureException when signature is invalid + * @throws JWTVerifyException when expiration, issuer or audience are invalid + * @throws JWTAlgorithmException when the algorithm is missing or unsupported + * @throws IllegalStateException when token's structure is invalid or secret / public key does not match algorithm of token + */ + @SuppressWarnings({"WeakerAccess", "unchecked"}) + public Map verify(final String token) throws NoSuchAlgorithmException, InvalidKeyException, IllegalStateException, + IOException, SignatureException, JWTVerifyException { + if (token == null || "".equals(token)) { + throw new IllegalStateException("token not set"); + } + final String[] pieces = token.split("\\."); + if (pieces.length != 3) { + throw new IllegalStateException("Wrong number of segments: " + pieces.length); + } + final JsonNode jwtHeader = decodeAndParse(pieces[0]); + final Algorithm algorithm = getAlgorithm(jwtHeader); + final JsonNode jwtPayload = decodeAndParse(pieces[1]); + verifySignature(pieces, algorithm); + verifyExpiration(jwtPayload); + verifyIssuer(jwtPayload); + verifyAudience(jwtPayload); + return mapper.treeToValue(jwtPayload, Map.class); + } + + void verifySignature(final String[] pieces, final Algorithm algorithm) throws NoSuchAlgorithmException, + InvalidKeyException, SignatureException, JWTAlgorithmException, IllegalStateException { + if (pieces.length != 3) { + throw new IllegalStateException("Wrong number of segments: " + pieces.length); + } + switch (algorithm) { + case HS256: + case HS384: + case HS512: + verifyHmac(algorithm, pieces, secret); + return; + case RS256: + case RS384: + case RS512: + verifyRs(algorithm, pieces, publicKey); + return; + default: + throw new JWTAlgorithmException("Unsupported signing method"); + } + } + + private void verifyHmac(final Algorithm algorithm, final String[] pieces, final byte[] secret) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException { + if (secret == null || secret.length == 0) { + throw new IllegalStateException("Secret cannot be null or empty when using algorithm: " + algorithm.getValue()); + } + final Mac hmac = Mac.getInstance(algorithm.getValue()); + hmac.init(new SecretKeySpec(secret, algorithm.getValue())); + final byte[] sig = hmac.doFinal((pieces[0] + "." + pieces[1]).getBytes()); + if (!MessageDigest.isEqual(sig, decoder.decode(pieces[2]))) { + throw new SignatureException("signature verification failed"); + } + } + + private void verifyRs(final Algorithm algorithm, final String[] pieces, final PublicKey publicKey) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException, JWTAlgorithmException { + if (publicKey == null) { + throw new IllegalStateException("PublicKey cannot be null when using algorithm: " + algorithm.getValue()); + } + final byte[] decodedSignatureBytes = new Base64(true).decode(pieces[2]); + final byte[] headerPayloadBytes = (pieces[0] + "." + pieces[1]).getBytes(); + final boolean verified = verifySignatureWithPublicKey(this.publicKey, headerPayloadBytes, decodedSignatureBytes, algorithm); + if (!verified) { + throw new SignatureException("signature verification failed"); + } + } + + private boolean verifySignatureWithPublicKey(final PublicKey publicKey, final byte[] messageBytes, final byte[] signatureBytes, final Algorithm algorithm) throws InvalidKeyException, SignatureException, NoSuchAlgorithmException, JWTAlgorithmException { + try { + final Signature signature = Signature.getInstance(algorithm.getValue(), "BC"); + signature.initVerify(publicKey); + signature.update(messageBytes); + return signature.verify(signatureBytes); + } catch (NoSuchProviderException e) { + throw new JWTAlgorithmException(e.getMessage(), e.getCause()); + } + } + + void verifyExpiration(final JsonNode jwtClaims) throws JWTExpiredException { + final long expiration = jwtClaims.has("exp") ? jwtClaims.get("exp").asLong(0) : 0; + if (expiration != 0 && System.currentTimeMillis() / 1000L >= expiration) { + throw new JWTExpiredException("jwt expired", expiration); + } + } + + void verifyIssuer(final JsonNode jwtClaims) throws JWTIssuerException { + if (this.issuer == null ) { + return; + } + + final String issuerFromToken = jwtClaims.has("iss") ? jwtClaims.get("iss").asText() : null; + + if (issuerFromToken == null || !issuer.equals(issuerFromToken)) { + throw new JWTIssuerException("jwt issuer invalid", issuerFromToken); + } + } + + void verifyAudience(final JsonNode jwtClaims) throws JWTAudienceException { + if (audience == null) { + return; + } + final JsonNode audNode = jwtClaims.get("aud"); + if (audNode == null) { + throw new JWTAudienceException("jwt audience invalid", null); + } + if (audNode.isArray()) { + for (final JsonNode jsonNode : audNode) { + if (audience.equals(jsonNode.textValue())) { + return; + } + } + } else if (audNode.isTextual()) { + if (audience.equals(audNode.textValue())) { + return; + } + } + throw new JWTAudienceException("jwt audience invalid", audNode); + } + + Algorithm getAlgorithm(final JsonNode jwtHeader) throws JWTAlgorithmException { + final String algorithmName = jwtHeader.has("alg") ? jwtHeader.get("alg").asText() : null; + if (jwtHeader.get("alg") == null) { + throw new IllegalStateException("algorithm not set"); + } + return Algorithm.findByName(algorithmName); + } + + JsonNode decodeAndParse(final String b64String) throws IOException { + final String jsonString = new String(decoder.decode(b64String), "UTF-8"); + return mapper.readValue(jsonString, JsonNode.class); + } + +} diff --git a/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTVerifyException.java b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTVerifyException.java new file mode 100644 index 000000000..9c2a20103 --- /dev/null +++ b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/JWTVerifyException.java @@ -0,0 +1,18 @@ +package com.genexus.security.web.jose.jwt; + +/** + * Represents General Exception related to Verification + */ +public class JWTVerifyException extends Exception { + + public JWTVerifyException() {} + + public JWTVerifyException(final String message, final Throwable cause) { + super(message, cause); + } + + public JWTVerifyException(final String message) { + super(message); + } + +} diff --git a/gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/PemFileReader.java b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/PemFileReader.java new file mode 100644 index 000000000..73deaa589 --- /dev/null +++ b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/PemFileReader.java @@ -0,0 +1,42 @@ +package com.genexus.security.web.jose.jwt.pem; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; + +import org.bouncycastle.util.io.pem.PemObject; +import org.bouncycastle.util.io.pem.PemReader; +import org.bouncycastle.util.io.pem.PemWriter; + +/** + * Can read PEM from disk - depends on BouncyCastle PemReader + */ +class PemFileReader { + + private PemObject pemObject; + + public PemFileReader(final String filename) throws IOException { + final PemReader pemReader = new PemReader(new InputStreamReader(new FileInputStream(filename))); + try { + this.pemObject = pemReader.readPemObject(); + } finally { + pemReader.close(); + } + } + + public void write(final String filename) throws IOException { + final PemWriter pemWriter = new PemWriter(new OutputStreamWriter(new FileOutputStream(filename))); + try { + pemWriter.writeObject(this.pemObject); + } finally { + pemWriter.close(); + } + } + + public PemObject getPemObject() { + return pemObject; + } + +} diff --git a/gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/PemFileWriter.java b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/PemFileWriter.java new file mode 100644 index 000000000..aebe9a65f --- /dev/null +++ b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/PemFileWriter.java @@ -0,0 +1,31 @@ +package com.genexus.security.web.jose.jwt.pem; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.security.Key; + +import org.bouncycastle.util.io.pem.PemObject; +import org.bouncycastle.util.io.pem.PemWriter; + +/** + * Can write PEM to disk - depends on BouncyCastle PemWriter + */ +class PemFileWriter { + + private PemObject pemObject; + + public PemFileWriter(final Key key, final String description) { + this.pemObject = new PemObject(description, key.getEncoded()); + } + + public void write(final String filename) throws IOException { + final PemWriter pemWriter = new PemWriter(new OutputStreamWriter(new FileOutputStream(filename))); + try { + pemWriter.writeObject(this.pemObject); + } finally { + pemWriter.close(); + } + } + +} diff --git a/gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/PemReader.java b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/PemReader.java new file mode 100644 index 000000000..758161835 --- /dev/null +++ b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/PemReader.java @@ -0,0 +1,66 @@ +package com.genexus.security.web.jose.jwt.pem; + + +import java.io.File; +import java.io.IOException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Security; +import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +/** + * Read operations for PEM files + */ +public class PemReader { + + static { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { + Security.addProvider(new BouncyCastleProvider()); + } + } + + public static PrivateKey readPrivateKey(final String filePath) throws NoSuchProviderException, NoSuchAlgorithmException, IOException, InvalidKeySpecException { + final KeyFactory factory = KeyFactory.getInstance("RSA", "BC"); + final PrivateKey privateKey = readPrivateKeyFromFile(factory, filePath); + return privateKey; + } + + public static PublicKey readPublicKey(final String filePath) throws NoSuchProviderException, NoSuchAlgorithmException, IOException, InvalidKeySpecException { + final KeyFactory factory = KeyFactory.getInstance("RSA", "BC"); + final PublicKey publicKey = readPublicKeyFromFile(factory, filePath); + return publicKey; + } + + private static PrivateKey readPrivateKeyFromFile(final KeyFactory factory, final String filename) throws InvalidKeySpecException, IOException { + final PemFileReader pemFileReader = new PemFileReader(filename); + final byte[] content = pemFileReader.getPemObject().getContent(); + final PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(content); + return factory.generatePrivate(privKeySpec); + } + + private static PublicKey readPublicKeyFromFile(final KeyFactory factory, final String filename) throws InvalidKeySpecException, IOException { + final File file = new File(filename); + final byte[] data = new byte[0];//Files.readAllBytes(file.toPath()); + final X509Certificate cert = X509CertUtils.parse(new String(data)); + if (cert != null) { + java.security.PublicKey publicKey = cert.getPublicKey(); + return publicKey; + } else { + final PemFileReader pemFileReader = new PemFileReader(filename); + final byte[] content = pemFileReader.getPemObject().getContent(); + final X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content); + return factory.generatePublic(pubKeySpec); + } + + + } + +} diff --git a/gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/PemWriter.java b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/PemWriter.java new file mode 100644 index 000000000..5dc26e0e3 --- /dev/null +++ b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/PemWriter.java @@ -0,0 +1,28 @@ +package com.genexus.security.web.jose.jwt.pem; + + + +import java.io.IOException; +import java.security.Key; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +/** + * Write operations for PEM files + */ +public class PemWriter { + + public static void writePrivateKey(final RSAPrivateKey privateKey, final String description, final String filename) throws IOException { + writePemFile(privateKey, description, filename); + } + + public static void writePublicKey(final RSAPublicKey publicKey, final String description, final String filename) throws IOException { + writePemFile(publicKey, description, filename); + } + + public static void writePemFile(final Key key, final String description, final String filename) throws IOException { + final PemFileWriter pemFileWriter = new PemFileWriter(key, description); + pemFileWriter.write(filename); + } + +} diff --git a/gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/X509CertUtils.java b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/X509CertUtils.java new file mode 100644 index 000000000..33a4f3cb5 --- /dev/null +++ b/gxweb/src/main/java/com/genexus/security/web/jose/jwt/pem/X509CertUtils.java @@ -0,0 +1,61 @@ +package com.genexus.security.web.jose.jwt.pem; + +import java.io.ByteArrayInputStream; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import org.apache.commons.codec.binary.Base64; + + +/** + * X.509 certificate utilities. + */ +public class X509CertUtils { + + private static final String PEM_BEGIN_MARKER = "-----BEGIN CERTIFICATE-----"; + private static final String PEM_END_MARKER = "-----END CERTIFICATE-----"; + + /** + * Parses a DER-encoded X.509 certificate. + */ + public static X509Certificate parse(final byte[] derEncodedCert) { + if (derEncodedCert == null || derEncodedCert.length == 0) { + return null; + } + try { + final CertificateFactory cf = CertificateFactory.getInstance("X.509"); + final Certificate cert = cf.generateCertificate(new ByteArrayInputStream(derEncodedCert)); + if (!(cert instanceof X509Certificate)) { + return null; + } + return (X509Certificate) cert; + } catch (CertificateException e) { + return null; + } + } + + /** + * Parses a PEM-encoded X.509 certificate. + */ + public static X509Certificate parse(final String pemEncodedCert) { + if (pemEncodedCert == null || pemEncodedCert.isEmpty()) { + return null; + } + final int markerStart = pemEncodedCert.indexOf(PEM_BEGIN_MARKER); + if (markerStart < 0) { + return null; + } + String buf = pemEncodedCert.substring(markerStart + PEM_BEGIN_MARKER.length()); + final int markerEnd = buf.indexOf(PEM_END_MARKER); + if (markerEnd < 0) { + return null; + } + buf = buf.substring(0, markerEnd); + buf = buf.replaceAll("\\s", ""); + return parse(new Base64(true).decodeBase64(buf)); + } + +} + diff --git a/gxweb/src/main/java/com/genexus/webpanels/DynAjaxEventContext.java b/gxweb/src/main/java/com/genexus/webpanels/DynAjaxEventContext.java new file mode 100644 index 000000000..23943d196 --- /dev/null +++ b/gxweb/src/main/java/com/genexus/webpanels/DynAjaxEventContext.java @@ -0,0 +1,48 @@ +package com.genexus.webpanels; + +import com.genexus.GXutil; +import com.genexus.internet.IGxJSONSerializable; +import json.org.json.JSONArray; + +import java.util.HashSet; +import java.util.Hashtable; + +public class DynAjaxEventContext implements IDynAjaxEventContext { + JSONArray inParmsMetadata; + HashSet inParmsMetadataHash = new HashSet(); + JSONArray outParmsMetadata; + HashSet outParmsMetadataHash = new HashSet(); + private Hashtable inParmsHashValue = new Hashtable(); + + public void ClearParmsMetadata() { + inParmsMetadata = new JSONArray(); + inParmsMetadataHash = new HashSet(); + outParmsMetadata = new JSONArray(); + outParmsMetadataHash = new HashSet(); + } + + public boolean isInputParm(String key) { + return inParmsMetadataHash.contains(key); + } + + public void Clear() { + inParmsHashValue.clear(); + } + + public void SetParmHash(String fieldName, Object value) { + IGxJSONSerializable jsonValue = (value instanceof IGxJSONSerializable) ? (IGxJSONSerializable) value : null; + if (jsonValue != null) { + inParmsHashValue.put(fieldName, GXutil.getHash(jsonValue.toJSonString())); + } + } + + public boolean isParmModified(String fieldName, Object value) { + IGxJSONSerializable jsonValue = (value instanceof IGxJSONSerializable) ? (IGxJSONSerializable) value : null; + if (value != null) { + if (!inParmsHashValue.containsKey(fieldName)) + return true; + return !GXutil.getHash(jsonValue.toJSonString()).equals(inParmsHashValue.get(fieldName)); + } + return true; + } +} diff --git a/gxweb/src/main/java/com/genexus/webpanels/GXMasterPage.java b/gxweb/src/main/java/com/genexus/webpanels/GXMasterPage.java index 6ab3dc59c..000ad05ed 100644 --- a/gxweb/src/main/java/com/genexus/webpanels/GXMasterPage.java +++ b/gxweb/src/main/java/com/genexus/webpanels/GXMasterPage.java @@ -1,6 +1,7 @@ package com.genexus.webpanels; import com.genexus.ModelContext; +import com.genexus.internet.HttpAjaxContext; import com.genexus.internet.HttpContext; public abstract class GXMasterPage extends GXWebPanel @@ -29,14 +30,14 @@ public GXMasterPage(int remoteHandle, ModelContext context) public void setDataArea( GXDataArea DataAreaObject) { this.DataAreaObject = DataAreaObject; - this.httpContext = DataAreaObject.getHttpContext(); + this.httpContext = (HttpAjaxContext) DataAreaObject.getHttpContext(); _ShowMPWhenPopUp = true; } public void setDataArea( GXDataArea DataAreaObject, boolean ShowMPWhenPopUp) { this.DataAreaObject = DataAreaObject; - this.httpContext = DataAreaObject.getHttpContext(); + this.httpContext = (HttpAjaxContext)DataAreaObject.getHttpContext(); _ShowMPWhenPopUp = ShowMPWhenPopUp; } diff --git a/gxweb/src/main/java/com/genexus/webpanels/GXStaticWebPanel.java b/gxweb/src/main/java/com/genexus/webpanels/GXStaticWebPanel.java deleted file mode 100644 index fae699b76..000000000 --- a/gxweb/src/main/java/com/genexus/webpanels/GXStaticWebPanel.java +++ /dev/null @@ -1,155 +0,0 @@ -package com.genexus.webpanels; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.*; - -import com.genexus.CommonUtil; -import com.genexus.ModelContext; -import com.genexus.PrivateUtilities; -import com.genexus.internet.HttpContext; -import com.genexus.internet.HttpContextNull; - -public abstract class GXStaticWebPanel extends GXWebPanel -{ - private static Hashtable visitedLinks = new Hashtable<>(); - private static Vector copyList = new Vector<>(); - - protected static String extension = "html"; - private String fileName ; - - public static final String STATIC_DIR = "genexus.staticweb.dir"; - public static final String STATIC_DYNURL = "genexus.staticweb.dynurl"; - public static final String STATIC_OVER = "genexus.staticweb.overwrite"; - public static final String STATIC_LINKS = "genexus.staticweb.links"; - public static final String STATIC_COPYDIR = "genexus.staticweb.copydir"; - - private static long startTime = System.currentTimeMillis(); - - HttpContext oldHttpContext; - - public GXStaticWebPanel(HttpContext httpContext) - { - super(httpContext); - } - - public GXStaticWebPanel(int remoteHandle, ModelContext context) - { - super(remoteHandle, context); - oldHttpContext = (HttpContext) context.getHttpContext(); - httpContext = new HttpContextNull(); - - context.setHttpContext(httpContext); - httpContext.setBuffered(false); - } - - protected void createFile(String fileName) - { - try - { - visitedLinks.put(fileName, ""); - ((HttpContext) context.getHttpContext()).setOutputStream(new BufferedOutputStream(new FileOutputStream(fileName))); - - addMessage("Creating " + fileName + "..."); - - this.fileName = fileName; - } - catch (IOException e) - { - throw new RuntimeException(e.getMessage()); - } - } - - public static byte copyFiles() - { - String outputDir = PrivateUtilities.addLastPathSeparator(PrivateUtilities.getSystemProperty(STATIC_COPYDIR, "")); - - if (!outputDir.trim().equals("")) - { - for (Enumeration en = copyList.elements(); en.hasMoreElements(); ) - { - String fileName = (String) en.nextElement(); - System.out.println("Copying " + getStaticDir() + fileName + " to " + outputDir + fileName); - PrivateUtilities.copyFileRetry(getStaticDir() + fileName, outputDir + fileName); - } - } - - visitedLinks = new Hashtable<>(); - - copyList.removeAllElements(); - return 0; - } - - protected void addFileToCopy(String file) - { - if (!PrivateUtilities.getSystemProperty(STATIC_COPYDIR, "").equals("")) - copyList.addElement(file); - } - - protected int processParameters(String args[]) - { - return 0; - } - - public static byte isStaticOverwrite() - { - return PrivateUtilities.getSystemProperty(STATIC_OVER, "true").equals("true")?(byte) 1:0; - } - - public static byte isExpandLinks() - { - return PrivateUtilities.getSystemProperty(STATIC_LINKS, "true").equals("true")?(byte) 1:0; - } - - public static byte isStaticCreated(String link) - { - return visitedLinks.get(link) == null? (byte) 0 :(byte) 1; - } - - protected byte wasVisited(String link) - { - if ( (PrivateUtilities.getSystemProperty(STATIC_OVER, "true").equals("false") && new File(getStaticDir() + link).exists()) || - (PrivateUtilities.getSystemProperty(STATIC_LINKS, "true").equals("false")) ) - { - return 1; - } - - return visitedLinks.get(link) == null? 0 :(byte) 1; - } - - protected static String getTime() - { - Date d = new Date(); - Calendar calendar = GregorianCalendar.getInstance(); - calendar.setTime(d); - return CommonUtil.padl(""+ calendar.get(Calendar.HOUR_OF_DAY), 2, "0") + ":" + - CommonUtil.padl(""+ calendar.get(Calendar.MINUTE), 2, "0") + ":" + - CommonUtil.padl(""+ calendar.get(Calendar.SECOND), 2, "0"); - } - - protected String encodeStaticParm(String parm) - { - return CommonUtil.URLEncode(parm, "UTF8"); - } - - public static String getStaticDir() - { - return PrivateUtilities.addLastPathSeparator(WebUtils.getSystemProperty(STATIC_DIR)); - } - - private void addMessage(String msg) - { - System.out.println(msg); - } - - protected void cleanup() - { - if (isStaticGeneration) - addMessage("Closing " + fileName + "..."); - - super.cleanup(); - context.setHttpContext(oldHttpContext); - } -} \ No newline at end of file diff --git a/gxweb/src/main/java/com/genexus/webpanels/GXUserControl.java b/gxweb/src/main/java/com/genexus/webpanels/GXUserControl.java index 9ae3ff866..78cacdf48 100644 --- a/gxweb/src/main/java/com/genexus/webpanels/GXUserControl.java +++ b/gxweb/src/main/java/com/genexus/webpanels/GXUserControl.java @@ -1,6 +1,7 @@ package com.genexus.webpanels; + import com.genexus.ModelContext; -import com.genexus.internet.HttpContext; +import com.genexus.internet.HttpAjaxContext; import com.genexus.usercontrols.UserControlFactoryImpl; import com.genexus.util.GXMap; @@ -32,13 +33,13 @@ public void setProperty(String propertyName, Object propertyValue) } public void sendProperty(ModelContext context, String componentPrefix, boolean isMasterPage, String internalName, String propertyName, String propertyValue) { - ((HttpContext)context.getHttpContext()).ajax_rsp_assign_uc_prop(componentPrefix, isMasterPage, internalName, propertyName, propertyValue); + ((HttpAjaxContext)context.getHttpContext()).ajax_rsp_assign_uc_prop(componentPrefix, isMasterPage, internalName, propertyName, propertyValue); setProperty(propertyName, propertyValue); } public void render(ModelContext context, String controlType, String internalName, String htmlId) { propertyBag.put("ContainerName", htmlId); String ucServerContent = UserControlFactoryImpl.getInstance().renderControl(controlType, internalName, propertyBag); - ((HttpContext)context.getHttpContext()).writeText( String.format("
%s
", htmlId, ucServerContent)); + ((HttpAjaxContext)context.getHttpContext()).writeText( String.format("
%s
", htmlId, ucServerContent)); } } diff --git a/gxweb/src/main/java/com/genexus/webpanels/GXWebGrid.java b/gxweb/src/main/java/com/genexus/webpanels/GXWebGrid.java index f7d3fc7a2..45c32ec30 100644 --- a/gxweb/src/main/java/com/genexus/webpanels/GXWebGrid.java +++ b/gxweb/src/main/java/com/genexus/webpanels/GXWebGrid.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import com.genexus.ModelContext; +import com.genexus.internet.HttpAjaxContext; import com.genexus.internet.HttpContext; import com.genexus.internet.IGxJSONAble; import com.genexus.common.interfaces.IGXWebGrid; @@ -62,7 +63,7 @@ public void setWritingTableContent(boolean writingTableContent) public void SetWrapped(int wrapped) { - HttpContext httpContext = (HttpContext) this.context.getHttpContext(); + HttpAjaxContext httpContext = (HttpAjaxContext) context.getHttpContext(); this.wrapped = (wrapped==1); if (!this.wrapped) { diff --git a/gxweb/src/main/java/com/genexus/webpanels/GXWebObjectBase.java b/gxweb/src/main/java/com/genexus/webpanels/GXWebObjectBase.java new file mode 100644 index 000000000..ba4b717e3 --- /dev/null +++ b/gxweb/src/main/java/com/genexus/webpanels/GXWebObjectBase.java @@ -0,0 +1,288 @@ +package com.genexus.webpanels; + +import java.sql.SQLException; +import org.apache.commons.lang.StringUtils; + +import com.genexus.*; +import com.genexus.configuration.ConfigurationManager; +import com.genexus.diagnostics.core.ILogger; +import com.genexus.diagnostics.core.LogManager; +import com.genexus.diagnostics.GXDebugInfo; +import com.genexus.diagnostics.GXDebugManager; +import com.genexus.internet.HttpAjaxContext; +import com.genexus.internet.GXInternetConstants; +import com.genexus.internet.HttpContext; +import com.genexus.ModelContext; +import com.genexus.security.GXSecurityProvider; + +public abstract class GXWebObjectBase extends GXObjectBase implements IErrorHandler, GXInternetConstants, ISubmitteable +{ + public static final ILogger logger = LogManager.getLogger(GXWebObjectBase.class); + + private static String GX_SPA_GXOBJECT_RESPONSE_HEADER = "X-GXOBJECT"; + protected static String GX_SPA_MASTERPAGE_HEADER = "X-SPA-MP"; + protected static String GX_AJAX_MULTIPART_ID = "GXAjaxMultipart"; + + protected boolean IntegratedSecurityEnabled() { return false;} + protected int IntegratedSecurityLevel() { return 0;} + protected String IntegratedSecurityPermissionPrefix() {return "";} + + protected HttpAjaxContext httpContext; + + public abstract void webExecute(); + public abstract boolean isMasterPage(); + + public GXWebObjectBase() + { + } + + /** + * Este constructor se usa cuando aun no tengo un ModelContext ni remoteHandle, pero + * si tengo el HttpContext. Basicamente es el punto de entrada en los servlets. + */ + public GXWebObjectBase(HttpContext httpContext, Class contextClass) + { + init(httpContext, contextClass); + castHttpContext(); + } + + /** + * Este constructor se usa cuando aun no tengo un ModelContext ni remoteHandle, pero + * si tengo el HttpContext. Basicamente es el punto de entrada en los servlets. + */ + public GXWebObjectBase(HttpContext httpContext) + { + super(httpContext); + castHttpContext(); + } + + /** + * Este constructor se usa cuando ya tengo un ModelContext y remoteHandle. + * Basicamente es el punto de entrada para webcomponents, webwrappers, etc. + */ + public GXWebObjectBase(int remoteHandle, ModelContext context) + { + super(remoteHandle, context); + castHttpContext(); + } + + private void castHttpContext() { + this.httpContext = (HttpAjaxContext) super.httpContext; + } + /*** + * Return the DefaultTheme for all WebPanels and Transactions. + * @return + */ + @SuppressWarnings("unused") + protected void initializeTheme() { + this.httpContext.setDefaultTheme(ConfigurationManager.getValue("Theme")); + } + + protected boolean CheckCmpSecurityAccess() + { + boolean[] flag = new boolean[]{false}; + boolean[] permissionFlag = new boolean[]{false}; + String permissionPrefix = IntegratedSecurityPermissionPrefix(); + com.genexus.internet.HttpRequest req = ((HttpContext)ModelContext.getModelContext().getHttpContext()).getHttpRequest(); + if (req == null) + return false; + String reqUrl = req.getRequestURL(); + ModelContext modelContext = ModelContext.getModelContext(getClass()); + if (IntegratedSecurityLevel() == SECURITY_LOW || IntegratedSecurityLevel() == SECURITY_GXOBJECT) + { + GXSecurityProvider.getInstance().checksession(-2, modelContext, reqUrl, permissionFlag); + } + if (IntegratedSecurityLevel() != SECURITY_LOW && IntegratedSecurityLevel() != SECURITY_GXOBJECT) + { + GXSecurityProvider.getInstance().checksessionprm(-2, modelContext, reqUrl, permissionPrefix, flag, permissionFlag); + } + return permissionFlag[0]; + } + + protected void sendCacheHeaders() + { + if (httpContext.isSpaRequest()) { + httpContext.getResponse().setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + httpContext.getResponse().setHeader("Pragma", "no-cache"); + httpContext.getResponse().setHeader("Expires", "0"); + } + else { + super.sendCacheHeaders(); + } + } + + protected void sendAdditionalHeaders() + { + if (httpContext.isSpaRequest()) + sendSpaHeaders(); + if (httpContext.getBrowserType() == HttpContextWeb.BROWSER_IE && !httpContext.isPopUpObject()) + { + String IECompMode = context.getClientPreferences().getIE_COMPATIBILITY(); + if (IECompMode.equals("EmulateIE7") && !httpContext.getBrowserVersion().startsWith("8") ) + return; + if (StringUtils.isNotEmpty(IECompMode)) + httpContext.getResponse().addHeader("X-UA-Compatible", "IE=" + IECompMode); + } + } + + protected void sendSpaHeaders() + { + httpContext.getResponse().setHeader(GX_SPA_GXOBJECT_RESPONSE_HEADER, getPgmname().toLowerCase()); + } + + public void doExecute() throws Exception + { + try + { + if (isSpaRequest() && !isSpaSupported()) + { + httpContext.sendResponseStatus(httpContext.SPA_NOT_SUPPORTED_STATUS_CODE, "SPA not supported by the object"); + } + else + { + preExecute(); + sendCacheHeaders(); + webExecute(); + sendAdditionalHeaders(); + httpContext.flushStream(); + } + } + catch (Throwable e) + { + cleanup(); // Antes de hacer el rethrow, hago un cleanup del objeto + throw e; + } + finally + { + finallyCleanup(); + } + } + + public void executeUsercontrolMethod(String CmpContext, boolean IsMasterPage, String containerName, String methodName, String input, Object[] parms) + { + httpContext.executeUsercontrolMethod(CmpContext, IsMasterPage, containerName, methodName, input, parms); + } + + public void setExternalObjectProperty(String CmpContext, boolean IsMasterPage, String containerName, String propertyName, Object value) + { + httpContext.setExternalObjectProperty(CmpContext, IsMasterPage, containerName, propertyName, value); + } + + public void executeExternalObjectMethod(String CmpContext, boolean IsMasterPage, String containerName, String methodName, Object[] parms, boolean isEvent) + { + httpContext.executeExternalObjectMethod(CmpContext, IsMasterPage, containerName, methodName, parms, isEvent); + } + + /** + * @Hack: Tenemos que ejecutar el submit esto en otro thread, pues el submit es asincrono, + * pero si creamos en el fuente generado el codigo del nuevo thread, se va a crear un + * archivo nuevo xxx$N.class al compilar el xxx, que deberia ser tratado especialmente + * en el makefile (copiado al directorio de servlets, etc); asi que delegamos la + * creacion del thread a la gxclassr donde se llama al metodo a ser ejecutado + * Adem�s ahora manejamos un pool de threads en el submit + */ + public void callSubmit(final int id, Object [] submitParms) + { + com.genexus.util.SubmitThreadPool.submit(this, id, submitParms, context.submitCopy()); + } + + /** Este metodo es redefinido por la clase GX generada cuando hay submits + */ + public void submit(int id, Object [] submitParms, ModelContext ctx){ + } + public void submit(int id, Object [] submitParms){ + } + public void submitReorg(int id, Object [] submitParms) throws SQLException{ + } + + public String getPgmname() + { + return ""; + } + + public String getPgmdesc() + { + return ""; + } + + protected boolean isSpaRequest() + { + return httpContext.isSpaRequest(); + } + + protected boolean isSpaRequest(boolean ignoreFlag) + { + return httpContext.isSpaRequest(ignoreFlag); + } + + protected boolean isSpaSupported() + { + return true; + } + + + protected void validateSpaRequest() + { + // SPA is disabled for objects without master page. However, SPA response headers are sent anyway, so the client side + // replaces the full content using AJAX. + if (isSpaRequest()) + { + httpContext.disableSpaRequest(); + sendSpaHeaders(); + } + } + + protected String getPgmInstanceId(String cmpCtx) + { + return String.format("%s%s", cmpCtx, this.getPgmname().toUpperCase()); + } + + private GXDebugInfo dbgInfo = null; + protected void trkCleanup() + { + if(dbgInfo != null) + dbgInfo.onCleanup(); + } + + protected void initialize(int objClass, int objId, int dbgLines, long hash) + { + dbgInfo = GXDebugManager.getInstance().getDbgInfo(context, objClass, objId, dbgLines, hash); + } + + protected void trk(int lineNro) + { + if(dbgInfo != null) + dbgInfo.trk(lineNro); + } + + protected void trk(int lineNro, int lineNro2) + { + if(dbgInfo != null) + dbgInfo.trk(lineNro, lineNro2); + } + + protected void trkrng(int lineNro, int lineNro2) + { + trkrng(lineNro, 0, lineNro2, 0); + } + + protected void trkrng(int lineNro, int colNro, int lineNro2, int colNro2) + { + if(dbgInfo != null) + dbgInfo.trkRng(lineNro, colNro, lineNro2, colNro2); + } + + protected void callWebObject(String url) + { + httpContext.wjLoc = url; + } + + + public void popup(String url) + { + } + + public void popup(String url, Object[] returnParms) + { + } +} diff --git a/gxweb/src/main/java/com/genexus/webpanels/GXWebPanel.java b/gxweb/src/main/java/com/genexus/webpanels/GXWebPanel.java index 8fa09a8ad..5a1799ab0 100644 --- a/gxweb/src/main/java/com/genexus/webpanels/GXWebPanel.java +++ b/gxweb/src/main/java/com/genexus/webpanels/GXWebPanel.java @@ -4,6 +4,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.lang.reflect.*; +import java.math.BigDecimal; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; @@ -15,14 +16,18 @@ import com.genexus.db.UserInformation; import com.genexus.diagnostics.core.ILogger; import com.genexus.diagnostics.core.LogManager; +import com.genexus.internet.HttpAjaxContext; import com.genexus.internet.HttpContext; import com.genexus.internet.IGxJSONSerializable; import com.genexus.security.GXSecurityProvider; +import com.genexus.security.web.SecureTokenHelper; +import com.genexus.security.web.WebSecurityHelper; import json.org.json.IJsonFormattable; import json.org.json.JSONArray; import json.org.json.JSONException; import json.org.json.JSONObject; +import org.apache.commons.lang.StringUtils; class DataIntegrityException extends Exception { @@ -214,6 +219,7 @@ protected void setEventMetadata(String eventName, String metadata) { protected void initState(ModelContext context, UserInformation ui) { super.initState(context, ui); + httpContext = (HttpAjaxContext) context.getHttpContext(); staticDir = context.getClientPreferences().getWEB_STATIC_DIR(); @@ -433,7 +439,7 @@ public void doExecute() throws Exception { if (isSpaRequest() && !isSpaSupported()) { - httpContext.sendResponseStatus(SPA_NOT_SUPPORTED_STATUS_CODE, "SPA not supported by the object"); + httpContext.sendResponseStatus(HttpContext.SPA_NOT_SUPPORTED_STATUS_CODE, "SPA not supported by the object"); } else { @@ -446,7 +452,6 @@ public void doExecute() throws Exception } catch (Throwable e) { - handleException(e.getClass().getName(), e.getMessage(), CommonUtil.getStackTraceAsString(e)); cleanup(); // Antes de hacer el rethrow, hago un cleanup del objeto throw e; } @@ -475,13 +480,13 @@ public void webAjaxEvent() throws Exception { else httpContext.setContentType("application/json"); - if (!redirect((HttpContextWeb) httpContext)){ - ((HttpContextWeb)httpContext).sendFinalJSONResponse(jsonResponse); + if (!redirect(httpContext)){ + httpContext.sendFinalJSONResponse(jsonResponse); } httpContext.setResponseCommited(); } - private boolean redirect(HttpContextWeb context) + private boolean redirect(HttpAjaxContext context) { if (context.wjLoc!=null && !context.wjLoc.equals("") ) { @@ -1214,4 +1219,223 @@ public void newWindow(IGXWindow win) { WebFrontendUtils.newWindow(win, httpContext); } + protected String getSecureSignedToken(String cmpCtx, Object Value) + { + return getSecureSignedToken(cmpCtx, serialize(Value)); + } + + protected String getSecureSignedToken(String cmpCtx, boolean Value) + { + return getSecureSignedToken(cmpCtx, Boolean.toString(Value)); + } + + protected String getSecureSignedToken(String cmpCtx, com.genexus.xml.GXXMLSerializable Value) + { + return getSecureSignedToken(cmpCtx, Value.toJSonString(false)); + } + + protected String getSecureSignedToken(String cmpCtx, String Value) + { + return WebSecurityHelper.sign(getPgmInstanceId(cmpCtx), "", Value, SecureTokenHelper.SecurityMode.Sign, getSecretKey()); + } + + protected boolean verifySecureSignedToken(String cmpCtx, int Value, String picture, String token){ + return verifySecureSignedToken(cmpCtx, serialize(Value, picture), token); + } + + protected boolean verifySecureSignedToken(String cmpCtx, short Value, String picture, String token){ + return verifySecureSignedToken(cmpCtx, serialize(Value, picture), token); + } + + protected boolean verifySecureSignedToken(String cmpCtx, long Value, String picture, String token){ + return verifySecureSignedToken(cmpCtx, serialize(Value, picture), token); + } + + protected boolean verifySecureSignedToken(String cmpCtx, double Value, String picture, String token){ + return verifySecureSignedToken(cmpCtx, serialize(Value, picture), token); + } + + protected boolean verifySecureSignedToken(String cmpCtx, Object Value, String picture, String token){ + return verifySecureSignedToken(cmpCtx, serialize(Value, picture), token); + } + + protected boolean verifySecureSignedToken(String cmpCtx, Object Value, String token){ + return verifySecureSignedToken(cmpCtx, serialize(Value), token); + } + + protected boolean verifySecureSignedToken(String cmpCtx, boolean Value, String token){ + return verifySecureSignedToken(cmpCtx, Boolean.toString(Value), token); + } + + protected boolean verifySecureSignedToken(String cmpCtx, com.genexus.xml.GXXMLSerializable Value, String token){ + return verifySecureSignedToken(cmpCtx, Value.toJSonString(false), token); + } + + protected boolean verifySecureSignedToken(String cmpCtx, String value, String token){ + return WebSecurityHelper.verify(getPgmInstanceId(cmpCtx), "", value, token, getSecretKey()); + } + + protected boolean validateObjectAccess(String cmpCtx) + { + if (this.httpContext.useSecurityTokenValidation()){ + String jwtToken = this.httpContext.getHeader("X-GXAUTH-TOKEN"); + jwtToken = (StringUtils.isBlank(jwtToken) && this.httpContext.isMultipartContent())? + this.httpContext.cgiGet("X-GXAUTH-TOKEN"): + jwtToken; + + if (!verifySecureSignedToken(cmpCtx, "", jwtToken)) + { + this.httpContext.sendResponseStatus(401, "Not Authorized"); + if (this.httpContext.getBrowserType() != HttpContextWeb.BROWSER_INDEXBOT) { + logger.warn(String.format("Validation security token failed for program: %s - '%s'", getPgmInstanceId(cmpCtx), jwtToken )); + } + return false; + } + } + return true; + } + + private static String GX_SEC_TOKEN_PREFIX = "GX_AUTH"; + + //Generates only with FullAjax and GAM disabled. + public void sendSecurityToken(String cmpCtx) + { + if (this.httpContext.wjLoc == null || this.httpContext.wjLoc.equals("") ) + { + this.httpContext.ajax_rsp_assign_hidden(getSecurityObjTokenId(cmpCtx), getObjectAccessWebToken(cmpCtx)); + } + } + + private String getSecurityObjTokenId(String cmpCtx) + { + return GX_SEC_TOKEN_PREFIX + "_" + cmpCtx + getPgmname().toUpperCase(); + } + + private String getObjectAccessWebToken(String cmpCtx) + { + return WebSecurityHelper.sign(getPgmInstanceId(cmpCtx), "", "", SecureTokenHelper.SecurityMode.Sign, getSecretKey()); + } + + private String getSecretKey() + { + //Some random SALT that is different in every GX App installation. Better if changes over time + String hashSalt = com.genexus.Application.getClientContext().getClientPreferences().getREORG_TIME_STAMP(); + return WebUtils.getEncryptionKey(this.context, "") + hashSalt; + } + + private String serialize(double Value, String Pic) + { + return serialize(localUtil.format(Value, Pic)); + } + + private String serialize(int Value, String Pic) + { + return serialize(localUtil.format(Value, Pic)); + } + + private String serialize(short Value, String Pic) + { + return serialize(localUtil.format(Value, Pic)); + } + + private String serialize(long Value, String Pic) + { + return serialize(localUtil.format(Value, Pic)); + } + + private String serialize(Object Value, String Pic) + { + if (!StringUtils.isBlank(Pic)) { + if (Value instanceof Byte) + { + return serialize(localUtil.format(((Byte)Value).intValue(), Pic)); + } + else + { + if (Value instanceof BigDecimal) + { + return serialize(localUtil.format((BigDecimal)Value, Pic)); + } + else + { + if (Value instanceof Integer) + { + return serialize(localUtil.format(((Integer)Value).intValue(), Pic)); + } + else + { + if (Value instanceof Short) + { + return serialize(localUtil.format(((Short)Value).shortValue(), Pic)); + } + else + { + if (Value instanceof Long) + { + return serialize(localUtil.format(((Long)Value).longValue(), Pic)); + } + else + { + if (Value instanceof Double) + { + return serialize(localUtil.format(((Double)Value).doubleValue(), Pic)); + } + else + { + if (Value instanceof Float) + { + return serialize(localUtil.format(((Float)Value).floatValue(), Pic)); + } + else + { + if (Value instanceof java.util.Date) + { + return serialize(localUtil.format((java.util.Date)Value, Pic)); + } + else + { + if (Value instanceof String) + { + return serialize(localUtil.format((String)Value, Pic)); + } + } + } + } + } + } + } + } + } + } + return serialize(Value); + } + + private String serialize(Object Value) { + String strValue = ""; + if (Value instanceof BigDecimal){ + strValue = Value.toString(); + if (strValue.indexOf(".") != -1) + strValue = strValue.replaceAll("0*$", "").replaceAll("\\.$", ""); + } + else{ + if (Value instanceof java.util.Date){ + strValue = " / / 00:00:00"; + if (!Value.equals(CommonUtil.resetTime( CommonUtil.nullDate()))) { + strValue = new java.text.SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Value); + } + } + else{ + if (Value instanceof com.genexus.xml.GXXMLSerializable) { + strValue = ((com.genexus.xml.GXXMLSerializable) Value).toJSonString(false); + } + else if (Value instanceof IGxJSONSerializable) { + strValue = ((IGxJSONSerializable) Value).toJSonString(); + } + else { + strValue = Value.toString(); + } + } + } + return strValue; + } } diff --git a/gxweb/src/main/java/com/genexus/webpanels/GXWebPanelStub.java b/gxweb/src/main/java/com/genexus/webpanels/GXWebPanelStub.java new file mode 100644 index 000000000..d2c28140d --- /dev/null +++ b/gxweb/src/main/java/com/genexus/webpanels/GXWebPanelStub.java @@ -0,0 +1,33 @@ +package com.genexus.webpanels; + +import com.genexus.ModelContext; +import com.genexus.internet.HttpAjaxContext; +import com.genexus.internet.HttpContext; +import com.genexus.servlet.ServletException; +import com.genexus.servlet.http.IHttpServletRequest; +import com.genexus.servlet.http.IHttpServletResponse; + +public abstract class GXWebPanelStub extends GXWebObjectStub{ + + public GXWebPanelStub() + { + } + + public GXWebPanelStub(int remoteHandle , ModelContext context) + { + super(remoteHandle, context); + } + + protected void callExecute(String method, IHttpServletRequest req, IHttpServletResponse res) throws ServletException { + HttpContext httpContext = null; + try + { + httpContext = new HttpAjaxContext(method, req, res, getWrappedServletContext()); + super.callExecute(method, req, res, httpContext); + } + catch (Exception e) + { + handleException(e, httpContext); + } + } +} diff --git a/gxweb/src/main/java/com/genexus/webpanels/GXWebRow.java b/gxweb/src/main/java/com/genexus/webpanels/GXWebRow.java index cc2ac580a..a53e39974 100644 --- a/gxweb/src/main/java/com/genexus/webpanels/GXWebRow.java +++ b/gxweb/src/main/java/com/genexus/webpanels/GXWebRow.java @@ -4,6 +4,7 @@ import com.genexus.CommonUtil; import com.genexus.ModelContext; +import com.genexus.internet.HttpAjaxContext; import com.genexus.internet.HttpContext; import com.genexus.internet.IGxJSONAble; import com.genexus.common.interfaces.IGXWebRow; @@ -80,9 +81,9 @@ public void AddColumnProperties(String controlType, int valueIndex, boolean valu this.firstRowAdded = true; return; } - ((HttpContext)context.getHttpContext()).drawingGrid = true; + ((HttpAjaxContext)context.getHttpContext()).drawingGrid = true; GXWebStdMethods.callMethod(this.context, controlType, props, _parentGrid.getGridName()); - ((HttpContext)context.getHttpContext()).drawingGrid = false; + ((HttpAjaxContext)context.getHttpContext()).drawingGrid = false; if (!this._parentGrid.isFreestyle()) { GXWebStdMethods.closeTag(this.context, "cell"); diff --git a/gxweb/src/main/java/com/genexus/webpanels/GXWebStdMethods.java b/gxweb/src/main/java/com/genexus/webpanels/GXWebStdMethods.java index 36756ed9c..b5bbe9755 100644 --- a/gxweb/src/main/java/com/genexus/webpanels/GXWebStdMethods.java +++ b/gxweb/src/main/java/com/genexus/webpanels/GXWebStdMethods.java @@ -3,7 +3,7 @@ import java.lang.reflect.Method; import com.genexus.ModelContext; -import com.genexus.internet.HttpContext; +import com.genexus.internet.HttpAjaxContext; public class GXWebStdMethods { @@ -67,7 +67,7 @@ public static void callMethod(ModelContext context, String controlType, Object[] Class webStdFuncs = getWebStdClass(context); if (webStdFuncs != null) { - HttpContext httpContext = (HttpContext) context.getHttpContext(); + HttpAjaxContext httpContext = (HttpAjaxContext) context.getHttpContext(); if (httpContext != null) { boolean addCallerPgm = true; @@ -202,7 +202,7 @@ private static boolean tagHasStdMethod(String tag) public static void openTag(ModelContext context, String tag, Object[] parms) { - HttpContext httpContext = (HttpContext) context.getHttpContext(); + HttpAjaxContext httpContext = (HttpAjaxContext) context.getHttpContext(); if (tag.equalsIgnoreCase("row")) { httpContext.writeTextNL(""); @@ -230,7 +230,7 @@ else if (tag.equalsIgnoreCase("usercontrol")) public static void closeTag(ModelContext context, String tag) { - HttpContext httpContext = (HttpContext) context.getHttpContext(); + HttpAjaxContext httpContext = (HttpAjaxContext) context.getHttpContext(); if (tag.equalsIgnoreCase("table")) { httpContext.writeTextNL(""); diff --git a/gxweb/src/main/java/com/genexus/webpanels/IDynAjaxEventContext.java b/gxweb/src/main/java/com/genexus/webpanels/IDynAjaxEventContext.java new file mode 100644 index 000000000..4d3de251b --- /dev/null +++ b/gxweb/src/main/java/com/genexus/webpanels/IDynAjaxEventContext.java @@ -0,0 +1,11 @@ +package com.genexus.webpanels; + +public interface IDynAjaxEventContext +{ + void Clear(); + void ClearParmsMetadata(); + boolean isInputParm(String key); + void SetParmHash(String fieldName, Object value); + boolean isParmModified(String fieldName, Object value); + +} \ No newline at end of file diff --git a/gxweb/src/main/java/com/genexus/webpanels/NoneMasterPage.java b/gxweb/src/main/java/com/genexus/webpanels/NoneMasterPage.java index f38de0ec2..88fc1aa3d 100644 --- a/gxweb/src/main/java/com/genexus/webpanels/NoneMasterPage.java +++ b/gxweb/src/main/java/com/genexus/webpanels/NoneMasterPage.java @@ -1,15 +1,7 @@ -/* - File: nonemasterpage_impl - Description: None Master Page - Author: GeneXus Java Generator version 15_0_12-126415 - Generated on: April 26, 2019 17:13:47.18 - Program type: Callable routine - Main DBMS: SQL Server -*/ package com.genexus.webpanels; + import com.genexus.*; -import com.genexus.internet.HttpContext; -import com.genexus.webpanels.*; +import com.genexus.internet.HttpAjaxContext; public final class NoneMasterPage extends GXMasterPage { @@ -206,7 +198,7 @@ public void wb0A0( ) wbLoad = true ; } - public static void classAttribute( HttpContext httpContext , + public static void classAttribute( HttpAjaxContext httpContext , String sClass ) { if ( ! (GXutil.strcmp("", sClass)==0) ) @@ -218,7 +210,7 @@ public static void classAttribute( HttpContext httpContext , } - public static void gx_div_start( HttpContext httpContext , + public static void gx_div_start( HttpAjaxContext httpContext , String sInternalName , int nVisible , int nWidth , @@ -284,7 +276,7 @@ public static void gx_div_start( HttpContext httpContext , } } - public static void styleAttribute( HttpContext httpContext , + public static void styleAttribute( HttpAjaxContext httpContext , String sStyle ) { if ( ! (GXutil.strcmp("", sStyle)==0) ) @@ -295,7 +287,7 @@ public static void styleAttribute( HttpContext httpContext , } } - public static void gx_div_end( HttpContext httpContext , + public static void gx_div_end( HttpAjaxContext httpContext , String sAlign , String sVAlign , String sHtmlTag ) @@ -311,7 +303,7 @@ public static void gx_div_end( HttpContext httpContext , httpContext.writeText( "") ; } - public static boolean gx_redirect( HttpContext httpContext ) + public static boolean gx_redirect( HttpAjaxContext httpContext ) { if ( httpContext.willRedirect( ) ) { diff --git a/gxweb/src/main/java/com/genexus/webpanels/WebFrontendUtils.java b/gxweb/src/main/java/com/genexus/webpanels/WebFrontendUtils.java index e76f0b4b2..7e0ce40f4 100644 --- a/gxweb/src/main/java/com/genexus/webpanels/WebFrontendUtils.java +++ b/gxweb/src/main/java/com/genexus/webpanels/WebFrontendUtils.java @@ -2,7 +2,10 @@ import com.genexus.*; import com.genexus.common.interfaces.IGXWindow; +import com.genexus.internet.HttpAjaxContext; import com.genexus.internet.HttpContext; +import com.genexus.reports.GXReport; +import com.genexus.reports.GXReportText; public class WebFrontendUtils { @@ -65,4 +68,14 @@ public static void newWindow(IGXWindow win, HttpContext httpContext) { ((HttpContextWeb) httpContext).redirect_impl(win.getUrl(), win); } + public static void printReportAtClient(GXProcedure reportClass, HttpContext httpContext, String printerRule) { + String fileName; + if (reportClass instanceof GXReport) + fileName = ((GXReport)reportClass).setPrintAtClient(); + else + fileName = ((GXReportText)reportClass).setPrintAtClient(); + if (httpContext != null) + ((HttpAjaxContext) httpContext).printReportAtClient(fileName, printerRule); + } + } \ No newline at end of file diff --git a/java/src/main/java/com/genexus/GXObjectBase.java b/java/src/main/java/com/genexus/GXObjectBase.java new file mode 100644 index 000000000..92bcf80ab --- /dev/null +++ b/java/src/main/java/com/genexus/GXObjectBase.java @@ -0,0 +1,203 @@ +package com.genexus; + +import com.genexus.db.Namespace; +import com.genexus.db.UserInformation; +import com.genexus.diagnostics.core.ILogger; +import com.genexus.diagnostics.core.LogManager; +import com.genexus.internet.HttpContext; +import com.genexus.webpanels.HttpContextWeb; +import com.genexus.webpanels.WebApplicationStartup; + +public abstract class GXObjectBase extends GXRestServiceWrapper{ + public static final ILogger logger = LogManager.getLogger(GXObjectBase.class); + + protected ModelContext context; + protected HttpContext httpContext; + protected LocalUtil localUtil; + protected int remoteHandle = -1; + protected UserInformation ui; + + protected static final int SECURITY_GXOBJECT = 3; + protected static final int SECURITY_HIGH = 2; + protected static final int SECURITY_LOW = 1; + + public abstract void webExecute(); + + public GXObjectBase() { + } + + /** + * Este constructor se usa cuando aun no tengo un ModelContext ni remoteHandle, pero + * si tengo el HttpContext. Basicamente es el punto de entrada en los servlets. + */ + public GXObjectBase(HttpContext httpContext) { + init(httpContext, getClass()); + } + + /** + * Este constructor se usa cuando ya tengo un ModelContext y remoteHandle. + * Basicamente es el punto de entrada para webcomponents, webwrappers, etc. + */ + public GXObjectBase(int remoteHandle, ModelContext context) { + this.context = context; + + ui = (UserInformation) GXObjectHelper.getUserInformation(context, remoteHandle); + this.remoteHandle = ui.getHandle(); + + initState(context, ui); + } + + protected void init(HttpContext httpContext, Class contextClass) { + this.context = new ModelContext(contextClass); + context.setHttpContext(httpContext); + + new WebApplicationStartup().init(contextClass, httpContext); + + ApplicationContext.getInstance().setPoolConnections(!Namespace.createNamespace(context).isRemoteGXDB()); + + ui = (UserInformation) GXObjectHelper.getUserInformation(context, -1); + ui.setAutoDisconnect(false); + remoteHandle = ui.getHandle(); + + initState(context, ui); + } + + protected void initState(ModelContext context, UserInformation ui) { + localUtil = ui.getLocalUtil(); + httpContext = (HttpContext) context.getHttpContext(); + httpContext.setContext( context); + httpContext.setCompression(getCompressionMode()); + } + + protected boolean getCompressionMode() { + return context.getClientPreferences().getCOMPRESS_HTML(); + } + + public int setLanguage(String language) { + int res = GXutil.setLanguage(language, context, ui); + localUtil = ui.getLocalUtil(); + return res; + } + + public int setTheme(String theme) { + int res = GXutil.setTheme(theme, context); + return res; + } + + public void doExecute() throws Exception + { + try + { + preExecute(); + sendCacheHeaders(); + webExecute(); + httpContext.flushStream(); + } + catch (Throwable e) + { + cleanup(); + throw e; + } + finally + { + finallyCleanup(); + } + } + + protected void preExecute() + { + httpContext.responseContentType("text/html"); //default Content-Type + httpContext.initClientId(); + } + + protected void sendCacheHeaders() + { + httpContext.getResponse().addDateHeader("Expires", 0); + httpContext.getResponse().addDateHeader("Last-Modified", 0); + if (this instanceof GXWebReport && ((GXWebReport)this).getOutputType()==GXWebReport.OUTPUT_PDF) { + httpContext.getResponse().addHeader("Cache-Control", "must-revalidate,post-check=0, pre-check=0"); + //Estos headers se setean por un bug de Reader X que hace que en IE no se vea el reporte cuando esta embebido, + //solo se ve luego de hacer F5. + } + else { + httpContext.getResponse().addHeader("Cache-Control", "max-age=0, no-cache, no-store, must-revalidate"); + } + } + + protected void finallyCleanup() { + try { + if (ui!= null) + ui.disconnect(); + } + catch (java.sql.SQLException e) { + logger.error("Exception while disconecting ", e); + } + if (httpContext != null) + httpContext.cleanup(); + cleanModelContext(); + } + + private void cleanModelContext() { + try { + ((ThreadLocal)com.genexus.CommonUtil.threadCalendar).getClass().getMethod("remove", new Class[0]).invoke(com.genexus.CommonUtil.threadCalendar, (java.lang.Object[])new Class[0]); + ((ThreadLocal)com.genexus.ModelContext.threadModelContext).getClass().getMethod("remove", new Class[0]).invoke(com.genexus.ModelContext.threadModelContext, (java.lang.Object[])new Class[0]); + } + catch (NoSuchMethodException e) { + logger.error("cleanModelContext", e); + } + catch (IllegalAccessException e) { + logger.error("cleanModelContext", e); + } + catch (java.lang.reflect.InvocationTargetException e) { + logger.error("cleanModelContext " + e.getTargetException(), e); + } + } + + protected void cleanup() { + Application.cleanupConnection(remoteHandle); + } + + public HttpContext getHttpContext() { + return httpContext; + } + + public void setHttpContext(HttpContext httpContext) { + this.httpContext = (HttpContextWeb) httpContext; + } + + public ModelContext getModelContext() { + return context; + } + + public int getRemoteHandle() { + return remoteHandle; + } + + public ModelContext getContext() { + return context; + } + + public void handleError() { + new DefaultErrorHandler().handleError(context, remoteHandle); + } + + public Object getParm( Object[] parms, int index) + { + return parms[index]; + } + + protected String formatLink(String jumpURL) + { + return formatLink(jumpURL, new String[]{}); + } + + protected String formatLink(String jumpURL, String[] parms) + { + return formatLink(jumpURL, parms, new String[]{}); + } + + protected String formatLink(String jumpURL, String[] parms, String[] parmsName) + { + return URLRouter.getURLRoute(jumpURL, parms, parmsName, httpContext.getRequest().getContextPath(), context.getPackageName()); + } +} diff --git a/java/src/main/java/com/genexus/GXWebReport.java b/java/src/main/java/com/genexus/GXWebReport.java new file mode 100644 index 000000000..d6f084b6d --- /dev/null +++ b/java/src/main/java/com/genexus/GXWebReport.java @@ -0,0 +1,185 @@ +package com.genexus; + +import com.genexus.db.UserInformation; +import com.genexus.internet.HttpContext; +import com.genexus.reports.GXReportMetadata; +import com.genexus.reports.IReportHandler; +import com.genexus.reports.PDFReportItext; +import com.genexus.webpanels.GXWebProcedure; + +public abstract class GXWebReport extends GXWebProcedure +{ + public static final int OUTPUT_RVIEWER = 1; + public static final int OUTPUT_PDF = 2; + + // Tiene que ser protected porque se pasa como par�metro en los reports + protected GXReportMetadata reportMetadata; + protected IReportHandler reportHandler; + + protected int lineHeight; + protected int Gx_line; + protected int P_lines; + protected int gxXPage; + protected int gxYPage; + protected int Gx_page; + protected String Gx_out = ""; // Esto est� asi porque no me pude deshacer de una comparacion contra Gx_out antes del ask. + protected String filename; + protected String filetype; + + public GXWebReport(HttpContext httpContext) + { + super(httpContext); + } + + protected void initState(ModelContext context, UserInformation ui) + { + super.initState(context, ui); + + httpContext.setBuffered(true); + httpContext.setBinary(true); + + reportHandler = new PDFReportItext(context); + + initValues(); + } + + protected void preExecute() + { + httpContext.setContentType("application/pdf"); + httpContext.setStream(); + + // Tiene que ir despues del setStream porque sino el getOutputStream apunta + // a otro lado. + ((PDFReportItext) reportHandler).setOutputStream(httpContext.getOutputStream()); + } + + protected void setOutputFileName(String outputFileName){ + filename = outputFileName; + } + protected void setOutputType(String outputType){ + filetype = outputType.toLowerCase(); + } + private void initValues() + { + Gx_line = 0; + P_lines = 0; + gxXPage = 0; + gxYPage = 0; + Gx_page = 0; + Gx_out = ""; // Esto est� asi porque no me pude deshacer de una comparacion contra Gx_out antes del ask. + lineHeight = 0; + } + + public void setPrinter(IReportHandler reportHandler) + { + this.reportHandler = reportHandler; + } + + public IReportHandler getPrinter() + { + return reportHandler; + } + + protected void GxEndPage() throws ProcessInterruptedException + { + if (reportHandler != null) + reportHandler.GxEndPage(); + } + + protected boolean initTextPrinter(String output, int gxXPage, int gxYPage, String iniFile, String form, String printer, int mode, int nPaperLength, int nPaperWidth, int nGridX, int nGridY, int nPageLines) + { + int x[] = {gxXPage}; + int y[] = {gxYPage}; + + getPrinter().GxRVSetLanguage(localUtil._language); + boolean ret = getPrinter().GxPrTextInit(output, x, y, iniFile, form, printer, mode, nPaperLength, nPaperWidth, nGridX, nGridY, nPageLines); + + this.gxXPage = x[0]; + this.gxYPage = y[0]; + + return ret; + } + + protected boolean initPrinter(String output, int gxXPage, int gxYPage, String iniFile, String form, String printer, int mode, int orientation, int pageSize, int pageLength, int pageWidth, int scale, int copies, int defSrc, int quality, int color, int duplex) + { + int x[] = {gxXPage}; + int y[] = {gxYPage}; + setResponseOuputFileName(); + + getPrinter().GxRVSetLanguage(localUtil._language); + boolean ret = getPrinter().GxPrintInit(output, x, y, iniFile, form, printer, mode, orientation, pageSize, pageLength, pageWidth, scale, copies, defSrc, quality, color, duplex); + + this.gxXPage = x[0]; + this.gxYPage = y[0]; + + return ret; + } + + private void setResponseOuputFileName(){ + String outputFileName = filename!=null ? filename : getClass().getSimpleName(); + String outputFileType = filetype!=null ? "." + filetype.toLowerCase(): ".pdf"; + httpContext.getResponse().addHeader("content-disposition", "inline; filename=" + outputFileName + outputFileType); + } + + protected void endPrinter() + { + getPrinter().GxEndPrinter(); + } + + protected int getOutputType() + { + return OUTPUT_RVIEWER; + } + + protected java.io.OutputStream getOutputStream() + { + throw new RuntimeException("Output stream not set"); + } + + //M�todos para la implementaci�n de reportes din�micos + protected void loadReportMetadata(String name) + { + reportMetadata = new GXReportMetadata(name, reportHandler); + reportMetadata.load(); + } + + protected int GxDrawDynamicGetPrintBlockHeight(int printBlock) + { + return reportMetadata.GxDrawGetPrintBlockHeight(printBlock); + } + + protected void GxDrawDynamicText(int printBlock, int controlId, int Gx_line) + { + reportMetadata.GxDrawText(printBlock, controlId, Gx_line); + } + + protected void GxDrawDynamicText(int printBlock, int controlId, String value, int Gx_line) + { + reportMetadata.GxDrawText(printBlock, controlId, Gx_line, value); + } + + protected void GxDrawDynamicLine(int printBlock, int controlId, int Gx_line) + { + reportMetadata.GxDrawLine(printBlock, controlId, Gx_line); + } + + protected void GxDrawDynamicRect(int printBlock, int controlId, int Gx_line) + { + reportMetadata.GxDrawRect(printBlock, controlId, Gx_line); + } + + protected void GxDrawDynamicBitMap(int printBlock, int controlId, String value, int Gx_line) + { + reportMetadata.GxDrawBitMap(printBlock, controlId, Gx_line, value, 0); + } + + protected void GxDrawDynamicBitMap(int printBlock, int controlId, String value, int aspectRatio, int Gx_line) + { + reportMetadata.GxDrawBitMap(printBlock, controlId, Gx_line, value, aspectRatio); + } + + protected void cleanup( ) + { + super.cleanup(); + } +} diff --git a/java/src/main/java/com/genexus/GXutil.java b/java/src/main/java/com/genexus/GXutil.java index dbae021f1..32c18f70d 100644 --- a/java/src/main/java/com/genexus/GXutil.java +++ b/java/src/main/java/com/genexus/GXutil.java @@ -15,6 +15,7 @@ import com.genexus.util.*; import json.org.json.JSONObject; +import org.apache.commons.lang.StringUtils; public final class GXutil { @@ -1704,11 +1705,19 @@ public static String pagingSelect(String select) public static String getEncryptedSignature( String value, String key) { - return Encryption.encrypt64(CommonUtil.getHash( com.genexus.security.web.WebSecurityHelper.StripInvalidChars(value), CommonUtil.SECURITY_HASH_ALGORITHM), key); + return Encryption.encrypt64(CommonUtil.getHash( StripInvalidChars(value), CommonUtil.SECURITY_HASH_ALGORITHM), key); } public static boolean checkEncryptedSignature( String value, String hash, String key) { - return CommonUtil.getHash( com.genexus.security.web.WebSecurityHelper.StripInvalidChars(value), CommonUtil.SECURITY_HASH_ALGORITHM).equals(Encryption.decrypt64(hash, key)); + return CommonUtil.getHash( StripInvalidChars(value), CommonUtil.SECURITY_HASH_ALGORITHM).equals(Encryption.decrypt64(hash, key)); + } + + public static String StripInvalidChars(String input) + { + if (input == null) + return input; + String output = input.replaceAll("[\u0000-\u001f]", ""); + return StringUtils.strip(output); } public static String buildWSDLFromHttpClient(com.genexus.internet.HttpClient GXSoapHTTPClient, String wsdlURL) diff --git a/java/src/main/java/com/genexus/GxRestService.java b/java/src/main/java/com/genexus/GxRestService.java index 2e848c6f2..51da992ba 100644 --- a/java/src/main/java/com/genexus/GxRestService.java +++ b/java/src/main/java/com/genexus/GxRestService.java @@ -4,59 +4,43 @@ import java.text.SimpleDateFormat; import java.util.Date; -import com.genexus.servlet.IServletContext; -import com.genexus.servlet.http.IHttpServletRequest; -import com.genexus.servlet.http.IHttpServletResponse; - import com.genexus.diagnostics.core.ILogger; -import com.genexus.internet.HttpContext; import com.genexus.internet.MsgList; import com.genexus.security.GXResult; import com.genexus.security.GXSecurityProvider; -import com.genexus.webpanels.GXWebObjectBase; +import com.genexus.servlet.IServletContext; +import com.genexus.servlet.http.IHttpServletRequest; +import com.genexus.servlet.http.IHttpServletResponse; import com.genexus.webpanels.HttpContextWeb; import json.org.json.JSONException; import json.org.json.JSONObject; -abstract public class GxRestService extends GXWebObjectBase -{ +abstract public class GxRestService extends GXObjectBase { private static ILogger logger = null; protected JSONObject errorJson; protected boolean error = false; - protected boolean useAuthentication = false; protected String gamError; protected boolean forbidden = false; protected String permissionPrefix; protected abstract boolean IntegratedSecurityEnabled(); protected abstract int IntegratedSecurityLevel(); + protected String ExecutePermissionPrefix(){ return ""; } protected boolean IsSynchronizer() - { - return false; - } - - public boolean isMasterPage() { return false; } - - protected static final int SECURITY_HIGH = 2; protected static final int SECURITY_LOW = 1; protected static final String POST = "POST"; - - public GxRestService() - { - super(); - } - protected HttpContext restHttpContext; + protected HttpContextWeb restHttpContext; protected com.genexus.ws.rs.core.IResponseBuilder builder; protected void init(String requestMethod) { @@ -101,15 +85,15 @@ private void initLogger(IServletContext myContext) { public void webExecute( ) { - } + } protected void cleanup() { - GXutil.setThreadTimeZone(ModelContext.getModelContext().getClientTimeZone()); - super.cleanup(); + GXutil.setThreadTimeZone(ModelContext.getModelContext().getClientTimeZone()); + super.cleanup(); super.finallyCleanup(); - WrapperUtils.requestBodyThreadLocal.remove(); - } + WrapperUtils.requestBodyThreadLocal.remove(); + } public void ErrorCheck(IGxSilentTrn trn) { @@ -212,7 +196,7 @@ public boolean isAuthenticated(IHttpServletRequest myServletRequest) public boolean isAuthenticated(IHttpServletRequest myServletRequest, String synchronizer) { boolean validSynchronizer = false; - try{ + try { if (synchronizer!= null && !synchronizer.equals("")) { synchronizer = synchronizer.toLowerCase() + "_services_rest"; @@ -221,13 +205,13 @@ public boolean isAuthenticated(IHttpServletRequest myServletRequest, String sync packageName += "."; Class synchronizerClass = Class.forName(packageName + synchronizer); GxRestService synchronizerRestService = (GxRestService) synchronizerClass.getConstructor().newInstance(); - if (synchronizerRestService!=null && synchronizerRestService.IsSynchronizer()){ + if (synchronizerRestService!=null && synchronizerRestService.IsSynchronizer()) { validSynchronizer = true; return isAuthenticated(myServletRequest, synchronizerRestService.IntegratedSecurityLevel(), synchronizerRestService.IntegratedSecurityEnabled(), synchronizerRestService.ExecutePermissionPrefix()); } } return false; - } + } catch(Exception e) { logger.error("Could not check user authenticated", e); diff --git a/java/src/main/java/com/genexus/internet/HttpContext.java b/java/src/main/java/com/genexus/internet/HttpContext.java index b1662058a..ed7a3cdcb 100644 --- a/java/src/main/java/com/genexus/internet/HttpContext.java +++ b/java/src/main/java/com/genexus/internet/HttpContext.java @@ -2,57 +2,38 @@ import java.io.*; import java.util.Date; -import java.util.Enumeration; import java.util.HashMap; -import java.util.HashSet; import java.util.Hashtable; -import java.util.Vector; +import json.org.json.JSONObject; +import org.apache.logging.log4j.Logger; -import com.genexus.common.interfaces.IGXWebRow; +import com.genexus.*; import com.genexus.servlet.http.ICookie; import com.genexus.servlet.http.IHttpServletRequest; import com.genexus.servlet.http.IHttpServletResponse; - -import com.genexus.*; - -import com.genexus.util.Codecs; -import com.genexus.util.Encryption; -import com.genexus.util.ThemeHelper; -import com.genexus.webpanels.GXWebObjectBase; import com.genexus.webpanels.WebSession; -import com.genexus.webpanels.WebUtils; -import json.org.json.IJsonFormattable; -import json.org.json.JSONArray; -import json.org.json.JSONException; -import json.org.json.JSONObject; -import org.apache.logging.log4j.Logger; - -public abstract class HttpContext - extends HttpAjaxContext implements IHttpContext +public abstract class HttpContext implements IHttpContext { private static Logger logger = org.apache.logging.log4j.LogManager.getLogger(HttpContext.class); - private static String GX_AJAX_REQUEST_HEADER = "GxAjaxRequest"; + public static int SPA_NOT_SUPPORTED_STATUS_CODE = 530; private static String GX_SPA_REQUEST_HEADER = "X-SPA-REQUEST"; protected static String GX_SPA_REDIRECT_URL = "X-SPA-REDIRECT-URL"; private static String GX_SOAP_ACTION_HEADER = "SOAPAction"; public static String GXTheme = "GXTheme"; public static String GXLanguage = "GXLanguage"; - private static String CACHE_INVALIDATION_TOKEN; - protected boolean PortletMode = false; protected boolean AjaxCallMode = false; protected boolean AjaxEventMode = false; protected boolean fullAjaxMode = false; - public boolean drawingGrid = false; + protected boolean ajaxRefreshAsGET = false; + public MsgList GX_msglist = new MsgList(); - public void setDrawingGrid(boolean drawingGrid) - { - this.drawingGrid = drawingGrid; + public MsgList getMessageList() { + return GX_msglist; } - public void setFullAjaxMode() { fullAjaxMode = true; } @@ -110,24 +91,12 @@ public boolean isSoapRequest() return getRequest() != null && getRequest().getHeader(GX_SOAP_ACTION_HEADER) != null; } - public void ajax_sending_grid_row(IGXWebRow row) - { - if (isAjaxCallMode()) - { - _currentGridRow = row; - } - else - { - _currentGridRow = null; - } - } - public byte wbGlbDoneStart = 0; //nSOAPErr public HttpResponse GX_webresponse; - private String clientId = ""; + protected String clientId = ""; public String wjLoc = ""; public int wjLocDisableFrm = 0; public String sCallerURL = ""; @@ -141,56 +110,21 @@ public void ajax_sending_grid_row(IGXWebRow row) protected boolean doNotCompress; protected ModelContext context; - private boolean isEnabled = true; + protected boolean isEnabled = true; private OutputStream out; private PrintWriter writer; private String userId; private boolean isBinary = false; private Boolean mustUseWriter; protected boolean isCrawlerRequest = false; - private boolean validEncryptedParm = true; - private boolean encryptionKeySended = false; - - private Vector javascriptSources = new Vector<>(); - private Vector deferredFragments = new Vector(); - private Vector styleSheets = new Vector<>(); - private HashSet deferredJavascriptSources = new HashSet(); private boolean responseCommited = false; - private boolean wrapped = false; - private int drawGridsAtServer = -1; + protected boolean wrapped = false; + protected int drawGridsAtServer = -1; private boolean ignoreSpa = false; - private String serviceWorkerFileName = "service-worker.js"; - private Boolean isServiceWorkerDefinedFlag = null; - - private String webAppManifestFileName = "manifest.json"; - private Boolean isWebAppManifestDefinedFlag = null; - private static HashMap cachedMessages = new HashMap(); - private String currentLanguage = null; - private Vector userStyleSheetFiles = new Vector(); - private String themekbPrefix; - private String themestyleSheet; - private String themeurlBuildNumber; - - private boolean isServiceWorkerDefined() - { - if (isServiceWorkerDefinedFlag == null) - { - isServiceWorkerDefinedFlag = Boolean.valueOf(checkFileExists(serviceWorkerFileName)); - } - return isServiceWorkerDefinedFlag == Boolean.valueOf(true); - } - - private boolean isWebAppManifestDefined() - { - if (isWebAppManifestDefinedFlag == null) - { - isWebAppManifestDefinedFlag = Boolean.valueOf(checkFileExists(webAppManifestFileName)); - } - return isWebAppManifestDefinedFlag == Boolean.valueOf(true); - } + protected String currentLanguage = null; public boolean isOutputEnabled() { @@ -247,22 +181,6 @@ protected void copyCommon(HttpContext ctx) ctx.responseCommited = responseCommited; } - public static final int TYPE_RESET = 0; - public static final int TYPE_SUBMIT = 1; - public static final int TYPE_BUTTON = 2; - - public static final int BROWSER_OTHER = 0; - public static final int BROWSER_IE = 1; - public static final int BROWSER_NETSCAPE = 2; - public static final int BROWSER_OPERA = 3; - public static final int BROWSER_UP = 4; - public static final int BROWSER_POCKET_IE = 5; - public static final int BROWSER_FIREFOX = 6; - public static final int BROWSER_CHROME = 7; - public static final int BROWSER_SAFARI = 8; - public static final int BROWSER_EDGE = 9; - public static final int BROWSER_INDEXBOT = 20; - public abstract void cleanup(); public abstract String getResourceRelative(String path); public abstract String getResourceRelative(String path, boolean includeBasePath); @@ -295,7 +213,6 @@ protected void copyCommon(HttpContext ctx) public abstract void setDefaultPath(String path); public abstract String getBrowserVersion(); public abstract Object getSessionValue(String name); - public abstract void webPutSessionValue(String name, Object value); public abstract void webPutSessionValue(String name, long value); public abstract void webPutSessionValue(String name, double value); @@ -326,11 +243,8 @@ protected void copyCommon(HttpContext ctx) public abstract void changePostValue(String ctrl, String value); public abstract boolean isFileParm( String parm); public abstract void parseGXState(JSONObject tokenValues); - - public abstract void deletePostValue(String ctrl); - public abstract void DeletePostValuePrefix(String sPrefix); - - + public abstract void deletePostValue(String ctrl); + public abstract void DeletePostValuePrefix(String sPrefix); public abstract HttpResponse getHttpResponse(); public abstract HttpRequest getHttpRequest(); public abstract void setHttpRequest(HttpRequest httprequest); @@ -339,246 +253,11 @@ protected void copyCommon(HttpContext ctx) public abstract void setRequest(IHttpServletRequest request); public abstract Hashtable getPostData(); public abstract WebSession getWebSession(); - public abstract void redirect(String url); - public abstract void redirect(String url, boolean SkipPushUrl); public abstract void setStream() ; public abstract void flushStream(); - - public abstract void closeHtmlHeader(); - public abstract boolean getHtmlHeaderClosed(); - public abstract void ajax_rsp_command_close(); - public abstract void dispatchAjaxCommands(); - public abstract boolean isHttpContextNull(); public abstract boolean isHttpContextWeb(); - - public void AddDeferredFrags() - { - Enumeration vEnum = deferredFragments.elements(); - while(vEnum.hasMoreElements()) - { - writeTextNL(vEnum.nextElement()); - } - } - - public void ClearJavascriptSources() { - javascriptSources.clear(); - } - - public void AddJavascriptSource(String jsSrc, String urlBuildNumber, boolean userDefined, boolean isInlined) - { - if(!javascriptSources.contains(jsSrc)) - { - urlBuildNumber = getURLBuildNumber(jsSrc, urlBuildNumber); - javascriptSources.add(jsSrc); - String queryString = urlBuildNumber; - String attributes = ""; - if (userDefined) - { - queryString = ""; - attributes = "data-gx-external-script"; - } - String fragment = "" ; - if (isAjaxRequest() || isInlined || jsSrc == "jquery.js" || jsSrc == "gxcore.js") - { - writeTextNL(fragment); - } - else - { - deferredFragments.add(fragment); - } - // After including jQuery, include all the deferred Javascript files - if (jsSrc.equals("jquery.js")) - { - for (String deferredJsSrc : deferredJavascriptSources) - { - AddJavascriptSource(deferredJsSrc, "", false, true); - } - } - // After including gxgral, set the Service Worker Url if one is defined - if (jsSrc.equals("gxgral.js") && isServiceWorkerDefined()) - { - writeTextNL(""); - } - } - } - - public void addWebAppManifest() - { - if (isWebAppManifestDefined()) - { - writeTextNL(""); - } - } - - private boolean checkFileExists(String fileName) - { - boolean fileExists = false; - try - { - File file = new File(getDefaultPath() + staticContentBase + fileName); - fileExists = file.exists() && file.isFile(); - com.genexus.diagnostics.Log.info("Searching if file exists (" + fileName + "). Found: " + String.valueOf(fileExists)); - } - catch (Exception e) - { - fileExists = false; - com.genexus.diagnostics.Log.info("Failed searching for a file (" + fileName + ")"); - } - return fileExists; - } - - - public void AddDeferredJavascriptSource(String jsSrc, String urlBuildNumber) - { - deferredJavascriptSources.add(oldConvertURL(jsSrc) + urlBuildNumber); - } - - - private String FetchCustomCSS() - { - String cssContent; - cssContent = ApplicationContext.getcustomCSSContent().get(getRequest().getServletPath()); - if (cssContent == null) - { - String path = getRequest().getServletPath().replaceAll(".*/", "") + ".css"; - try(InputStream istream = context.packageClass.getResourceAsStream(path)) - { - - if (istream == null) - { - cssContent = ""; - } - else { - //BOMInputStream bomInputStream = new BOMInputStream(istream);// Avoid using BOMInputStream because of runtime error (java.lang.NoSuchMethodError: org.apache.commons.io.IOUtils.length([Ljava/lang/Object;)I) issue 94611 - //cssContent = IOUtils.toString(bomInputStream, "UTF-8"); - cssContent = PrivateUtilities.BOMInputStreamToStringUTF8(istream); - } - } - catch ( Exception e) { - cssContent = ""; - } - ApplicationContext.getcustomCSSContent().put(getRequest().getServletPath(), cssContent); - } - return cssContent; - } - - public void CloseStyles() - { - String cssContent = FetchCustomCSS(); - boolean bHasCustomContent = ! cssContent.isEmpty(); - if (bHasCustomContent && !styleSheets.contains(getRequest().getServletPath())) - { - writeTextNL(""); - styleSheets.add(getRequest().getServletPath()); - } - String[] referencedFiles = ThemeHelper.getThemeCssReferencedFiles(PrivateUtilities.removeExtension(themestyleSheet)); - for (int i=0; i @import url(\"" + sUncachedURL + "\") layer(" + sLayerName + ");"); - } - else - { - writeTextNL(" 0) - { - return true; - } - return false; - } - - private String getAjaxEncryptionKey() - { - if(getSessionValue(Encryption.AJAX_ENCRYPTION_KEY) == null) - { - if (!recoverEncryptionKey()) - { - webPutSessionValue(Encryption.AJAX_ENCRYPTION_KEY, Encryption.getRijndaelKey()); - } - } - return (String)getSessionValue(Encryption.AJAX_ENCRYPTION_KEY); - } - - private boolean recoverEncryptionKey() - { - if (getSessionValue(Encryption.AJAX_ENCRYPTION_KEY) == null) - { - String clientKey = getRequest().getHeader(Encryption.AJAX_SECURITY_TOKEN); - if (clientKey != null && clientKey.trim().length() > 0) - { - boolean candecrypt[]=new boolean[1]; - clientKey = Encryption.decryptRijndael(Encryption.GX_AJAX_PRIVATE_IV + clientKey, Encryption.GX_AJAX_PRIVATE_KEY, candecrypt); - if (candecrypt[0]) - { - webPutSessionValue(Encryption.AJAX_ENCRYPTION_KEY, clientKey); - return true; - }else - { - return false; - } - } - } - return false; - } - - public String DecryptAjaxCall(String encrypted) - { - validEncryptedParm = false; - if (isGxAjaxRequest()) - { - String key = getAjaxEncryptionKey(); - boolean candecrypt[] = new boolean[1]; - String decrypted = Encryption.decryptRijndael(encrypted, key, candecrypt); - validEncryptedParm = candecrypt[0]; - if (!validEncryptedParm) - { - CommonUtil.writeLogln( String.format("403 Forbidden error. Could not decrypt Ajax parameter: '%s' with key: '%s'", encrypted, key)); - sendResponseStatus(403, "Forbidden action"); - return ""; - } - if (validEncryptedParm && !getRequestMethod().equalsIgnoreCase("post")) - { - setQueryString(decrypted); - decrypted = GetNextPar(); - } - return decrypted; - } - return encrypted; - } - - public boolean IsValidAjaxCall() - { - return IsValidAjaxCall(true); - } - - public boolean IsValidAjaxCall(boolean insideAjaxCall) - { - if (insideAjaxCall && !validEncryptedParm) - { - CommonUtil.writeLogln( "Failed IsValidAjaxCall 403 Forbidden action"); - sendResponseStatus(403, "Forbidden action"); - return false; - } - else if (!insideAjaxCall && isGxAjaxRequest() && !isFullAjaxMode() && ajaxOnSessionTimeout().equalsIgnoreCase("Warn")) - { - sendResponseStatus(440, "Session timeout"); - return false; - } - return true; - } public void sendResponseStatus(int statusCode, String statusDescription) { if (statusCode < 200 || statusCode >= 300) { getResponse().setHeader("Content-Encoding", ""); - if (statusCode != GXWebObjectBase.SPA_NOT_SUPPORTED_STATUS_CODE) + if (statusCode != SPA_NOT_SUPPORTED_STATUS_CODE) { CommonUtil.writeLog("sendResponseStatus " + Integer.toString(statusCode) + " " + statusDescription); } @@ -896,11 +385,6 @@ public void sendResponseStatus(int statusCode, String statusDescription) disableOutput(); } - private void sendReferer() - { - ajax_rsp_assign_hidden("sCallerURL", org.owasp.encoder.Encode.forUri(getReferer())); - } - private static String CLIENT_ID_HEADER = "GX_CLIENT_ID"; public void initClientId() @@ -926,78 +410,10 @@ public boolean useSecurityTokenValidation() { return ((Preferences)this.context.getPreferences()).getProperty("ValidateSecurityToken", "y").equals("y"); } - - protected void addNavigationHidden() - { - if (this.isLocalStorageSupported()) - { - try { - HiddenValues.put("GX_CLI_NAV", "true"); - } catch (JSONException e) { - } - GXNavigationHelper nav = this.getNavigationHelper(); - if (nav.count() > 0) - { - String sUrl = this.getRequestNavUrl().trim(); - String popupLevel = nav.getUrlPopupLevel(sUrl); - try { - HiddenValues.put("GX_NAV", nav.toJSonString(popupLevel)); - } catch (JSONException e) { - } - nav.deleteStack(popupLevel); - } - } - } - - public void SendWebComponentState() - { - AddStylesheetsToLoad(); - } - - public void SendState() - { - sendReferer(); - sendWebSocketParms(); - addNavigationHidden(); - AddThemeHidden(this.getTheme()); - AddStylesheetsToLoad(); - if (isSpaRequest()) - { - writeTextNL(""); - } - else - { - if (this.drawGridsAtServer()) - { - writeTextNL(""); - } - skipLines(1); - String value = HiddenValues.toString(); - if (useBase64ViewState()) - { - try{ - value = Codecs.base64Encode(value, "UTF8"); - }catch(Exception ex){} - writeTextNL(""); - } - writeText("
"); - } - } - - private void sendWebSocketParms() - { - if (!this.isAjaxRequest() || isSpaRequest()) - { - ajax_rsp_assign_hidden("GX_WEBSOCKET_ID", clientId); - } - } - public String getEncryptedSignature( String value, String key) { - return encrypt64(CommonUtil.getHash( com.genexus.security.web.WebSecurityHelper.StripInvalidChars(value), CommonUtil.SECURITY_HASH_ALGORITHM), key); + return encrypt64(CommonUtil.getHash( GXutil.StripInvalidChars(value), CommonUtil.SECURITY_HASH_ALGORITHM), key); } public String encrypt64(String value, String key) @@ -1032,85 +448,6 @@ public String decrypt64(String value, String key) return sRet; } - public void SendAjaxEncryptionKey() - { - if(!encryptionKeySended) - { - String key = getAjaxEncryptionKey(); - ajax_rsp_assign_hidden(Encryption.AJAX_ENCRYPTION_KEY, key); - ajax_rsp_assign_hidden(Encryption.AJAX_ENCRYPTION_IV, Encryption.GX_AJAX_PRIVATE_IV); - try - { - ajax_rsp_assign_hidden(Encryption.AJAX_SECURITY_TOKEN, Encryption.encryptRijndael(key, Encryption.GX_AJAX_PRIVATE_KEY)); - } - catch(Exception exc) {} - encryptionKeySended = true; - } - } - - public void SendServerCommands() - { - try { - if (!isAjaxRequest() && commands.getCount() > 0) - { - HiddenValues.put("GX_SRV_COMMANDS", commands.getJSONArray()); - } - } - catch (JSONException e) { - } - } - - public void ajax_req_read_hidden_sdt(String jsonStr, Object SdtObj) - { - try - { - IJsonFormattable jsonObj; - if (jsonStr.startsWith("[")) - jsonObj = new JSONArray(jsonStr); - else - jsonObj = new JSONObject(jsonStr); - ((IGxJSONAble)SdtObj).FromJSONObject(jsonObj); - } - catch(JSONException exc) {} - } - - public void ajax_rsp_assign_prop_as_hidden(String Control, String Property, String Value) - { - if (!this.isAjaxRequest()) - { - ajax_rsp_assign_hidden(Control + "_" + Property.substring(0, 1) + Property.substring(1).toLowerCase(), Value); - } - } - - public boolean IsSameComponent(String oldName, String newName) - { - if(oldName.trim().equalsIgnoreCase(newName.trim())) - { - return true; - } - else - { - if(newName.trim().toLowerCase().startsWith(oldName.trim().toLowerCase() + "?")) - { - return true; - } - else - { - String packageName = context.getPackageName(); - String qoldName; - String qnewName; - - if ( (oldName.indexOf(packageName) != 0) || (newName.indexOf(packageName) != 0)) - { - qoldName = (oldName.indexOf(packageName) != 0) ? packageName + "." + oldName : oldName; - qnewName = (newName.indexOf(packageName) != 0) ? packageName + "." + newName : newName; - return IsSameComponent(qoldName, qnewName); - } - } - } - return false; - } - public void webGetSessionValue(String name, byte[] value) { Object o = getSessionValue(name); @@ -1163,205 +500,19 @@ public void webGetSessionValue(String name, String[] value) value[0] = (String) o; } } -/* - public void webGetSessionValue(String name, java.util.Date[] value) - { - Object o = getSessionValue(name); - if (o != null) - System.arraycopy(o, 0, value, 0, value.length); - } - - public void webGetSessionValue(String name, byte[][] value) - { - Object o = getSessionValue(name); - if (o != null) - System.arraycopy(o, 0, value, 0, value.length); - } - - public void webGetSessionValue(String name, short[][] value) - { - Object o = getSessionValue(name); - if (o != null) - System.arraycopy(o, 0, value, 0, value.length); - } - - public void webGetSessionValue(String name, int[][] value) - { - Object o = getSessionValue(name); - if (o != null) - System.arraycopy(o, 0, value, 0, value.length); - } - - public void webGetSessionValue(String name, long[][] value) - { - Object o = getSessionValue(name); - if (o != null) - System.arraycopy(o, 0, value, 0, value.length); - } - - public void webGetSessionValue(String name, float[][] value) - { - Object o = getSessionValue(name); - if (o != null) - System.arraycopy(o, 0, value, 0, value.length); - } - - public void webGetSessionValue(String name, double[][] value) - { - Object o = getSessionValue(name); - if (o != null) - System.arraycopy(o, 0, value, 0, value.length); - } - - public void webGetSessionValue(String name, String[][] value) - { - Object o = getSessionValue(name); - if (o != null) - System.arraycopy(o, 0, value, 0, value.length); - } - - public void webGetSessionValue(String name, java.util.Date[][] value) - { - Object o = getSessionValue(name); - if (o != null) - System.arraycopy(o, 0, value, 0, value.length); - } -*/ public String getSubscriberId() { return getHeader("HTTP_X_UP_SUBNO"); } - public byte isMobileBrowser() - { - String accept = getHeader("HTTP_ACCEPT"); - - return (accept.indexOf("wap") >= 0 || accept.indexOf("hdml") >= 0)?0: (byte) 1; - } - - public void writeValueComplete(String text) - { - writeValueComplete(text, true, true, true); - } - - public void writeValueSpace(String text) - { - writeValueComplete(text, false, false, true); - } - - public void writeValueEnter(String text) - { - writeValueComplete(text, false, true, false); - } - - /** Este writeValue tiene en consideracion los espacios consecutivos, - * los enter y los tabs - */ - public void writeValueComplete(String text, boolean cvtTabs, boolean cvtEnters, boolean cvtSpaces) - { - StringBuilder sb = new StringBuilder(); - boolean lastCharIsSpace = true; // Asumo que al comienzo el lastChar era space - for (int i = 0; i < text.length(); i++) - { - char currentChar = text.charAt(i); - switch (currentChar) - { - case (char) 34: - sb.append("""); - break; - case (char) 38: - sb.append("&"); - break; - case (char) 60: - sb.append("<"); - break; - case (char) 62: - sb.append(">"); - break; - case '\t': - sb.append(cvtTabs ? "    " : ("" + currentChar)); - break; - case '\r': - if (cvtEnters && text.length() > i + 1 && text.charAt(i+1) == '\n'){ - sb.append(cvtEnters ? "
" : ("" + currentChar)); - i++; - } - break; - case '\n': - sb.append(cvtEnters ? "
" : ("" + currentChar)); - break; - case ' ': - sb.append((lastCharIsSpace && cvtSpaces) ? " " : " "); - break; - default: - sb.append("" + currentChar); - } - lastCharIsSpace = currentChar == ' '; - } - writeText(sb.toString()); - } - - public void writeValue(String text) - { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < text.length(); i++) - { - char currentChar = text.charAt(i); - - switch (currentChar) - { - case '"': - sb.append("""); - break; - case '&': - sb.append("&"); - break; - case '<': - sb.append("<"); - break; - case '>': - sb.append(">"); - break; - default: - sb.append(currentChar); - } - } - writeText(sb.toString()); - } - - public void skipLines(long num) - { - for(; num > 0; num --) - { - writeText("\n"); - } - } - public void setOutputStream(OutputStream out) { this.out = out; } - public void writeTextNL(String text) - { - writeText(text + "\n"); - } - public boolean useUtf8 = false; - public void writeText(String text) - { - if (getResponseCommited()) - return; - if (isEnabled == false) - { - ajax_addCmpContent(text); - return; - } - _writeText(text); - } - public void _writeText(String text) { _writeText(text, false); @@ -1420,12 +571,6 @@ public void setWriter(PrintWriter writer) this.writer = writer; } -/* public PrintWriter getWriter() - { - return writer; - } - -*/ public void closeWriter() { if (writer != null) @@ -1447,11 +592,6 @@ public void closeOutputStream() } } - public MsgList getMessageList() - { - return GX_msglist; - } - public void setBuffered(boolean buffered) { this.buffered = buffered; @@ -1480,7 +620,7 @@ public void setUserId(String userId) this.userId = userId; } - private String staticContentBase = ""; + protected String staticContentBase = ""; public void setStaticContentBase(String staticContentBase) { this.staticContentBase = staticContentBase; @@ -1684,47 +824,6 @@ public String getLanguage() } return currentLanguage; } - public String htmlEndTag(HTMLElement element) - { - HTMLDocType docType = context.getClientPreferences().getDOCTYPE(); - if ((docType == HTMLDocType.HTML4 || docType == HTMLDocType.NONE || docType == HTMLDocType.HTML4S) && - (element == HTMLElement.IMG || - element == HTMLElement.INPUT || - element == HTMLElement.META || - element == HTMLElement.LINK)) - return ">"; - else if (element == HTMLElement.OPTION) - if (docType == HTMLDocType.XHTML1 || docType == HTMLDocType.HTML5) - return ""; - else - return ""; - else - return "/>"; - } - public String htmlDocType() - { - HTMLDocType docType = context.getClientPreferences().getDOCTYPE(); - switch (docType) - { - case HTML4: - if (context.getClientPreferences().getDOCTYPE_DTD()) - return ""; - else - return ""; - case HTML4S: - if (context.getClientPreferences().getDOCTYPE_DTD()) - return ""; - else - return ""; - case XHTML1: - if (context.getClientPreferences().getDOCTYPE_DTD()) - return ""; - else - return ""; - case HTML5: return ""; - default: return ""; - } - } public int setLanguage(String language) { diff --git a/java/src/main/java/com/genexus/internet/HttpContextNull.java b/java/src/main/java/com/genexus/internet/HttpContextNull.java index 6ff8cdad9..4e3b2ed01 100644 --- a/java/src/main/java/com/genexus/internet/HttpContextNull.java +++ b/java/src/main/java/com/genexus/internet/HttpContextNull.java @@ -409,27 +409,20 @@ public void setHttpRequest(HttpRequest httprequest) this.httprequest = httprequest; } - public WebSession getWebSession() { return webSession; } - public void redirect(String url) {} - public void redirect(String url, boolean SkipPushUrl) {} - public void ajax_rsp_command_close(){}; - public void dispatchAjaxCommands() {}; - public void closeHtmlHeader() {}; - public boolean getHtmlHeaderClosed() { return false; } - public void setStream(){} public void flushStream(){} public String cgiGetFileName(String parm) {return "";} public String cgiGetFileType(String parm) {return "";} public void getMultimediaValue(String internalName, String[] blobVar, String[] uriVar) { blobVar[0] = ""; uriVar[0] = ""; } public void cleanup() {} - public boolean isMultipartContent() { return false; } public boolean isHttpContextNull() {return true;} public boolean isHttpContextWeb() {return false;} + + public void redirect(String url) {} } diff --git a/java/src/main/java/com/genexus/reports/GXReport.java b/java/src/main/java/com/genexus/reports/GXReport.java index 8b896005f..add2dbd88 100644 --- a/java/src/main/java/com/genexus/reports/GXReport.java +++ b/java/src/main/java/com/genexus/reports/GXReport.java @@ -49,24 +49,16 @@ public static byte openGXReport(String document) } return 0; } - - protected void setPrintAtClient() - { - setPrintAtClient(""); - } - protected void setPrintAtClient(String printerRule) + public String setPrintAtClient() { String blobPath = com.genexus.Preferences.getDefaultPreferences().getBLOB_PATH(); String fileName = com.genexus.PrivateUtilities.getTempFileName(blobPath, "clientReport", getOutputType() == OUTPUT_PDF ? "pdf":"gxr"); getPrinter().GxSetDocName(fileName); getPrinter().GxSetDocFormat("GXR"); - if (httpContext != null) - { - httpContext.printReportAtClient(fileName, printerRule); - } com.genexus.webpanels.BlobsCleaner.getInstance().addBlobFile(fileName); + return fileName; } public void setPrinter(IReportHandler reportHandler) diff --git a/java/src/main/java/com/genexus/reports/GXReportText.java b/java/src/main/java/com/genexus/reports/GXReportText.java index fda7707a8..7de41326b 100644 --- a/java/src/main/java/com/genexus/reports/GXReportText.java +++ b/java/src/main/java/com/genexus/reports/GXReportText.java @@ -84,25 +84,17 @@ protected void setOutput(String fileName) setOutput(System.out); } } - - protected void setPrintAtClient() - { - setPrintAtClient(""); - } - protected void setPrintAtClient(String printerRule) - { - printAtClient = true; - String blobPath = com.genexus.Preferences.getDefaultPreferences().getBLOB_PATH(); - String fileName = com.genexus.PrivateUtilities.getTempFileName(blobPath, "clientReport", "txt"); - - setOutput(fileName); - if (httpContext != null) - { - httpContext.printReportAtClient(fileName, printerRule); - } - com.genexus.webpanels.BlobsCleaner.getInstance().addBlobFile(fileName); - } + public String setPrintAtClient() + { + printAtClient = true; + String blobPath = com.genexus.Preferences.getDefaultPreferences().getBLOB_PATH(); + String fileName = com.genexus.PrivateUtilities.getTempFileName(blobPath, "clientReport", "txt"); + + setOutput(fileName); + com.genexus.webpanels.BlobsCleaner.getInstance().addBlobFile(fileName); + return fileName; + } class AsciiPrintWriter extends PrintWriter { diff --git a/java/src/main/java/com/genexus/webpanels/GXOAuthAccessToken.java b/java/src/main/java/com/genexus/webpanels/GXOAuthAccessToken.java index cb9e31389..b40a4766c 100644 --- a/java/src/main/java/com/genexus/webpanels/GXOAuthAccessToken.java +++ b/java/src/main/java/com/genexus/webpanels/GXOAuthAccessToken.java @@ -127,8 +127,8 @@ protected void doExecute(HttpContext context) throws Exception } String OauthRealm = "OAuth realm=\"" + context.getRequest().getServerName() + "\"" + ",error_code=\"" + gamError + "\"" + ",error_description=\"" + messagePermissionEncoded + "\""; context.getResponse().addHeader("WWW-Authenticate", OauthRealm); - SetError(gamError, messagePermission); - context.writeText(errorJson.toString()); + SetError(gamError, messagePermission); + ((HttpContextWeb) context).writeText(errorJson.toString()); context.getResponse().flushBuffer(); return; } @@ -144,7 +144,7 @@ protected void doExecute(HttpContext context) throws Exception context.getResponse().addHeader("location", redirectURL[0]); JSONObject jObj = new JSONObject(); jObj.put("Location", redirectURL[0]); - context.writeText(jObj.toString()); + ((HttpContextWeb) context).writeText(jObj.toString()); context.getResponse().flushBuffer(); return; } @@ -152,7 +152,7 @@ protected void doExecute(HttpContext context) throws Exception { context.getResponse().setContentType("application/json"); context.getResponse().setStatus(200); - context.writeText((String)gamout.getjsonString()); + ((HttpContextWeb) context).writeText((String)gamout.getjsonString()); context.getResponse().flushBuffer(); return; } diff --git a/java/src/main/java/com/genexus/webpanels/GXOAuthLogout.java b/java/src/main/java/com/genexus/webpanels/GXOAuthLogout.java index 9c7a927ac..bbe1b5530 100644 --- a/java/src/main/java/com/genexus/webpanels/GXOAuthLogout.java +++ b/java/src/main/java/com/genexus/webpanels/GXOAuthLogout.java @@ -40,7 +40,7 @@ protected void doExecute(HttpContext context) throws Exception { jObj.put("code", statusCode[0]); } - context.writeText(jObj.toString()); + ((HttpContextWeb) context).writeText(jObj.toString()); context.getResponse().flushBuffer(); return; } diff --git a/java/src/main/java/com/genexus/webpanels/GXOAuthUserInfo.java b/java/src/main/java/com/genexus/webpanels/GXOAuthUserInfo.java index 93ccfc255..17b148c78 100644 --- a/java/src/main/java/com/genexus/webpanels/GXOAuthUserInfo.java +++ b/java/src/main/java/com/genexus/webpanels/GXOAuthUserInfo.java @@ -29,7 +29,7 @@ protected void doExecute(HttpContext context) throws Exception { context.getResponse().setContentType("application/json"); context.getResponse().setStatus(200); - context.writeText(user[0]); + ((HttpContextWeb) context).writeText(user[0]); context.getResponse().flushBuffer(); return; } diff --git a/java/src/main/java/com/genexus/webpanels/GXObjectUploadServices.java b/java/src/main/java/com/genexus/webpanels/GXObjectUploadServices.java index a10adf505..094cf19e9 100644 --- a/java/src/main/java/com/genexus/webpanels/GXObjectUploadServices.java +++ b/java/src/main/java/com/genexus/webpanels/GXObjectUploadServices.java @@ -39,7 +39,7 @@ protected void doExecute(HttpContext context) throws Exception ModelContext.getModelContext().setHttpContext(context); context.setContext(modelContext); - if (context.isMultipartContent()) + if (((HttpContextWeb) context).isMultipartContent()) { context.setContentType("text/plain"); FileItemCollection postedFiles = context.getHttpRequest().getPostedparts(); @@ -67,7 +67,7 @@ protected void doExecute(HttpContext context) throws Exception } JSONObject jObjResponse = new JSONObject(); jObjResponse.put("files", jsonArray); - context.writeText(jObjResponse.toString()); + ((HttpContextWeb) context).writeText(jObjResponse.toString()); context.getResponse().flushBuffer(); } else @@ -86,7 +86,7 @@ protected void doExecute(HttpContext context) throws Exception context.getResponse().setContentType("application/json"); context.getResponse().setStatus(201); context.getResponse().setHeader("GeneXus-Object-Id", keyId); - context.writeText(jObj.toString()); + ((HttpContextWeb) context).writeText(jObj.toString()); context.getResponse().flushBuffer(); } else { diff --git a/java/src/main/java/com/genexus/webpanels/GXWebException.java b/java/src/main/java/com/genexus/webpanels/GXWebException.java deleted file mode 100644 index b8d066463..000000000 --- a/java/src/main/java/com/genexus/webpanels/GXWebException.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.genexus.webpanels; - -public class GXWebException extends RuntimeException -{ - /** - * - */ - private static final long serialVersionUID = 1L; - Exception e; - String msg; - - public GXWebException(Exception e) - { - this.e = e; - this.msg = e.getMessage(); - } - - public GXWebException(String text) - { - this.msg = text; - - } - - public String toString() - { - if (e != null) - return e.toString() + " / " + msg; - return msg; - } -} \ No newline at end of file diff --git a/java/src/main/java/com/genexus/webpanels/GXWebObjectStub.java b/java/src/main/java/com/genexus/webpanels/GXWebObjectStub.java index 322aa95a3..bd2b365b4 100644 --- a/java/src/main/java/com/genexus/webpanels/GXWebObjectStub.java +++ b/java/src/main/java/com/genexus/webpanels/GXWebObjectStub.java @@ -82,10 +82,22 @@ private void dumpRequestInfo(HttpContext httpContext) logger.debug(sBuffer.toString()); } - protected void callExecute(String method, IHttpServletRequest req, IHttpServletResponse res) throws ServletException + protected void callExecute(String method, IHttpServletRequest req, IHttpServletResponse res) throws ServletException { + HttpContext httpContext = null; + try + { + httpContext = new HttpContextWeb(method, req, res, getWrappedServletContext()); + callExecute(method, req, res, httpContext); + } + catch (Exception e) + { + handleException(e, httpContext); + } + } + + protected void callExecute(String method, IHttpServletRequest req, IHttpServletResponse res, HttpContext httpContext) throws ServletException { initialize(req, res); - HttpContext httpContext = null; try { String gxcfg = getWrappedServletContext().getInitParameter("gxcfg"); @@ -97,7 +109,6 @@ protected void callExecute(String method, IHttpServletRequest req, IHttpServletR appContext.setServletEngine(true); Application.init(gxcfgClass); } - httpContext = new HttpContextWeb(method, req, res, getWrappedServletContext()); if (logger.isDebugEnabled()) dumpRequestInfo(httpContext); boolean useAuthentication = IntegratedSecurityEnabled(); @@ -166,7 +177,7 @@ else if (IntegratedSecurityLevel() == SECURITY_LOW) GXSecurityProvider.getInstance().checksession(-2, modelContext, reqUrl, flag); if(!flag[0]) { - httpContext.redirect(loginObjectURL, true); + ((HttpContextWeb)httpContext).redirect(loginObjectURL, true); } else { @@ -187,11 +198,11 @@ else if (IntegratedSecurityLevel() == SECURITY_LOW) String notAuthorizedObjectURL = URLRouter.getURLRoute(notAuthorizedObject.toLowerCase(), new String[]{}, new String[]{}, httpContext.getRequest().getContextPath(), modelContext.getPackageName()); if (flag[0]) { - httpContext.redirect(notAuthorizedObjectURL, true); + ((HttpContextWeb)httpContext).redirect(notAuthorizedObjectURL, true); } else { - httpContext.redirect(loginObjectURL, true); + ((HttpContextWeb)httpContext).redirect(loginObjectURL, true); } } } @@ -203,13 +214,18 @@ else if (IntegratedSecurityLevel() == SECURITY_LOW) { if (!res.isCommitted()) res.reset(); - logger.error("Web Execution Error", e); - if (logger.isDebugEnabled() && httpContext != null) - dumpRequestInfo(httpContext); - throw new ServletException(com.genexus.PrivateUtilities.getStackTraceAsString(e)); + handleException(e, httpContext); } } + protected void handleException(Throwable e, HttpContext httpContext) throws ServletException + { + logger.error("Web Execution Error", e); + if (logger.isDebugEnabled() && httpContext != null) + dumpRequestInfo(httpContext); + throw new ServletException(com.genexus.PrivateUtilities.getStackTraceAsString(e)); + } + private void initialize(IHttpServletRequest req, IHttpServletResponse res) { if (logger == null) { logger = com.genexus.specific.java.LogManager.initialize(req.getServletContext().getRealPath("/"), GXWebObjectStub.class); diff --git a/java/src/main/java/com/genexus/webpanels/GXWebProcedure.java b/java/src/main/java/com/genexus/webpanels/GXWebProcedure.java index c83646266..da002d857 100644 --- a/java/src/main/java/com/genexus/webpanels/GXWebProcedure.java +++ b/java/src/main/java/com/genexus/webpanels/GXWebProcedure.java @@ -2,6 +2,7 @@ import java.io.PrintWriter; +import com.genexus.GXObjectBase; import com.genexus.servlet.IServletContext; import com.genexus.servlet.ServletContext; import com.genexus.servlet.http.IHttpServletRequest; @@ -18,7 +19,7 @@ import com.genexus.internet.HttpContext; import com.genexus.ws.GXHandlerChain; -public abstract class GXWebProcedure extends GXWebObjectBase +public abstract class GXWebProcedure extends GXObjectBase { private static final ILogger logger = LogManager.getLogger(GXWebProcedure.class); diff --git a/java/src/main/java/com/genexus/webpanels/HttpContextWeb.java b/java/src/main/java/com/genexus/webpanels/HttpContextWeb.java index a43ccb661..7a6c6e38d 100644 --- a/java/src/main/java/com/genexus/webpanels/HttpContextWeb.java +++ b/java/src/main/java/com/genexus/webpanels/HttpContextWeb.java @@ -42,27 +42,27 @@ public class HttpContextWeb extends HttpContext { HttpResponse httpRes; HttpRequest httpReq; - IServletContext servletContext; + protected IServletContext servletContext; - boolean useOldQueryStringFormat; + protected boolean useOldQueryStringFormat; protected Vector parms; private Hashtable namedParms; private Hashtable postData; private boolean useNamedParameters; private int currParameter; - private IHttpServletRequest request; - private IHttpServletResponse response; - private String requestMethod; + protected IHttpServletRequest request; + protected IHttpServletResponse response; + protected String requestMethod; protected String contentType = ""; - private boolean SkipPushUrl = false; + protected boolean SkipPushUrl = false; + protected boolean Redirected = false; private Hashtable cookies; private boolean streamSet = false; private WebSession webSession; private FileItemCollection fileItemCollection; private IFileItemIterator lstParts; private boolean ajaxCallAsPOST = false; - private boolean htmlHeaderClosed = false; private String sTmpDir; private boolean firstParConsumed = false; @@ -80,6 +80,18 @@ public class HttpContextWeb extends HttpContext { private static final String SAME_SITE_STRICT = "Strict"; private static final String SET_COOKIE = "Set-Cookie"; + public static final int BROWSER_OTHER = 0; + public static final int BROWSER_IE = 1; + public static final int BROWSER_NETSCAPE = 2; + public static final int BROWSER_OPERA = 3; + public static final int BROWSER_UP = 4; + public static final int BROWSER_POCKET_IE = 5; + public static final int BROWSER_FIREFOX = 6; + public static final int BROWSER_CHROME = 7; + public static final int BROWSER_SAFARI = 8; + public static final int BROWSER_EDGE = 9; + public static final int BROWSER_INDEXBOT = 20; + public boolean isMultipartContent() { return ServletFileUpload.isMultipartContent(request); } @@ -183,16 +195,8 @@ public FileItemCollection getPostedparts() { public HttpContext copy() { try { HttpContextWeb o = new HttpContextWeb(requestMethod, request, response, servletContext); - o.cookies = cookies; - o.webSession = webSession; - o.httpRes = httpRes; - o.httpReq = httpReq; - o.postData = postData; - o.parms = parms; - o.namedParms = namedParms; - o.streamSet = streamSet; - o.isCrawlerRequest = o.isCrawlerRequest(); copyCommon(o); + super.copyCommon(o); return o; } catch (java.io.IOException e) { @@ -200,6 +204,18 @@ public HttpContext copy() { } } + protected void copyCommon(HttpContextWeb o) { + o.cookies = cookies; + o.webSession = webSession; + o.httpRes = httpRes; + o.httpReq = httpReq; + o.postData = postData; + o.parms = parms; + o.namedParms = namedParms; + o.streamSet = streamSet; + o.isCrawlerRequest = o.isCrawlerRequest(); + } + public HttpContextWeb(String requestMethod, IHttpServletRequest req, IHttpServletResponse res, IServletContext servletContext) throws IOException { this(ClientContext.getModelContext().getClientPreferences().getProperty("UseNamedParameters", "1").equals("1"), requestMethod, req, res, servletContext); @@ -1256,7 +1272,23 @@ public WebSession getWebSession() { return webSession; } - private void redirect_http(String url) { + public void redirect(String url) { + redirect(url, false); + } + + public void redirect(String url, boolean bSkipPushUrl) { + SkipPushUrl = bSkipPushUrl; + if (!Redirected) { + redirect_impl(url, null); + } + } + + public void redirect_impl(String url, IGXWindow win) { + redirect_http(url); + } + + + protected void redirect_http(String url) { Redirected = true; if (getResponseCommited()) return; @@ -1310,129 +1342,13 @@ private void doForward(IRequestDispatcher dispatcher) throws Exception { dispatcher.forward(getRequest(), getResponse()); } - public void ajax_rsp_command_close() { - bCloseCommand = true; - try { - JSONObject closeParms = new JSONObject(); - closeParms.put("values", ObjArrayToJSONArray(this.getWebReturnParms())); - closeParms.put("metadata", ObjArrayToJSONArray(this.getWebReturnParmsMetadata())); - appendAjaxCommand("close", closeParms); - } catch (JSONException ex) { - } - } - - private void pushUrlSessionStorage() { + protected void pushUrlSessionStorage() { if (context != null && context.getHttpContext().isLocalStorageSupported() && !SkipPushUrl) { context.getHttpContext().pushCurrentUrl(); } SkipPushUrl = false; } - public boolean getHtmlHeaderClosed() { - return this.htmlHeaderClosed; - } - - public void closeHtmlHeader() { - this.htmlHeaderClosed = true; - this.writeTextNL(""); - } - - public void redirect_impl(String url, IGXWindow win) { - if (!isGxAjaxRequest() && !isAjaxRequest() && win == null) { - String popupLvl = getNavigationHelper(false).getUrlPopupLevel(getRequestNavUrl()); - String popLvlParm = ""; - if (popupLvl != "-1") { - popLvlParm = (url.indexOf('?') != -1) ? (useOldQueryStringFormat? "," : "&") : "?"; - popLvlParm += com.genexus.util.Encoder.encodeURL("gxPopupLevel=" + popupLvl + ";"); - } - - if (isSpaRequest(true)) { - pushUrlSessionStorage(); - getResponse().setHeader(GX_SPA_REDIRECT_URL, url + popLvlParm); - sendCacheHeaders(); - } else { - redirect_http(url + popLvlParm); - } - } else { - - try { - if (win != null) { - appendAjaxCommand("popup", win.GetJSONObject()); - } else if (!Redirected) { - JSONObject jsonCmd = new JSONObject(); - jsonCmd.put("url", url); - if (this.wjLocDisableFrm > 0) { - jsonCmd.put("forceDisableFrm", this.wjLocDisableFrm); - } - appendAjaxCommand("redirect", jsonCmd); - if (isGxAjaxRequest()) - dispatchAjaxCommands(); - Redirected = true; - } - } catch (JSONException e) { - redirect_http(url); - } - } - } - - private boolean isDocument(String url) { - try { - int idx = Math.max(url.lastIndexOf('/'), url.lastIndexOf('\\')); - if (idx >= 0 && idx < url.length()) { - url = url.substring(idx + 1); - } - idx = url.indexOf('?'); - String ext = url; - if (idx >= 0) { - ext = ext.substring(0, idx); - } - idx = url.lastIndexOf('.'); - if (idx >= 0) { - ext = ext.substring(idx); - } else { - ext = ""; - } - return (!ext.equals("") && !ext.startsWith(".aspx")); - } catch (Exception ex) { - log.error("isDocument error, url:" + url, ex); - return false; - } - } - - public void redirect(String url) { - redirect(url, false); - } - - public void redirect(String url, boolean bSkipPushUrl) { - SkipPushUrl = bSkipPushUrl; - if (!Redirected) { - redirect_impl(url, null); - } - } - - public void dispatchAjaxCommands() { - Boolean isResponseCommited = getResponseCommited(); - if (!getResponseCommited()) { - String res = getJSONResponsePrivate(""); - if (!isMultipartContent()) { - response.setContentType("application/json"); - } - sendFinalJSONResponse(res); - setResponseCommited(); - } - } - - public void sendFinalJSONResponse(String json) { - boolean isMultipartResponse = !getResponseCommited() && isMultipartContent(); - if (isMultipartResponse) { - _writeText( - ""); - } - public void setStream() { try { if (streamSet) { @@ -1537,6 +1453,13 @@ public void cleanup() { } } + public void writeText(String text) + { + if (getResponseCommited()) + return; + _writeText(text); + } + public boolean isHttpContextNull() {return false;} public boolean isHttpContextWeb() {return true;} -} +} \ No newline at end of file diff --git a/java/src/main/java/com/genexus/webpanels/WebUtils.java b/java/src/main/java/com/genexus/webpanels/WebUtils.java index 25f18c4db..881ef86de 100644 --- a/java/src/main/java/com/genexus/webpanels/WebUtils.java +++ b/java/src/main/java/com/genexus/webpanels/WebUtils.java @@ -324,7 +324,7 @@ public static String getEncodedContentDisposition(String value, int browserType) int filenameIdx = value.toLowerCase().indexOf("filename"); int eqIdx = value.toLowerCase().indexOf("=", filenameIdx); - if(filenameIdx == -1 || eqIdx == -1 || browserType == HttpContext.BROWSER_SAFARI) { //Safari does not support ContentDisposition Header encoded + if(filenameIdx == -1 || eqIdx == -1 || browserType == HttpContextWeb.BROWSER_SAFARI) { //Safari does not support ContentDisposition Header encoded return value; } diff --git a/pom.xml b/pom.xml index 3938a8094..9abd92366 100644 --- a/pom.xml +++ b/pom.xml @@ -8,13 +8,13 @@ parent ${revision}${changelist} pom - + GeneXus Standard Classes (Parent) Core classes for the runtime used by Java and Android apps generated with GeneXus https://github.com/genexuslabs/JavaClasses - 3.1 + 4.0 -SNAPSHOT From 257ab9a32714ec2d9c77bbfd6d231513e5dd34cf Mon Sep 17 00:00:00 2001 From: iroqueta Date: Fri, 12 May 2023 10:43:54 -0300 Subject: [PATCH 2/4] Refactor to move FrontEnd classes to gxweb module from gxclassR module. This allow run non FrontEnd object without Frontend support classes. Issue:102619 --- .../internet/GXWebProgressIndicator.java | 123 --- .../internet/GXWebProgressIndicatorInfo.java | 122 --- .../com/genexus/internet/HttpAjaxContext.java | 921 ------------------ .../com/genexus/security/web/SecureToken.java | 37 - .../security/web/SecureTokenHelper.java | 79 -- .../genexus/security/web/WebSecureToken.java | 121 --- .../security/web/WebSecurityHelper.java | 58 -- .../security/web/jose/jwt/Algorithm.java | 31 - .../web/jose/jwt/JWTAlgorithmException.java | 18 - .../web/jose/jwt/JWTAudienceException.java | 35 - .../web/jose/jwt/JWTExpiredException.java | 23 - .../web/jose/jwt/JWTIssuerException.java | 22 - .../security/web/jose/jwt/JWTSigner.java | 381 -------- .../security/web/jose/jwt/JWTVerifier.java | 234 ----- .../web/jose/jwt/JWTVerifyException.java | 18 - .../web/jose/jwt/pem/PemFileReader.java | 42 - .../web/jose/jwt/pem/PemFileWriter.java | 31 - .../security/web/jose/jwt/pem/PemReader.java | 66 -- .../security/web/jose/jwt/pem/PemWriter.java | 28 - .../web/jose/jwt/pem/X509CertUtils.java | 61 -- .../webpanels/DynAjaxEventContext.java | 48 - .../genexus/webpanels/GXWebObjectBase.java | 689 ------------- .../com/genexus/webpanels/GXWebReport.java | 186 ---- .../webpanels/IDynAjaxEventContext.java | 11 - 24 files changed, 3385 deletions(-) delete mode 100644 java/src/main/java/com/genexus/internet/GXWebProgressIndicator.java delete mode 100644 java/src/main/java/com/genexus/internet/GXWebProgressIndicatorInfo.java delete mode 100644 java/src/main/java/com/genexus/internet/HttpAjaxContext.java delete mode 100644 java/src/main/java/com/genexus/security/web/SecureToken.java delete mode 100644 java/src/main/java/com/genexus/security/web/SecureTokenHelper.java delete mode 100644 java/src/main/java/com/genexus/security/web/WebSecureToken.java delete mode 100644 java/src/main/java/com/genexus/security/web/WebSecurityHelper.java delete mode 100644 java/src/main/java/com/genexus/security/web/jose/jwt/Algorithm.java delete mode 100644 java/src/main/java/com/genexus/security/web/jose/jwt/JWTAlgorithmException.java delete mode 100644 java/src/main/java/com/genexus/security/web/jose/jwt/JWTAudienceException.java delete mode 100644 java/src/main/java/com/genexus/security/web/jose/jwt/JWTExpiredException.java delete mode 100644 java/src/main/java/com/genexus/security/web/jose/jwt/JWTIssuerException.java delete mode 100644 java/src/main/java/com/genexus/security/web/jose/jwt/JWTSigner.java delete mode 100644 java/src/main/java/com/genexus/security/web/jose/jwt/JWTVerifier.java delete mode 100644 java/src/main/java/com/genexus/security/web/jose/jwt/JWTVerifyException.java delete mode 100644 java/src/main/java/com/genexus/security/web/jose/jwt/pem/PemFileReader.java delete mode 100644 java/src/main/java/com/genexus/security/web/jose/jwt/pem/PemFileWriter.java delete mode 100644 java/src/main/java/com/genexus/security/web/jose/jwt/pem/PemReader.java delete mode 100644 java/src/main/java/com/genexus/security/web/jose/jwt/pem/PemWriter.java delete mode 100644 java/src/main/java/com/genexus/security/web/jose/jwt/pem/X509CertUtils.java delete mode 100644 java/src/main/java/com/genexus/webpanels/DynAjaxEventContext.java delete mode 100644 java/src/main/java/com/genexus/webpanels/GXWebObjectBase.java delete mode 100644 java/src/main/java/com/genexus/webpanels/GXWebReport.java delete mode 100644 java/src/main/java/com/genexus/webpanels/IDynAjaxEventContext.java diff --git a/java/src/main/java/com/genexus/internet/GXWebProgressIndicator.java b/java/src/main/java/com/genexus/internet/GXWebProgressIndicator.java deleted file mode 100644 index 46aebaffc..000000000 --- a/java/src/main/java/com/genexus/internet/GXWebProgressIndicator.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.genexus.internet; - -import com.genexus.ModelContext; - -public class GXWebProgressIndicator - { - private static String ID = "GX_PROGRESS_BAR"; - private GXWebNotification notification; - private GXWebProgressIndicatorInfo info; - private ModelContext context; - - public GXWebProgressIndicator(ModelContext gxContext) - { - context = gxContext; - notification = new GXWebNotification(gxContext); - info = new GXWebProgressIndicatorInfo(0,gxContext,""); - } - - public void show() - { - setAction("0"); - updateProgress(); - } - - private void updateProgress() - { - GXWebNotificationInfo notif = new GXWebNotificationInfo(0,context,""); - notif.setId(GXWebProgressIndicator.ID); - notif.setGroupName(GXWebProgressIndicator.ID); - notif.setMessage(info); - notification.notify(notif); - } - - public void showWithTitle(String title) - { - setTitle(title); - setAction("1"); - updateProgress(); - } - - public void showWithTitleAndDescription(String title, String desc) - { - setTitle(title); - setDescription(desc); - setAction("2"); - updateProgress(); - } - - public void hide() - { - setAction("3"); - updateProgress(); - } - - private String getAction() { - return info.getAction(); - } - - private void setAction(String action) { - info.setAction(action); - } - - private String getProgressMessage() - { - return info.toJSonString(); - } - - public String getCssClass() { - return info.getCssClass(); - } - - public void setCssClass(String cssClass) { - info.setCssClass(cssClass); - updateProgress(); - } - - public String getTitle() { - return info.getTitle(); - } - - public void setTitle(String title) { - info.setTitle(title); - updateProgress(); - } - - - public String getDescription() { - return info.getDescription(); - } - - public void setDescription(String description) { - info.setDescription(description); - updateProgress(); - } - - public int getMaxValue() { - return info.getMaxValue(); - } - - public void setMaxValue(int maxValue) { - info.setMaxValue(maxValue); - } - - public int getValue() { - return info.getValue(); - } - - public void setValue(int value) { - info.setValue(value); - updateProgress(); - } - - public byte getType() { - return info.getType(); - } - - public void setType(byte type) { - info.setType(type); - } - - - } - diff --git a/java/src/main/java/com/genexus/internet/GXWebProgressIndicatorInfo.java b/java/src/main/java/com/genexus/internet/GXWebProgressIndicatorInfo.java deleted file mode 100644 index 70dd62357..000000000 --- a/java/src/main/java/com/genexus/internet/GXWebProgressIndicatorInfo.java +++ /dev/null @@ -1,122 +0,0 @@ -package com.genexus.internet; - -import com.genexus.ModelContext; -import com.genexus.xml.GXXMLSerializable; -import com.genexus.xml.XMLReader; -import com.genexus.xml.XMLWriter; - - - public final class GXWebProgressIndicatorInfo extends GXXMLSerializable - { - private String action; /* 0: Show, 1:ShowWithTitle, 2: ShowWithTitleAndDesc, 3:Hide */ - private String cssClass; - private String title; - private String description; - private int maxValue; - private int value; - private byte type; - - public GXWebProgressIndicatorInfo(int arg0, ModelContext arg1, - String arg2) { - super(arg0, arg1, arg2); - // TODO Auto-generated constructor stub - } - - public void tojson( boolean includeState ) - { - AddObjectProperty("Action", action); - AddObjectProperty("Class", cssClass); - AddObjectProperty("Title", title); - AddObjectProperty("Description", description); - AddObjectProperty("MaxValue", maxValue); - AddObjectProperty("Value", value); - AddObjectProperty("Type", type); - } - - public void tojson( ) - { - tojson( true) ; - } - - public String getJsonMap(String value) {return null;} - - public void initialize() { - // TODO Auto-generated method stub - } - - - public short readxml(XMLReader arg0, String arg1) { - // TODO Auto-generated method stub - return 0; - } - - - public void writexml(XMLWriter arg0, String arg1, String arg2) { - // TODO Auto-generated method stub - - } - - - public void writexml(XMLWriter arg0, String arg1, String arg2, - boolean arg3) { - // TODO Auto-generated method stub - - } - - public String getCssClass() { - return cssClass; - } - - public void setCssClass(String cssClass) { - this.cssClass = cssClass; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getAction() { - return action; - } - - public void setAction(String action) { - this.action = action; - } - - public int getMaxValue() { - return maxValue; - } - - public void setMaxValue(int maxValue) { - this.maxValue = maxValue; - } - - public int getValue() { - return value; - } - - public void setValue(int value) { - this.value = value; - } - - public byte getType() { - return type; - } - - public void setType(byte type) { - this.type = type; - } - } - diff --git a/java/src/main/java/com/genexus/internet/HttpAjaxContext.java b/java/src/main/java/com/genexus/internet/HttpAjaxContext.java deleted file mode 100644 index 314367583..000000000 --- a/java/src/main/java/com/genexus/internet/HttpAjaxContext.java +++ /dev/null @@ -1,921 +0,0 @@ - -package com.genexus.internet; - -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Stack; -import java.util.Collections; -import java.util.Arrays; - -import com.genexus.IGXAssigned; -import com.genexus.common.interfaces.IGXWebGrid; -import com.genexus.diagnostics.core.ILogger; -import com.genexus.diagnostics.core.LogManager; -import com.genexus.webpanels.DynAjaxEventContext; -import com.genexus.common.interfaces.IGXWebRow; - -import json.org.json.IJsonFormattable; -import json.org.json.JSONArray; -import json.org.json.JSONException; -import json.org.json.JSONObject; - -public abstract class HttpAjaxContext -{ - public static final ILogger logger = LogManager.getLogger(HttpAjaxContext.class); - private JSONArray AttValues = new JSONArray(); - private JSONArray PropValues = new JSONArray(); - protected JSONObject HiddenValues = new JSONObject(); - protected JSONObject Messages = new JSONObject(); - private JSONObject WebComponents = new JSONObject(); - private Hashtable LoadCommands = new Hashtable<>(); - private ArrayList Grids = new ArrayList(); - private Hashtable DicGrids = new Hashtable(); - private JSONObject ComponentObjects = new JSONObject(); - protected GXAjaxCommandCollection commands = new GXAjaxCommandCollection(); - protected IGXWebRow _currentGridRow = null; - protected JSONArray StylesheetsToLoad = new JSONArray(); - - protected boolean bCloseCommand = false; - protected boolean Redirected = false; - protected boolean ajaxRefreshAsGET = false; - protected String formCaption = ""; - private Object[] returnParms = new Object[] {}; - private Object[] returnParmsMetadata = new Object[] {}; - - private Stack cmpContents = new Stack<>(); - - private String _ajaxOnSessionTimeout = "Ignore"; - public void setAjaxOnSessionTimeout( String ajaxOnSessionTimeout){ this._ajaxOnSessionTimeout = ajaxOnSessionTimeout;} - public String ajaxOnSessionTimeout(){ return _ajaxOnSessionTimeout;} - - DynAjaxEventContext dynAjaxEventContext = new DynAjaxEventContext(); - - public DynAjaxEventContext getDynAjaxEventContext() { - return dynAjaxEventContext; - } - - public abstract boolean isMultipartContent(); - public abstract void ajax_rsp_assign_prop_as_hidden(String Control, String Property, String Value); - - public abstract boolean isSpaRequest(); - public abstract boolean isSpaRequest(boolean ignoreFlag); - private boolean isJsOutputEnabled = true; - - public void disableJsOutput() - { - isJsOutputEnabled = false; - } - - public void enableJsOutput() - { - isJsOutputEnabled = true; - } - - public boolean isJsOutputEnabled() - { - return isJsOutputEnabled; - } - - public boolean isRedirected() - { - return Redirected; - } - - public boolean isCloseCommand() - { - return bCloseCommand; - } - - protected int nCmpDrawLvl = 0; - public MsgList GX_msglist = new MsgList(); - - private void doAjaxRefresh(String command) - { - try - { - String refreshMethod = "POST"; - if (ajaxRefreshAsGET) - { - refreshMethod = "GET"; - } - appendAjaxCommand(command, refreshMethod); - } - catch (JSONException ex) - { - } - } - - public void doAjaxRefresh() - { - doAjaxRefresh("refresh"); - } - - public void doAjaxRefreshForm() - { - doAjaxRefresh("refresh_form"); - } - - public void doAjaxRefreshCmp(String sPrefix) - { - try - { - appendAjaxCommand("cmp_refresh", sPrefix); - } - catch (JSONException ex) - { - } - } - - public void doAjaxLoad(int SId, IGXWebRow row) - { - try - { - JSONObject JSONRow = new JSONObject(); - JSONRow.put("grid", SId); - JSONRow.put("props", row.getParentGrid().GetJSONObject()); - JSONRow.put("values", row.getParentGrid().GetValues()); - appendLoadData(SId, JSONRow); - } - catch (JSONException ex) - { - } - } - - public void doAjaxAddLines(int SId, int lines) - { - try - { - JSONObject JSONData = new JSONObject(); - JSONData.put("grid", SId); - JSONData.put("count", lines); - appendAjaxCommand("addlines", JSONData); - } - catch (JSONException ex) - { - } - } - - public void doAjaxSetFocus(String controlName) - { - try - { - appendAjaxCommand("set_focus", controlName); - } - catch (JSONException ex) - { - } - } - - protected Object[] getWebReturnParms() - { - return this.returnParms; - } - - protected Object[] getWebReturnParmsMetadata() - { - return this.returnParmsMetadata; - } - - public void setWebReturnParms(Object[] retParms) - { - this.returnParms = retParms; - } - - public void setWebReturnParmsMetadata(Object[] retParmsMetadata) - { - this.returnParmsMetadata = retParmsMetadata; - } - - public void appendAjaxCommand(String cmdType, Object cmdData) throws JSONException - { - commands.AppendCommand(new GXAjaxCommand(cmdType, cmdData)); - } - - public void appendLoadData(int SId, JSONObject Data) throws JSONException - { - LoadCommands.put(SId, Data); - } - - public void executeUsercontrolMethod(String CmpContext, boolean IsMasterPage, String containerName, String methodName, String input, Object[] parms) - { - GXUsercontrolMethod method = new GXUsercontrolMethod(CmpContext, IsMasterPage, containerName, methodName, input, parms); - commands.AppendCommand(new GXAjaxCommand("ucmethod", method.GetJSONObject())); - } - - public void setExternalObjectProperty(String CmpContext, boolean IsMasterPage, String containerName, String propertyName, Object value) - { - JSONObject obj = new JSONObject(); - try - { - obj.put("CmpContext", CmpContext); - obj.put("IsMasterPage", IsMasterPage); - obj.put("ObjectName", containerName); - obj.put("PropertyName", propertyName); - obj.put("Value", value); - } catch (JSONException ex) { - } - commands.AppendCommand(new GXAjaxCommand("exoprop", obj)); - } - - public void executeExternalObjectMethod(String CmpContext, boolean IsMasterPage, String containerName, String methodName, Object[] parms, boolean isEvent) - { - JSONObject obj = new JSONObject(); - try - { - obj.put("CmpContext", CmpContext); - obj.put("IsMasterPage", IsMasterPage); - obj.put("ObjectName", containerName); - obj.put("Method", methodName); - obj.put("Parms", HttpAjaxContext.ObjArrayToJSONArray(parms)); - obj.put("IsEvent", isEvent); - } catch (JSONException ex) { - } - commands.AppendCommand(new GXAjaxCommand("exomethod", obj)); - } - - protected void addPrintReportCommand(String reportFile, String printerRule) - { - JSONObject obj = new JSONObject(); - try - { - obj.put("reportFile", reportFile); - obj.put("printerRule", printerRule); - } - catch (JSONException e) { } - commands.AppendCommand(new GXAjaxCommand("print", obj)); - } - - protected void ajax_addCmpContent( String content) - { - if (nCmpDrawLvl > 0) - (cmpContents.peek()).addContent(content); - } - - public void ajax_rspStartCmp( String CmpId) - { - if (isJsOutputEnabled) - { - try - { - WebComponents.put(CmpId, ""); - } - catch (JSONException ex) { } - } - nCmpDrawLvl++; - cmpContents.push(new GXCmpContent(CmpId)); - } - - public void ajax_rspEndCmp() - { - nCmpDrawLvl--; - try - { - GXCmpContent cmp = cmpContents.pop(); - WebComponents.put(cmp.getId(), cmp.getContent()); - if (isSpaRequest()) - { - if (nCmpDrawLvl > 0) - (cmpContents.peek()).addContent(cmp.getContent()); - } - } - catch (JSONException ex) - { - } - } - - private JSONObject getGxObject(JSONArray array, String CmpContext, boolean IsMasterPage) - { - try - { - JSONObject obj; - int len = array.length(); - for(int i=0; i= 0) - return; - } - if (Control.equals("FORM") && Property.equals("Caption")) - { - formCaption = Value; - } - JSONObject obj = getGxObject(PropValues, CmpContext, IsMasterPage); - if (obj != null) - { - JSONObject ctrlProps = getControlProps(obj, Control); - if (ctrlProps != null) - { - ctrlProps.put(Property, Value); - } - } - com.genexus.internet.HttpContext webContext = (HttpContext) com.genexus.ModelContext.getModelContext().getHttpContext(); - if (webContext != null && !webContext.isAjaxRequest()) - { - ajax_rsp_assign_hidden(Control + "_" + Property.substring(0, 1) + Property.substring(1).toLowerCase(), Value); - } - } - catch (JSONException e) { - } - } - } - } - - public void ajax_rsp_assign_uc_prop(String CmpContext, boolean IsMasterPage, String Control, String Property, String Value) - { - ajax_rsp_assign_prop(CmpContext, IsMasterPage, Control, Property, Value, true); - ajax_rsp_assign_prop_as_hidden(Control, Property, Value); - } - - public void ajax_rsp_assign_boolean_hidden(String Property, Boolean Value) - { - ajax_rsp_assign_hidden(Property, (Object)Value); - } - - public void ajax_rsp_assign_hidden(String Property, String Value) - { - ajax_rsp_assign_hidden(Property, (Object)Value); - } - - private void ajax_rsp_assign_hidden(String Property, Object Value) - { - try { - if (_currentGridRow != null) - _currentGridRow.AddHidden(Property, Value); - else - HiddenValues.put(Property, Value); - } - catch (JSONException e) { - } - } - - public void ajax_rsp_assign_hidden_sdt( String SdtName, Object SdtObj) - { - try { - if (SdtObj instanceof IGxJSONAble) - { - HiddenValues.put(SdtName, ((IGxJSONAble)SdtObj).GetJSONObject()); - } - else - { - if (SdtObj.getClass().isArray()) - { - try { - HiddenValues.put(SdtName, ObjArrayToJSONArray(SdtObj)); - } - catch(ClassCastException e){ - logger.error(String.format("Could not serialize Object '%s' to JSON", SdtName), e); - HiddenValues.put(SdtName, SdtObj); - } - } - } - } - catch (JSONException e) { - logger.error(String.format("Could not serialize Object '%s' to JSON", SdtName), e); - } - } - - public void ajax_rsp_assign_grid(String gridName, IGXWebGrid gridObj) - { - Object jsonObj = ((IGxJSONAble) gridObj).GetJSONObject(); - Grids.add(jsonObj); - } - - public void ajax_rsp_assign_grid(String gridName, IGXWebGrid gridObj, String Control) - { - Object jsonObj = ((IGxJSONAble) gridObj).GetJSONObject(); - if (DicGrids.containsKey(Control)) { - Grids.set(DicGrids.get(Control), jsonObj); - } - else - { - Grids.add(jsonObj); - DicGrids.put(Control, Grids.size() - 1); - } - } - - public void ajax_rsp_clear(){ - PropValues = new JSONArray(); - } - - private boolean shouldLogAjaxControlProperty(String property) - { - return isJsOutputEnabled || (isSpaRequest() && property == "Enabled"); - } - - @Deprecated - public void AddComponentObject(String cmpCtx, String objName) - { - AddComponentObject(cmpCtx, objName, true); - } - - public void AddComponentObject(String cmpCtx, String objName, boolean justCreated) - { - try { - com.genexus.internet.HttpContext webContext = (HttpContext) com.genexus.ModelContext.getModelContext().getHttpContext(); - if (justCreated) - { - try { - webContext.DeletePostValuePrefix(cmpCtx); - } - catch (Exception e) { - logger.error("Could not delete post value prefix", e); - } - } - ComponentObjects.put(cmpCtx, objName); - } - catch (JSONException e) { - } - } - - public void SendComponentObjects() - { - try { - HiddenValues.put("GX_CMP_OBJS", ComponentObjects); - } - catch (JSONException e) { - } - } - - protected void AddThemeHidden(String theme) - { - try { - HiddenValues.put("GX_THEME", theme); - } - catch (JSONException e) { - } - } - - public void AddStylesheetsToLoad() - { - if (StylesheetsToLoad.length() > 0) - { - try { - HiddenValues.put("GX_STYLE_FILES", StylesheetsToLoad); - } - catch (JSONException e) { - } - } - } - - public void SaveComponentMsgList( String sPrefix) - { - try { - Messages.put(sPrefix, GX_msglist.GetJSONObject()); - } - catch (JSONException e) { - } - } - - public String getJSONContainerResponse(IGxJSONAble Container) { - - GXJSONObject jsonCmdWrapper = new GXJSONObject(isMultipartContent()); - try - { - jsonCmdWrapper.put("gxHiddens", HiddenValues); - jsonCmdWrapper.put("gxContainer", Container.GetJSONObject()); - } - catch (JSONException e) - { - } - return jsonCmdWrapper.toString(); - } - - protected String getJSONResponsePrivate(String cmpContext) - { - GXJSONObject jsonCmdWrapper = new GXJSONObject(isMultipartContent()); - try - { - Collections.reverse(Arrays.asList(Grids)); - JSONArray JSONGrids = new JSONArray(Grids); - if (commands.AllowUIRefresh()) - { - if (cmpContext == null || cmpContext.equals("")) - { - cmpContext = "MAIN"; - } - SaveComponentMsgList(cmpContext); - jsonCmdWrapper.put("gxProps", PropValues); - jsonCmdWrapper.put("gxHiddens", HiddenValues); - jsonCmdWrapper.put("gxValues", AttValues); - jsonCmdWrapper.put("gxMessages", Messages); - jsonCmdWrapper.put("gxComponents", WebComponents); - jsonCmdWrapper.put("gxGrids", JSONGrids); - } - for(Enumeration loadCmds = LoadCommands.keys(); loadCmds.hasMoreElements();) - { - appendAjaxCommand("load", LoadCommands.get(loadCmds.nextElement())); - } - if (commands.getCount() > 0) - { - jsonCmdWrapper.put("gxCommands", commands.getJSONArray()); - } - } - catch (JSONException e) - { - } - return jsonCmdWrapper.toString(); - } - - public String getJSONResponse(String cmpContext) - { - if (isCloseCommand() || isRedirected()) - return ""; - return getJSONResponsePrivate(cmpContext); - } - - public String getJSONResponse() - { - return getJSONResponse(""); - } - - public static Object[] createArrayFromArrayObject(Object o) { - if(!o.getClass().getComponentType().isPrimitive()) - return (Object[])o; - - int element_count = Array.getLength(o); - Object elements[] = new Object[element_count]; - - for(int i = 0; i < element_count; i++){ - elements[i] = Array.get(o, i); - } - - return elements; - } - - public static JSONArray ObjArrayToJSONArray(Object parms) - { - return ObjArrayToJSONArray(createArrayFromArrayObject(parms)); - } - - public static JSONArray ObjArrayToJSONArray(Object[] parms) - { - JSONArray inputs = new JSONArray(); - for (int i = 0; i < parms.length; i++) - { - Object parm = parms[i]; - if (parm instanceof IGxJSONAble) - { - inputs.put(((IGxJSONAble)parm).GetJSONObject()); - } - else if (parm.getClass().isArray()) - { - inputs.put(ObjArrayToJSONArray((Object[])parm)); - } - else - { - inputs.put(parm); - } - } - return inputs; - } - - public String getWebReturnParmsJS() - { - return ObjArrayToJSONArray(this.getWebReturnParms()).toString(); - } - - public String getWebReturnParmsMetadataJS() - { - return ObjArrayToJSONArray(this.getWebReturnParmsMetadata()).toString(); - } - - class GXCmpContent - { - private String id; - private String content; - - public GXCmpContent(String id) - { - this.id = id; - this.content = ""; - } - - public String getId() - { - return id; - } - - public void addContent(String content) - { - this.content += content; - } - - public String getContent() - { - return content; - } - } - - class GXAjaxCommand - { - private String[] canManyCmds = new String[] { "print", "load", "popup", "refresh", "ucmethod", "cmp_refresh", "addlines", "set_focus", "calltarget", "exoprop", "exomethod", "refresh_form" }; - private String type; - private Object data; - - public GXAjaxCommand(String type) - { - this.type = type; - this.data = ""; - } - - public GXAjaxCommand(String type, Object data) - { - this.type = type; - this.data = data; - } - - public String getType() - { - return type; - } - - public void setData(Object data) - { - this.data = data; - } - - public Object getData() - { - return data; - } - - public JSONObject getJSONObject() - { - JSONObject jObj = new JSONObject(); - try { - jObj.put(type, data); - } catch (JSONException ex) { - } - return jObj; - } - - public boolean canHaveMany() - { - for (int i = 0; i < canManyCmds.length; i++) - { - if (type.equals(canManyCmds[i])) - { - return true; - } - } - return false; - } - - public boolean equals(Object obj) - { - if (obj instanceof GXAjaxCommand) - { - if (!canHaveMany()) - { - return (type.equalsIgnoreCase(((GXAjaxCommand)obj).getType())); - } - } - return super.equals(obj); - } - - public String toString() - { - return "{ type:" + type + ", data:" + data + " }"; - } - } - - public class GXUsercontrolMethod implements IGxJSONAble - { - JSONObject wrapper; - - public GXUsercontrolMethod(String CmpContext, boolean IsMasterPage, String containerName, String methodName, String output, Object[] parms) - { - wrapper = new JSONObject(); - AddObjectProperty("CmpContext", CmpContext); - AddObjectProperty("IsMasterPage", new Boolean(IsMasterPage)); - AddObjectProperty("Control", containerName); - AddObjectProperty("Method", methodName); - AddObjectProperty("Output", output); - AddObjectProperty("Parms", HttpAjaxContext.ObjArrayToJSONArray(parms)); - } - - public JSONArray GetParmsJArray(Object[] parms) - { - JSONArray inputs = new JSONArray(); - for (int i = 0; i < parms.length; i++) - { - Object parm = parms[i]; - if (parm instanceof IGxJSONAble) - { - inputs.put(((IGxJSONAble)parm).GetJSONObject()); - } - else - { - inputs.put(parm); - } - } - return inputs; - } - - public void AddObjectProperty(String name, Object prop) - { - try - { - wrapper.put(name, prop); - } catch (JSONException ex) { - } - } - - public Object GetJSONObject(boolean includeState) - { - return GetJSONObject(); - } - - public Object GetJSONObject() - { - return wrapper; - } - - public void FromJSONObject(IJsonFormattable obj) - { - } - - public String ToJavascriptSource() - { - return wrapper.toString(); - } - - public void tojson() - { - } - } - - class GXAjaxCommandCollection - { - private ArrayList commands; - private boolean allowUIRefresh; - - public GXAjaxCommandCollection() - { - commands = new ArrayList<>(); - allowUIRefresh = true; - } - - public int getCount() - { - return commands.size(); - } - - public boolean AllowUIRefresh() - { - return allowUIRefresh; - } - - public void AppendCommand(GXAjaxCommand cmd) - { - GXAjaxCommand cmd1 = GetCommand(cmd); - if (cmd1 == null) - { - if (allowUIRefresh) - { - allowUIRefresh = cmd.canHaveMany(); - } - commands.add(cmd); - } - else - { - cmd1.setData(cmd.getData()); - } - } - - private GXAjaxCommand GetCommand(GXAjaxCommand cmd) - { - int cIdx = commands.indexOf(cmd); - if (cIdx > 0) - { - return commands.get(cIdx); - } - return null; - } - - public JSONArray getJSONArray() - { - JSONArray jArr = new JSONArray(); - for(int i=0; i claims; - - try { - claims = new ObjectMapper().readValue(payload, Map.class); - } - catch (JsonProcessingException e) { - logger.error("Signature Error - Failed to serialize payload", e); - return ""; - } - - switch (mode) - { - case Sign: - try { - encoded = signer.sign(claims); - } catch (Exception e) { - logger.error("Signature Error", e); - } - break; - case SignEncrypt: - case None: - logger.warn(String.format("Signature Mode '%s' not implemented", mode)); - break; - } - return encoded; - } - - public static boolean verify(String jwtToken, SecureToken outToken, String secretKey) - { - JWTVerifier verifier = new JWTVerifier(secretKey); - boolean ok = false; - if (!StringUtils.isBlank(jwtToken)) - { - try { - Map mapObj = verifier.verify(jwtToken); - JSONObject jObj = new JSONObject(mapObj); - outToken.FromJSONObject(jObj); - ok = true; - } - catch (Exception e) - { - logger.debug(String.format("Web Token Encryption Exception for Token \nTOKEN: '%s'", jwtToken), e); - } - } - return ok; - } -} diff --git a/java/src/main/java/com/genexus/security/web/WebSecureToken.java b/java/src/main/java/com/genexus/security/web/WebSecureToken.java deleted file mode 100644 index cece09808..000000000 --- a/java/src/main/java/com/genexus/security/web/WebSecureToken.java +++ /dev/null @@ -1,121 +0,0 @@ -package com.genexus.security.web; - -import java.util.Date; - -import org.apache.commons.lang.StringUtils; - -import json.org.json.IJsonFormattable; -import json.org.json.JSONException; -import json.org.json.JSONObject; - -public class WebSecureToken extends SecureToken { - private static int TOKEN_DAYS_EXPIRATION = 15; - private static String JSON_ISSUER_NAME = "gx-issuer"; - private static String JSON_EXPIRATION_NAME = "gx-exp"; - private static String JSON_PGMNAME_NAME = "gx-pgm"; - private static String JSON_VALUE_NAME = "gx-val"; - - private String _issuer = ""; - private String _pgmName = ""; - private String _value = ""; - private Date _expiration; - - private JSONObject _jObj = new JSONObject(); - - public WebSecureToken(){ - _expiration = org.apache.commons.lang.time.DateUtils.addDays(new Date(), TOKEN_DAYS_EXPIRATION); - } - - public WebSecureToken(String pgmName, String issuer, String value) { - _expiration = org.apache.commons.lang.time.DateUtils.addDays(new Date(), TOKEN_DAYS_EXPIRATION); - _pgmName = pgmName; - _value = value; - _issuer = issuer; - } - - public String get_issuer() { - return _issuer; - } - public void set_issuer(String _issuer) { - this._issuer = _issuer; - } - public String get_pgmName() { - return _pgmName; - } - public void set_pgmName(String _pgmName) { - this._pgmName = _pgmName; - } - public String get_value() { - return _value; - } - public void set_value(String _value) { - this._value = _value; - } - public Date get_expiration() { - return _expiration; - } - public void set_expiration(Date _expiration) { - this._expiration = _expiration; - } - - public void tojson() - { - AddObjectProperty(WebSecureToken.JSON_ISSUER_NAME, _issuer); - AddObjectProperty(WebSecureToken.JSON_PGMNAME_NAME, _pgmName); - AddObjectProperty(WebSecureToken.JSON_VALUE_NAME, _value); - AddObjectProperty(WebSecureToken.JSON_EXPIRATION_NAME, Long.toString(_expiration.getTime())); - } - - public void AddObjectProperty(String name, Object prop) - { - String ptyValue = ((String)prop); - if (!StringUtils.isBlank(name) && !StringUtils.isBlank(ptyValue)) - { - try { - _jObj.put(name, ptyValue); - } - catch (JSONException e) { - } - } - } - - public Object GetJSONObject() - { - tojson(); - return _jObj; - } - - public Object GetJSONObject(boolean includeState) - { - return GetJSONObject(); - } - - public void FromJSONObject(IJsonFormattable obj) - { - JSONObject jObj = (JSONObject) obj; - this._issuer = getJsonPtyValueString(jObj, WebSecureToken.JSON_ISSUER_NAME); - this._value = getJsonPtyValueString(jObj, WebSecureToken.JSON_VALUE_NAME); - this._pgmName = getJsonPtyValueString(jObj, WebSecureToken.JSON_PGMNAME_NAME); - String expLong = getJsonPtyValueString(jObj, WebSecureToken.JSON_EXPIRATION_NAME); - if (!StringUtils.isBlank(expLong)){ - this._expiration.setTime(Long.parseLong(expLong)); - } - } - - public String ToJavascriptSource() - { - return GetJSONObject().toString(); - } - - private String getJsonPtyValueString(JSONObject jObj, String name) - { - if (jObj.has(name)) - try { - return jObj.getString(name); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return ""; - } -} diff --git a/java/src/main/java/com/genexus/security/web/WebSecurityHelper.java b/java/src/main/java/com/genexus/security/web/WebSecurityHelper.java deleted file mode 100644 index 4a35d07aa..000000000 --- a/java/src/main/java/com/genexus/security/web/WebSecurityHelper.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.genexus.security.web; - -import java.util.Date; - -import org.apache.commons.lang.StringUtils; -import org.apache.logging.log4j.Logger; - -import com.genexus.security.web.SecureTokenHelper.SecurityMode; - -public class WebSecurityHelper { - - private static Logger log = org.apache.logging.log4j.LogManager.getLogger(WebSecurityHelper.class); - - public static String StripInvalidChars(String input) - { - if (input == null) - return input; - String output = input.replaceAll("[\u0000-\u001f]", ""); - return StringUtils.strip(output); - } - - public static String sign(String pgmName, String issuer, String value, SecurityMode mode, String key) - { - WebSecureToken token = new WebSecureToken(pgmName, issuer, StripInvalidChars(value)); - return SecureTokenHelper.sign(token, mode, key); - } - - public static boolean verify(String pgmName, String issuer, String value, String jwtToken, String key) - { - WebSecureToken token = new WebSecureToken(); - if(!SecureTokenHelper.verify(jwtToken, token, key)) - return false; - boolean ret = !StringUtils.isBlank(pgmName) && token.get_pgmName().equals(pgmName) && issuer.equals(token.get_issuer()) && - StripInvalidChars(value).equals(StripInvalidChars(token.get_value())) && new Date().compareTo(token.get_expiration()) < 0; - if (!ret && log.isDebugEnabled()) { - String lsep = System.getProperty("line.separator"); - - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append("Verify: Invalid token" + lsep); - - if (!(token.get_pgmName().equals(pgmName))) { - stringBuilder.append(String.format("Verify: pgmName mismatch '%s' <> '%s' %s", token.get_pgmName(), pgmName, lsep)); - } - if (!(token.get_issuer().equals(issuer))) { - stringBuilder.append(String.format("Verify: issuer mismatch '%s' <> '%s' %s", token.get_issuer(), issuer, lsep)); - } - if (!StripInvalidChars(value).equals(StripInvalidChars(token.get_value()))) { - stringBuilder.append(String.format("Verify: value mismatch '%s' <> '%s' %s", token.get_value(), value, lsep)); - } - if (!(new Date().compareTo(token.get_expiration()) < 0)) { - stringBuilder.append("Verify: token expired "); - } - log.error(stringBuilder.toString()); - } - return ret; - } - -} diff --git a/java/src/main/java/com/genexus/security/web/jose/jwt/Algorithm.java b/java/src/main/java/com/genexus/security/web/jose/jwt/Algorithm.java deleted file mode 100644 index e69034c51..000000000 --- a/java/src/main/java/com/genexus/security/web/jose/jwt/Algorithm.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.genexus.security.web.jose.jwt; - - -/** - * Supported Library Algorithms - * - * https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyPairGenerator - */ -public enum Algorithm { - - HS256("HmacSHA256"), HS384("HmacSHA384"), HS512("HmacSHA512"), RS256("SHA256withRSA"), RS384("SHA384withRSA"), RS512("SHA512withRSA"); - - private Algorithm(final String value) { - this.value = value; - } - - private String value; - - public String getValue() { - return value; - } - - public static Algorithm findByName(final String name) throws JWTAlgorithmException { - try { - return Algorithm.valueOf(name); - } catch (IllegalArgumentException e) { - throw new JWTAlgorithmException("Unsupported algorithm: " + name); - } - } - -} diff --git a/java/src/main/java/com/genexus/security/web/jose/jwt/JWTAlgorithmException.java b/java/src/main/java/com/genexus/security/web/jose/jwt/JWTAlgorithmException.java deleted file mode 100644 index 42eef6e49..000000000 --- a/java/src/main/java/com/genexus/security/web/jose/jwt/JWTAlgorithmException.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.genexus.security.web.jose.jwt; - -/** - * Represents Exception related to Algorithm - for example JWT header algorithm is unsupported / missing - */ -public class JWTAlgorithmException extends JWTVerifyException { - public JWTAlgorithmException() {} - - public JWTAlgorithmException(final String message, final Throwable cause) { - super(message, cause); - } - - public JWTAlgorithmException(final String message) { - super(message); - } - -} - diff --git a/java/src/main/java/com/genexus/security/web/jose/jwt/JWTAudienceException.java b/java/src/main/java/com/genexus/security/web/jose/jwt/JWTAudienceException.java deleted file mode 100644 index 974ab9a02..000000000 --- a/java/src/main/java/com/genexus/security/web/jose/jwt/JWTAudienceException.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.genexus.security.web.jose.jwt; - -import java.util.ArrayList; -import java.util.List; - -import com.fasterxml.jackson.databind.JsonNode; - -/** - * Represents Exception related to Audience - for example illegal audience on JWT Verification - */ -public class JWTAudienceException extends JWTVerifyException { - - private JsonNode audienceNode; - - public JWTAudienceException(final JsonNode audienceNode) { - this.audienceNode = audienceNode; - } - - public JWTAudienceException(final String message, final JsonNode audienceNode) { - super(message); - this.audienceNode = audienceNode; - } - - public List getAudience() { - final ArrayList audience = new ArrayList(); - if (audienceNode.isArray()) { - for (final JsonNode jsonNode : audienceNode) { - audience.add(jsonNode.textValue()); - } - } else if (audienceNode.isTextual()) { - audience.add(audienceNode.textValue()); - } - return audience; - } -} diff --git a/java/src/main/java/com/genexus/security/web/jose/jwt/JWTExpiredException.java b/java/src/main/java/com/genexus/security/web/jose/jwt/JWTExpiredException.java deleted file mode 100644 index b2b6cba90..000000000 --- a/java/src/main/java/com/genexus/security/web/jose/jwt/JWTExpiredException.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.genexus.security.web.jose.jwt; - - -/** - * Represents Exception related to Expiration - for example JWT token has expired - */ -public class JWTExpiredException extends JWTVerifyException { - - private long expiration; - - public JWTExpiredException(final long expiration) { - this.expiration = expiration; - } - - public JWTExpiredException(final String message, final long expiration) { - super(message); - this.expiration = expiration; - } - - public long getExpiration() { - return expiration; - }; -} diff --git a/java/src/main/java/com/genexus/security/web/jose/jwt/JWTIssuerException.java b/java/src/main/java/com/genexus/security/web/jose/jwt/JWTIssuerException.java deleted file mode 100644 index 97df0fdfd..000000000 --- a/java/src/main/java/com/genexus/security/web/jose/jwt/JWTIssuerException.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.genexus.security.web.jose.jwt; - -/** - * Represents Exception related to Issuer - for example issuer mismatch / missing upon verification - */ -public class JWTIssuerException extends JWTVerifyException { - - private final String issuer; - - public JWTIssuerException(final String issuer) { - this.issuer = issuer; - } - - public JWTIssuerException(final String message, final String issuer) { - super(message); - this.issuer = issuer; - } - - public String getIssuer() { - return issuer; - } -} diff --git a/java/src/main/java/com/genexus/security/web/jose/jwt/JWTSigner.java b/java/src/main/java/com/genexus/security/web/jose/jwt/JWTSigner.java deleted file mode 100644 index 3e66093f5..000000000 --- a/java/src/main/java/com/genexus/security/web/jose/jwt/JWTSigner.java +++ /dev/null @@ -1,381 +0,0 @@ -package com.genexus.security.web.jose.jwt; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URISyntaxException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PrivateKey; -import java.security.Security; -import java.security.Signature; -import java.security.SignatureException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import org.apache.commons.lang.StringUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; - -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.lang.Validate; -import org.bouncycastle.jce.provider.BouncyCastleProvider; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.JsonNodeFactory; -import com.fasterxml.jackson.databind.node.ObjectNode; - -/** - * Handles JWT Sign Operation - * - * Default algorithm when none provided is HMAC SHA-256 ("HS256") - * - * See associated library test cases for clear examples on usage - * - */ -public class JWTSigner { - - static { - if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { - Security.addProvider(new BouncyCastleProvider()); - } - } - - private byte[] secret; - private PrivateKey privateKey; - private static Logger logger = LogManager.getLogger(JWTSigner.class); - - // Default algorithm HMAC SHA-256 ("HS256") - protected final static Algorithm DEFAULT_ALGORITHM = Algorithm.HS256; - - public JWTSigner(final String secret) { - this(secret.getBytes()); - } - - public JWTSigner(final byte[] secret) { - Validate.notNull(secret); - this.secret = secret; - } - - public JWTSigner(final PrivateKey privateKey) { - this.privateKey = privateKey; - } - - /** - * Generate a JSON Web Token. - * - * @param claims A map of the JWT claims that form the payload. Registered claims - * must be of appropriate Java datatype as following: - *
    - *
  • iss, sub: String - *
  • exp, nbf, iat, jti: numeric, eg. Long - *
  • aud: String, or Collection<String> - *
- * All claims with a null value are left out the JWT. - * Any claims set automatically as specified in - * the "options" parameter override claims in this map. - * @param options Allow choosing the signing algorithm, and automatic setting of some registered claims. - */ - public String sign(final Map claims, final Options options) { - Validate.notNull(claims, "JWT claims cannot be null"); - final Algorithm algorithm = (options != null && options.algorithm != null) ? options.algorithm : DEFAULT_ALGORITHM; - final List segments = new ArrayList(); - try { - segments.add(encodedHeader(algorithm)); - segments.add(encodedPayload(claims, options)); - segments.add(encodedSignature(join(segments, "."), algorithm)); - return join(segments, "."); - } catch (Exception e) { - logger.error("JWT Sign error", e); - throw new RuntimeException(e.getCause()); - } - } - - /** - * Generate a JSON Web Token using the default algorithm HMAC SHA-256 ("HS256") - * and no claims automatically set. - */ - public String sign(final Map claims) { - Validate.notNull(claims); - return sign(claims, null); - } - - /** - * Generate the header part of a JSON web token. - */ - private String encodedHeader(final Algorithm algorithm) throws UnsupportedEncodingException { - Validate.notNull(algorithm); - // create the header - final ObjectNode header = JsonNodeFactory.instance.objectNode(); - header.put("typ", "JWT"); - header.put("alg", algorithm.name()); - return base64UrlEncode(header.toString().getBytes("UTF-8")); - } - - /** - * Generate the JSON web token payload string from the claims. - * - * @param options - */ - private String encodedPayload(final Map _claims, final Options options) throws IOException { - final Map claims = new HashMap(_claims); - enforceStringOrURI(claims, "iss"); - enforceStringOrURI(claims, "sub"); - enforceStringOrURICollection(claims, "aud"); - enforceIntDate(claims, "exp"); - enforceIntDate(claims, "nbf"); - enforceIntDate(claims, "iat"); - enforceString(claims, "jti"); - if (options != null) { - processPayloadOptions(claims, options); - } - final String payload = new ObjectMapper().writeValueAsString(claims); - return base64UrlEncode(payload.getBytes("UTF-8")); - } - - private void processPayloadOptions(final Map claims, final Options options) { - Validate.notNull(claims); - Validate.notNull(options); - final long now = System.currentTimeMillis() / 1000l; - if (options.expirySeconds != null) - claims.put("exp", now + options.expirySeconds); - if (options.notValidBeforeLeeway != null) - claims.put("nbf", now - options.notValidBeforeLeeway); - if (options.isIssuedAt()) - claims.put("iat", now); - if (options.isJwtId()) - claims.put("jti", UUID.randomUUID().toString()); - } - - // consider cleanup - private void enforceIntDate(final Map claims, final String claimName) { - Validate.notNull(claims); - Validate.notNull(claimName); - final Object value = handleNullValue(claims, claimName); - if (value == null) - return; - if (!(value instanceof Number)) { - throw new IllegalStateException(String.format("Claim '%s' is invalid: must be an instance of Number", claimName)); - } - final long longValue = ((Number) value).longValue(); - if (longValue < 0) - throw new IllegalStateException(String.format("Claim '%s' is invalid: must be non-negative", claimName)); - claims.put(claimName, longValue); - } - - // consider cleanup - private void enforceStringOrURICollection(final Map claims, final String claimName) { - final Object values = handleNullValue(claims, claimName); - if (values == null) - return; - if (values instanceof Collection) { - @SuppressWarnings({"unchecked"}) - final Iterator iterator = ((Collection) values).iterator(); - while (iterator.hasNext()) { - Object value = iterator.next(); - String error = checkStringOrURI(value); - if (error != null) - throw new IllegalStateException(String.format("Claim 'aud' element is invalid: %s", error)); - } - } else { - enforceStringOrURI(claims, "aud"); - } - } - - // consider cleanup - private void enforceStringOrURI(final Map claims, final String claimName) { - final Object value = handleNullValue(claims, claimName); - if (value == null) - return; - final String error = checkStringOrURI(value); - if (error != null) - throw new IllegalStateException(String.format("Claim '%s' is invalid: %s", claimName, error)); - } - - // consider cleanup - private void enforceString(final Map claims, final String claimName) { - final Object value = handleNullValue(claims, claimName); - if (value == null) - return; - if (!(value instanceof String)) - throw new IllegalStateException(String.format("Claim '%s' is invalid: not a string", claimName)); - } - - // consider cleanup - private Object handleNullValue(final Map claims, final String claimName) { - if (!claims.containsKey(claimName)) - return null; - final Object value = claims.get(claimName); - if (value == null) { - claims.remove(claimName); - return null; - } - return value; - } - - // consider cleanup - private String checkStringOrURI(final Object value) { - if (!(value instanceof String)) - return "not a string"; - final String stringOrUri = (String) value; - if (!stringOrUri.contains(":")) - return null; - try { - new URI(stringOrUri); - } catch (URISyntaxException e) { - return "not a valid URI"; - } - return null; - } - - /** - * Sign the header and payload - */ - private String encodedSignature(final String signingInput, final Algorithm algorithm) throws NoSuchAlgorithmException, InvalidKeyException, - NoSuchProviderException, SignatureException, JWTAlgorithmException { - Validate.notNull(signingInput); - Validate.notNull(algorithm); - switch (algorithm) { - case HS256: - case HS384: - case HS512: - return base64UrlEncode(signHmac(algorithm, signingInput, secret)); - case RS256: - case RS384: - case RS512: - return base64UrlEncode(signRs(algorithm, signingInput, privateKey)); - default: - throw new JWTAlgorithmException("Unsupported signing method"); - } - } - - /** - * Safe URL encode a byte array to a String - */ - private String base64UrlEncode(final byte[] str) { - Validate.notNull(str); - return new String(Base64.encodeBase64URLSafe(str)); - } - - /** - * Sign an input string using HMAC and return the encrypted bytes - */ - private static byte[] signHmac(final Algorithm algorithm, final String msg, final byte[] secret) throws NoSuchAlgorithmException, InvalidKeyException { - Validate.notNull(algorithm); - Validate.notNull(msg); - Validate.notNull(secret); - final Mac mac = Mac.getInstance(algorithm.getValue()); - mac.init(new SecretKeySpec(secret, algorithm.getValue())); - return mac.doFinal(msg.getBytes()); - } - - /** - * Sign an input string using RSA and return the encrypted bytes - */ - private static byte[] signRs(final Algorithm algorithm, final String msg, final PrivateKey privateKey) throws NoSuchProviderException, - NoSuchAlgorithmException, InvalidKeyException, SignatureException { - Validate.notNull(algorithm); - Validate.notNull(msg); - Validate.notNull(privateKey); - final byte[] messageBytes = msg.getBytes(); - final Signature signature = Signature.getInstance(algorithm.getValue(), "BC"); - signature.initSign(privateKey); - signature.update(messageBytes); - return signature.sign(); - } - - private String join(final List input, final String separator) { - Validate.notNull(input); - Validate.notNull(separator); - return StringUtils.join(input.iterator(), separator); - } - - /** - * An option object for JWT signing operation. Allow choosing the algorithm, and/or specifying - * claims to be automatically set. - */ - public static class Options { - - private Algorithm algorithm; - private Integer expirySeconds; - private Integer notValidBeforeLeeway; - private boolean issuedAt; - private boolean jwtId; - - public Algorithm getAlgorithm() { - return algorithm; - } - - /** - * Algorithm to sign JWT with. - */ - public Options setAlgorithm(final Algorithm algorithm) { - this.algorithm = algorithm; - return this; - } - - - public Integer getExpirySeconds() { - return expirySeconds; - } - - /** - * Set JWT claim "exp" to current timestamp plus this value. - * Overrides content of claims in sign(). - */ - public Options setExpirySeconds(final Integer expirySeconds) { - this.expirySeconds = expirySeconds; - return this; - } - - public Integer getNotValidBeforeLeeway() { - return notValidBeforeLeeway; - } - - /** - * Set JWT claim "nbf" to current timestamp minus this value. - * Overrides content of claims in sign(). - */ - public Options setNotValidBeforeLeeway(final Integer notValidBeforeLeeway) { - this.notValidBeforeLeeway = notValidBeforeLeeway; - return this; - } - - public boolean isIssuedAt() { - return issuedAt; - } - - /** - * Set JWT claim "iat" to current timestamp. Defaults to false. - * Overrides content of claims in sign(). - */ - public Options setIssuedAt(final boolean issuedAt) { - this.issuedAt = issuedAt; - return this; - } - - public boolean isJwtId() { - return jwtId; - } - - /** - * Set JWT claim "jti" to a pseudo random unique value (type 4 UUID). Defaults to false. - * Overrides content of claims in sign(). - */ - public Options setJwtId(final boolean jwtId) { - this.jwtId = jwtId; - return this; - } - - } - -} diff --git a/java/src/main/java/com/genexus/security/web/jose/jwt/JWTVerifier.java b/java/src/main/java/com/genexus/security/web/jose/jwt/JWTVerifier.java deleted file mode 100644 index bf8b23840..000000000 --- a/java/src/main/java/com/genexus/security/web/jose/jwt/JWTVerifier.java +++ /dev/null @@ -1,234 +0,0 @@ -package com.genexus.security.web.jose.jwt; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.security.InvalidKeyException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PublicKey; -import java.security.Security; -import java.security.Signature; -import java.security.SignatureException; -import java.util.Map; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; - -import org.apache.commons.codec.binary.Base64; -import org.bouncycastle.jce.provider.BouncyCastleProvider; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; - -/** - * Handles JWT Verification Operations - * - * Validates claims and signature - * - * See associated library test cases for clear examples on usage - * - */ -public class JWTVerifier { - - static { - if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { - Security.addProvider(new BouncyCastleProvider()); - } - } - - private byte[] secret; - private PublicKey publicKey; - private final String audience; - private final String issuer; - private final Base64 decoder = new Base64(true); - - private final ObjectMapper mapper; - - - public JWTVerifier(final String secret, final String audience, final String issuer) { - this(secret.getBytes(Charset.forName("UTF-8")), audience, issuer); - } - - public JWTVerifier(final String secret, final String audience) { - this(secret, audience, null); - } - - public JWTVerifier(final String secret) { - this(secret, null, null); - } - - public JWTVerifier(final byte[] secret, final String audience) { - this(secret, audience, null); - } - - public JWTVerifier(final byte[] secret) { - this(secret, null, null); - } - - public JWTVerifier(final byte[] secret, final String audience, final String issuer) { - if (secret == null || secret.length == 0) { - throw new IllegalArgumentException("Secret cannot be null or empty"); - } - mapper = new ObjectMapper(); - this.secret = secret; - this.audience = audience; - this.issuer = issuer; - } - - public JWTVerifier(final PublicKey publicKey, final String audience, final String issuer) { - mapper = new ObjectMapper(); - this.publicKey = publicKey; - this.audience = audience; - this.issuer = issuer; - } - - public JWTVerifier(final PublicKey publicKey, final String audience) { - this(publicKey, audience, null); - } - - public JWTVerifier(final PublicKey publicKey) { - this(publicKey, null, null); - } - - - /** - * Performs JWT validation - * - * @param token token to verify - * @throws SignatureException when signature is invalid - * @throws JWTVerifyException when expiration, issuer or audience are invalid - * @throws JWTAlgorithmException when the algorithm is missing or unsupported - * @throws IllegalStateException when token's structure is invalid or secret / public key does not match algorithm of token - */ - @SuppressWarnings({"WeakerAccess", "unchecked"}) - public Map verify(final String token) throws NoSuchAlgorithmException, InvalidKeyException, IllegalStateException, - IOException, SignatureException, JWTVerifyException { - if (token == null || "".equals(token)) { - throw new IllegalStateException("token not set"); - } - final String[] pieces = token.split("\\."); - if (pieces.length != 3) { - throw new IllegalStateException("Wrong number of segments: " + pieces.length); - } - final JsonNode jwtHeader = decodeAndParse(pieces[0]); - final Algorithm algorithm = getAlgorithm(jwtHeader); - final JsonNode jwtPayload = decodeAndParse(pieces[1]); - verifySignature(pieces, algorithm); - verifyExpiration(jwtPayload); - verifyIssuer(jwtPayload); - verifyAudience(jwtPayload); - return mapper.treeToValue(jwtPayload, Map.class); - } - - void verifySignature(final String[] pieces, final Algorithm algorithm) throws NoSuchAlgorithmException, - InvalidKeyException, SignatureException, JWTAlgorithmException, IllegalStateException { - if (pieces.length != 3) { - throw new IllegalStateException("Wrong number of segments: " + pieces.length); - } - switch (algorithm) { - case HS256: - case HS384: - case HS512: - verifyHmac(algorithm, pieces, secret); - return; - case RS256: - case RS384: - case RS512: - verifyRs(algorithm, pieces, publicKey); - return; - default: - throw new JWTAlgorithmException("Unsupported signing method"); - } - } - - private void verifyHmac(final Algorithm algorithm, final String[] pieces, final byte[] secret) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException { - if (secret == null || secret.length == 0) { - throw new IllegalStateException("Secret cannot be null or empty when using algorithm: " + algorithm.getValue()); - } - final Mac hmac = Mac.getInstance(algorithm.getValue()); - hmac.init(new SecretKeySpec(secret, algorithm.getValue())); - final byte[] sig = hmac.doFinal((pieces[0] + "." + pieces[1]).getBytes()); - if (!MessageDigest.isEqual(sig, decoder.decode(pieces[2]))) { - throw new SignatureException("signature verification failed"); - } - } - - private void verifyRs(final Algorithm algorithm, final String[] pieces, final PublicKey publicKey) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException, JWTAlgorithmException { - if (publicKey == null) { - throw new IllegalStateException("PublicKey cannot be null when using algorithm: " + algorithm.getValue()); - } - final byte[] decodedSignatureBytes = new Base64(true).decode(pieces[2]); - final byte[] headerPayloadBytes = (pieces[0] + "." + pieces[1]).getBytes(); - final boolean verified = verifySignatureWithPublicKey(this.publicKey, headerPayloadBytes, decodedSignatureBytes, algorithm); - if (!verified) { - throw new SignatureException("signature verification failed"); - } - } - - private boolean verifySignatureWithPublicKey(final PublicKey publicKey, final byte[] messageBytes, final byte[] signatureBytes, final Algorithm algorithm) throws InvalidKeyException, SignatureException, NoSuchAlgorithmException, JWTAlgorithmException { - try { - final Signature signature = Signature.getInstance(algorithm.getValue(), "BC"); - signature.initVerify(publicKey); - signature.update(messageBytes); - return signature.verify(signatureBytes); - } catch (NoSuchProviderException e) { - throw new JWTAlgorithmException(e.getMessage(), e.getCause()); - } - } - - void verifyExpiration(final JsonNode jwtClaims) throws JWTExpiredException { - final long expiration = jwtClaims.has("exp") ? jwtClaims.get("exp").asLong(0) : 0; - if (expiration != 0 && System.currentTimeMillis() / 1000L >= expiration) { - throw new JWTExpiredException("jwt expired", expiration); - } - } - - void verifyIssuer(final JsonNode jwtClaims) throws JWTIssuerException { - if (this.issuer == null ) { - return; - } - - final String issuerFromToken = jwtClaims.has("iss") ? jwtClaims.get("iss").asText() : null; - - if (issuerFromToken == null || !issuer.equals(issuerFromToken)) { - throw new JWTIssuerException("jwt issuer invalid", issuerFromToken); - } - } - - void verifyAudience(final JsonNode jwtClaims) throws JWTAudienceException { - if (audience == null) { - return; - } - final JsonNode audNode = jwtClaims.get("aud"); - if (audNode == null) { - throw new JWTAudienceException("jwt audience invalid", null); - } - if (audNode.isArray()) { - for (final JsonNode jsonNode : audNode) { - if (audience.equals(jsonNode.textValue())) { - return; - } - } - } else if (audNode.isTextual()) { - if (audience.equals(audNode.textValue())) { - return; - } - } - throw new JWTAudienceException("jwt audience invalid", audNode); - } - - Algorithm getAlgorithm(final JsonNode jwtHeader) throws JWTAlgorithmException { - final String algorithmName = jwtHeader.has("alg") ? jwtHeader.get("alg").asText() : null; - if (jwtHeader.get("alg") == null) { - throw new IllegalStateException("algorithm not set"); - } - return Algorithm.findByName(algorithmName); - } - - JsonNode decodeAndParse(final String b64String) throws IOException { - final String jsonString = new String(decoder.decode(b64String), "UTF-8"); - return mapper.readValue(jsonString, JsonNode.class); - } - -} diff --git a/java/src/main/java/com/genexus/security/web/jose/jwt/JWTVerifyException.java b/java/src/main/java/com/genexus/security/web/jose/jwt/JWTVerifyException.java deleted file mode 100644 index 9c2a20103..000000000 --- a/java/src/main/java/com/genexus/security/web/jose/jwt/JWTVerifyException.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.genexus.security.web.jose.jwt; - -/** - * Represents General Exception related to Verification - */ -public class JWTVerifyException extends Exception { - - public JWTVerifyException() {} - - public JWTVerifyException(final String message, final Throwable cause) { - super(message, cause); - } - - public JWTVerifyException(final String message) { - super(message); - } - -} diff --git a/java/src/main/java/com/genexus/security/web/jose/jwt/pem/PemFileReader.java b/java/src/main/java/com/genexus/security/web/jose/jwt/pem/PemFileReader.java deleted file mode 100644 index 73deaa589..000000000 --- a/java/src/main/java/com/genexus/security/web/jose/jwt/pem/PemFileReader.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.genexus.security.web.jose.jwt.pem; - -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; - -import org.bouncycastle.util.io.pem.PemObject; -import org.bouncycastle.util.io.pem.PemReader; -import org.bouncycastle.util.io.pem.PemWriter; - -/** - * Can read PEM from disk - depends on BouncyCastle PemReader - */ -class PemFileReader { - - private PemObject pemObject; - - public PemFileReader(final String filename) throws IOException { - final PemReader pemReader = new PemReader(new InputStreamReader(new FileInputStream(filename))); - try { - this.pemObject = pemReader.readPemObject(); - } finally { - pemReader.close(); - } - } - - public void write(final String filename) throws IOException { - final PemWriter pemWriter = new PemWriter(new OutputStreamWriter(new FileOutputStream(filename))); - try { - pemWriter.writeObject(this.pemObject); - } finally { - pemWriter.close(); - } - } - - public PemObject getPemObject() { - return pemObject; - } - -} diff --git a/java/src/main/java/com/genexus/security/web/jose/jwt/pem/PemFileWriter.java b/java/src/main/java/com/genexus/security/web/jose/jwt/pem/PemFileWriter.java deleted file mode 100644 index aebe9a65f..000000000 --- a/java/src/main/java/com/genexus/security/web/jose/jwt/pem/PemFileWriter.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.genexus.security.web.jose.jwt.pem; - -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.security.Key; - -import org.bouncycastle.util.io.pem.PemObject; -import org.bouncycastle.util.io.pem.PemWriter; - -/** - * Can write PEM to disk - depends on BouncyCastle PemWriter - */ -class PemFileWriter { - - private PemObject pemObject; - - public PemFileWriter(final Key key, final String description) { - this.pemObject = new PemObject(description, key.getEncoded()); - } - - public void write(final String filename) throws IOException { - final PemWriter pemWriter = new PemWriter(new OutputStreamWriter(new FileOutputStream(filename))); - try { - pemWriter.writeObject(this.pemObject); - } finally { - pemWriter.close(); - } - } - -} diff --git a/java/src/main/java/com/genexus/security/web/jose/jwt/pem/PemReader.java b/java/src/main/java/com/genexus/security/web/jose/jwt/pem/PemReader.java deleted file mode 100644 index 758161835..000000000 --- a/java/src/main/java/com/genexus/security/web/jose/jwt/pem/PemReader.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.genexus.security.web.jose.jwt.pem; - - -import java.io.File; -import java.io.IOException; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.Security; -import java.security.cert.X509Certificate; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; - -import org.bouncycastle.jce.provider.BouncyCastleProvider; - -/** - * Read operations for PEM files - */ -public class PemReader { - - static { - if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { - Security.addProvider(new BouncyCastleProvider()); - } - } - - public static PrivateKey readPrivateKey(final String filePath) throws NoSuchProviderException, NoSuchAlgorithmException, IOException, InvalidKeySpecException { - final KeyFactory factory = KeyFactory.getInstance("RSA", "BC"); - final PrivateKey privateKey = readPrivateKeyFromFile(factory, filePath); - return privateKey; - } - - public static PublicKey readPublicKey(final String filePath) throws NoSuchProviderException, NoSuchAlgorithmException, IOException, InvalidKeySpecException { - final KeyFactory factory = KeyFactory.getInstance("RSA", "BC"); - final PublicKey publicKey = readPublicKeyFromFile(factory, filePath); - return publicKey; - } - - private static PrivateKey readPrivateKeyFromFile(final KeyFactory factory, final String filename) throws InvalidKeySpecException, IOException { - final PemFileReader pemFileReader = new PemFileReader(filename); - final byte[] content = pemFileReader.getPemObject().getContent(); - final PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(content); - return factory.generatePrivate(privKeySpec); - } - - private static PublicKey readPublicKeyFromFile(final KeyFactory factory, final String filename) throws InvalidKeySpecException, IOException { - final File file = new File(filename); - final byte[] data = new byte[0];//Files.readAllBytes(file.toPath()); - final X509Certificate cert = X509CertUtils.parse(new String(data)); - if (cert != null) { - java.security.PublicKey publicKey = cert.getPublicKey(); - return publicKey; - } else { - final PemFileReader pemFileReader = new PemFileReader(filename); - final byte[] content = pemFileReader.getPemObject().getContent(); - final X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content); - return factory.generatePublic(pubKeySpec); - } - - - } - -} diff --git a/java/src/main/java/com/genexus/security/web/jose/jwt/pem/PemWriter.java b/java/src/main/java/com/genexus/security/web/jose/jwt/pem/PemWriter.java deleted file mode 100644 index 5dc26e0e3..000000000 --- a/java/src/main/java/com/genexus/security/web/jose/jwt/pem/PemWriter.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.genexus.security.web.jose.jwt.pem; - - - -import java.io.IOException; -import java.security.Key; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; - -/** - * Write operations for PEM files - */ -public class PemWriter { - - public static void writePrivateKey(final RSAPrivateKey privateKey, final String description, final String filename) throws IOException { - writePemFile(privateKey, description, filename); - } - - public static void writePublicKey(final RSAPublicKey publicKey, final String description, final String filename) throws IOException { - writePemFile(publicKey, description, filename); - } - - public static void writePemFile(final Key key, final String description, final String filename) throws IOException { - final PemFileWriter pemFileWriter = new PemFileWriter(key, description); - pemFileWriter.write(filename); - } - -} diff --git a/java/src/main/java/com/genexus/security/web/jose/jwt/pem/X509CertUtils.java b/java/src/main/java/com/genexus/security/web/jose/jwt/pem/X509CertUtils.java deleted file mode 100644 index 33a4f3cb5..000000000 --- a/java/src/main/java/com/genexus/security/web/jose/jwt/pem/X509CertUtils.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.genexus.security.web.jose.jwt.pem; - -import java.io.ByteArrayInputStream; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; - -import org.apache.commons.codec.binary.Base64; - - -/** - * X.509 certificate utilities. - */ -public class X509CertUtils { - - private static final String PEM_BEGIN_MARKER = "-----BEGIN CERTIFICATE-----"; - private static final String PEM_END_MARKER = "-----END CERTIFICATE-----"; - - /** - * Parses a DER-encoded X.509 certificate. - */ - public static X509Certificate parse(final byte[] derEncodedCert) { - if (derEncodedCert == null || derEncodedCert.length == 0) { - return null; - } - try { - final CertificateFactory cf = CertificateFactory.getInstance("X.509"); - final Certificate cert = cf.generateCertificate(new ByteArrayInputStream(derEncodedCert)); - if (!(cert instanceof X509Certificate)) { - return null; - } - return (X509Certificate) cert; - } catch (CertificateException e) { - return null; - } - } - - /** - * Parses a PEM-encoded X.509 certificate. - */ - public static X509Certificate parse(final String pemEncodedCert) { - if (pemEncodedCert == null || pemEncodedCert.isEmpty()) { - return null; - } - final int markerStart = pemEncodedCert.indexOf(PEM_BEGIN_MARKER); - if (markerStart < 0) { - return null; - } - String buf = pemEncodedCert.substring(markerStart + PEM_BEGIN_MARKER.length()); - final int markerEnd = buf.indexOf(PEM_END_MARKER); - if (markerEnd < 0) { - return null; - } - buf = buf.substring(0, markerEnd); - buf = buf.replaceAll("\\s", ""); - return parse(new Base64(true).decodeBase64(buf)); - } - -} - diff --git a/java/src/main/java/com/genexus/webpanels/DynAjaxEventContext.java b/java/src/main/java/com/genexus/webpanels/DynAjaxEventContext.java deleted file mode 100644 index 23943d196..000000000 --- a/java/src/main/java/com/genexus/webpanels/DynAjaxEventContext.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.genexus.webpanels; - -import com.genexus.GXutil; -import com.genexus.internet.IGxJSONSerializable; -import json.org.json.JSONArray; - -import java.util.HashSet; -import java.util.Hashtable; - -public class DynAjaxEventContext implements IDynAjaxEventContext { - JSONArray inParmsMetadata; - HashSet inParmsMetadataHash = new HashSet(); - JSONArray outParmsMetadata; - HashSet outParmsMetadataHash = new HashSet(); - private Hashtable inParmsHashValue = new Hashtable(); - - public void ClearParmsMetadata() { - inParmsMetadata = new JSONArray(); - inParmsMetadataHash = new HashSet(); - outParmsMetadata = new JSONArray(); - outParmsMetadataHash = new HashSet(); - } - - public boolean isInputParm(String key) { - return inParmsMetadataHash.contains(key); - } - - public void Clear() { - inParmsHashValue.clear(); - } - - public void SetParmHash(String fieldName, Object value) { - IGxJSONSerializable jsonValue = (value instanceof IGxJSONSerializable) ? (IGxJSONSerializable) value : null; - if (jsonValue != null) { - inParmsHashValue.put(fieldName, GXutil.getHash(jsonValue.toJSonString())); - } - } - - public boolean isParmModified(String fieldName, Object value) { - IGxJSONSerializable jsonValue = (value instanceof IGxJSONSerializable) ? (IGxJSONSerializable) value : null; - if (value != null) { - if (!inParmsHashValue.containsKey(fieldName)) - return true; - return !GXutil.getHash(jsonValue.toJSonString()).equals(inParmsHashValue.get(fieldName)); - } - return true; - } -} diff --git a/java/src/main/java/com/genexus/webpanels/GXWebObjectBase.java b/java/src/main/java/com/genexus/webpanels/GXWebObjectBase.java deleted file mode 100644 index 7e779aae9..000000000 --- a/java/src/main/java/com/genexus/webpanels/GXWebObjectBase.java +++ /dev/null @@ -1,689 +0,0 @@ -package com.genexus.webpanels; - -import java.math.BigDecimal; -import java.sql.SQLException; -import java.util.TimeZone; - -import com.genexus.*; -import com.genexus.configuration.ConfigurationManager; -import com.genexus.diagnostics.GXDebugInfo; -import com.genexus.diagnostics.GXDebugManager; -import org.apache.commons.lang.StringUtils; - -import com.genexus.ModelContext; -import com.genexus.db.Namespace; -import com.genexus.db.UserInformation; -import com.genexus.diagnostics.core.ILogger; -import com.genexus.diagnostics.core.LogManager; -import com.genexus.internet.GXInternetConstants; -import com.genexus.internet.HttpContext; -import com.genexus.internet.IGxJSONSerializable; -import com.genexus.security.GXSecurityProvider; -import com.genexus.security.web.SecureTokenHelper; -import com.genexus.security.web.WebSecurityHelper; -import com.genexus.util.GXTimeZone; - -import com.genexus.GXRestServiceWrapper; - -public abstract class GXWebObjectBase extends GXRestServiceWrapper implements IErrorHandler, GXInternetConstants, ISubmitteable -{ - public static final ILogger logger = LogManager.getLogger(GXWebObjectBase.class); - - private static String GX_SPA_GXOBJECT_RESPONSE_HEADER = "X-GXOBJECT"; - protected static String GX_SPA_MASTERPAGE_HEADER = "X-SPA-MP"; - public static int SPA_NOT_SUPPORTED_STATUS_CODE = 530; - protected static String GX_AJAX_MULTIPART_ID = "GXAjaxMultipart"; - - protected boolean IntegratedSecurityEnabled() { return false;} - protected int IntegratedSecurityLevel() { return 0;} - protected String IntegratedSecurityPermissionPrefix() {return "";} - - protected static final int SECURITY_GXOBJECT = 3; - protected static final int SECURITY_HIGH = 2; - protected static final int SECURITY_LOW = 1; - - public abstract void webExecute(); - public abstract boolean isMasterPage(); - - protected ModelContext context; - protected HttpContext httpContext; - protected LocalUtil localUtil; - protected int remoteHandle = -1; - - protected UserInformation ui; - protected TimeZone timeZone; - - public Object getParm( Object[] parms, int index) - { - return parms[index]; - } - - public GXWebObjectBase() - { - } - - /** - * Este constructor se usa cuando aun no tengo un ModelContext ni remoteHandle, pero - * si tengo el HttpContext. Basicamente es el punto de entrada en los servlets. - */ - public GXWebObjectBase(HttpContext httpContext, Class contextClass) - { - init(httpContext, contextClass); - } - - /** - * Este constructor se usa cuando aun no tengo un ModelContext ni remoteHandle, pero - * si tengo el HttpContext. Basicamente es el punto de entrada en los servlets. - */ - public GXWebObjectBase(HttpContext httpContext) - { - init(httpContext, getClass()); - } - - /** - * Este constructor se usa cuando ya tengo un ModelContext y remoteHandle. - * Basicamente es el punto de entrada para webcomponents, webwrappers, etc. - */ - public GXWebObjectBase(int remoteHandle, ModelContext context) - { - this.context = context; - - ui = (UserInformation) GXObjectHelper.getUserInformation(context, remoteHandle); - this.remoteHandle = ui.getHandle(); - - initState(context, ui); - } - - /*** - * Return the DefaultTheme for all WebPanels and Transactions. - * @return - */ - @SuppressWarnings("unused") - protected void initializeTheme() { - this.httpContext.setDefaultTheme(ConfigurationManager.getValue("Theme")); - } - - protected void init(HttpContext httpContext, Class contextClass) - { - // @gusbro:06/06/05 - // El JDK.15 mantiene un TimeZone default por cada Thread, por lo cual el hack que haciemos - // en la gxutil de setear el timeZone falla en motores de servlets - // Lo que hacemos es setear el default aqui, ademas para ser mas 'prolijos' volvemos al valor - // original al finalizar el request (esto ultimo ya no se hace, porque puede traer problemas) - timeZone = GXTimeZone.getDefaultOriginal(); - this.context = new ModelContext(contextClass); - context.setHttpContext(httpContext); - - new WebApplicationStartup().init(contextClass, httpContext); - - ApplicationContext.getInstance().setPoolConnections(!Namespace.createNamespace(context).isRemoteGXDB()); - - ui = (UserInformation) GXObjectHelper.getUserInformation(context, -1); - ui.setAutoDisconnect(false); - remoteHandle = ui.getHandle(); - - initState(context, ui); - } - - protected void initState(ModelContext context, UserInformation ui) - { - localUtil = ui.getLocalUtil(); - httpContext = (HttpContext) context.getHttpContext(); - httpContext.setContext( context); - httpContext.setCompression(getCompressionMode()); - } - - protected boolean getCompressionMode() - { - return context.getClientPreferences().getCOMPRESS_HTML(); - } - - protected boolean CheckCmpSecurityAccess() - { - boolean[] flag = new boolean[]{false}; - boolean[] permissionFlag = new boolean[]{false}; - String permissionPrefix = IntegratedSecurityPermissionPrefix(); - com.genexus.internet.HttpRequest req = ((HttpContext)ModelContext.getModelContext().getHttpContext()).getHttpRequest(); - if (req == null) - return false; - String reqUrl = req.getRequestURL(); - ModelContext modelContext = ModelContext.getModelContext(getClass()); - if (IntegratedSecurityLevel() == SECURITY_LOW || IntegratedSecurityLevel() == SECURITY_GXOBJECT) - { - GXSecurityProvider.getInstance().checksession(-2, modelContext, reqUrl, permissionFlag); - } - if (IntegratedSecurityLevel() != SECURITY_LOW && IntegratedSecurityLevel() != SECURITY_GXOBJECT) - { - GXSecurityProvider.getInstance().checksessionprm(-2, modelContext, reqUrl, permissionPrefix, flag, permissionFlag); - } - return permissionFlag[0]; - } - - protected void preExecute() - { - httpContext.responseContentType("text/html"); //default Content-Type - httpContext.initClientId(); - } - - protected void sendCacheHeaders() - { - if (httpContext.isSpaRequest()) { - httpContext.getResponse().setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); - httpContext.getResponse().setHeader("Pragma", "no-cache"); - httpContext.getResponse().setHeader("Expires", "0"); - } - else { - httpContext.getResponse().addDateHeader("Expires", 0); - httpContext.getResponse().addDateHeader("Last-Modified", 0); - if (this instanceof GXWebReport && ((GXWebReport)this).getOutputType()==GXWebReport.OUTPUT_PDF) { - httpContext.getResponse().addHeader("Cache-Control", "must-revalidate,post-check=0, pre-check=0"); - //Estos headers se setean por un bug de Reader X que hace que en IE no se vea el reporte cuando esta embebido, - //solo se ve luego de hacer F5. - } - else { - httpContext.getResponse().addHeader("Cache-Control", "max-age=0, no-cache, no-store, must-revalidate"); - } - } - } - - protected void sendAdditionalHeaders() - { - if (httpContext.isSpaRequest()) - sendSpaHeaders(); - if (httpContext.getBrowserType() == HttpContext.BROWSER_IE && !httpContext.isPopUpObject()) - { - String IECompMode = context.getClientPreferences().getIE_COMPATIBILITY(); - if (IECompMode.equals("EmulateIE7") && !httpContext.getBrowserVersion().startsWith("8") ) - return; - if (StringUtils.isNotEmpty(IECompMode)) - httpContext.getResponse().addHeader("X-UA-Compatible", "IE=" + IECompMode); - } - } - - protected void sendSpaHeaders() - { - httpContext.getResponse().setHeader(GX_SPA_GXOBJECT_RESPONSE_HEADER, getPgmname().toLowerCase()); - } - - public void doExecute() throws Exception - { - try - { - if (isSpaRequest() && !isSpaSupported()) - { - httpContext.sendResponseStatus(SPA_NOT_SUPPORTED_STATUS_CODE, "SPA not supported by the object"); - } - else - { - preExecute(); - sendCacheHeaders(); - webExecute(); - sendAdditionalHeaders(); - httpContext.flushStream(); - } - } - catch (Throwable e) - { - handleException(e.getClass().getName(), e.getMessage(), CommonUtil.getStackTraceAsString(e)); - cleanup(); // Antes de hacer el rethrow, hago un cleanup del objeto - throw e; - } - finally - { - finallyCleanup(); - } - } - - protected void finallyCleanup() - { - try - { - if (ui!= null) - ui.disconnect(); - } - catch (java.sql.SQLException e) - { - logger.error("Exception while disconecting ", e); - } - if (httpContext != null) - httpContext.cleanup(); - cleanModelContext(); - } - - private void cleanModelContext() - { - try - { - ((ThreadLocal)com.genexus.CommonUtil.threadCalendar).getClass().getMethod("remove", new Class[0]).invoke(com.genexus.CommonUtil.threadCalendar, (java.lang.Object[])new Class[0]); - ((ThreadLocal)com.genexus.ModelContext.threadModelContext).getClass().getMethod("remove", new Class[0]).invoke(com.genexus.ModelContext.threadModelContext, (java.lang.Object[])new Class[0]); - HTTPClient.StreamDemultiplexor.cleanup(); - } - catch (NoSuchMethodException e) - { - logger.error("cleanModelContext", e); - } - catch (IllegalAccessException e) - { - logger.error("cleanModelContext", e); - } - catch (java.lang.reflect.InvocationTargetException e) - { - logger.error("cleanModelContext " + e.getTargetException(), e); - } - } - - protected void cleanup() - { - Application.cleanupConnection(remoteHandle); - } - - public HttpContext getHttpContext() - { - return httpContext; - } - - public void setHttpContext(HttpContext httpContext) - { - this.httpContext = httpContext; - } - - - public ModelContext getModelContext() - { - return context; - } - - public int getRemoteHandle() - { - return remoteHandle; - } - - public void handleError() - { - new DefaultErrorHandler().handleError(context, remoteHandle); - } - - public ModelContext getContext() - { - return context; - } - - public int setLanguage(String language) - { - int res = GXutil.setLanguage(language, context, ui); - this.localUtil = ui.getLocalUtil(); - return res; - } - public int setTheme(String theme) - { - int res = GXutil.setTheme(theme, context); - return res; - } - public void executeUsercontrolMethod(String CmpContext, boolean IsMasterPage, String containerName, String methodName, String input, Object[] parms) - { - httpContext.executeUsercontrolMethod(CmpContext, IsMasterPage, containerName, methodName, input, parms); - } - - public void setExternalObjectProperty(String CmpContext, boolean IsMasterPage, String containerName, String propertyName, Object value) - { - httpContext.setExternalObjectProperty(CmpContext, IsMasterPage, containerName, propertyName, value); - } - - public void executeExternalObjectMethod(String CmpContext, boolean IsMasterPage, String containerName, String methodName, Object[] parms, boolean isEvent) - { - httpContext.executeExternalObjectMethod(CmpContext, IsMasterPage, containerName, methodName, parms, isEvent); - } - - /** - * @Hack: Tenemos que ejecutar el submit esto en otro thread, pues el submit es asincrono, - * pero si creamos en el fuente generado el codigo del nuevo thread, se va a crear un - * archivo nuevo xxx$N.class al compilar el xxx, que deberia ser tratado especialmente - * en el makefile (copiado al directorio de servlets, etc); asi que delegamos la - * creacion del thread a la gxclassr donde se llama al metodo a ser ejecutado - * Adem�s ahora manejamos un pool de threads en el submit - */ - public void callSubmit(final int id, Object [] submitParms) - { - com.genexus.util.SubmitThreadPool.submit(this, id, submitParms, context.submitCopy()); - } - - /** Este metodo es redefinido por la clase GX generada cuando hay submits - */ - public void submit(int id, Object [] submitParms, ModelContext ctx){ - } - public void submit(int id, Object [] submitParms){ - } - public void submitReorg(int id, Object [] submitParms) throws SQLException{ - } - - protected String formatLink(String jumpURL) - { - return formatLink(jumpURL, new String[]{}); - } - - protected String formatLink(String jumpURL, String[] parms) - { - return formatLink(jumpURL, parms, new String[]{}); - } - - protected String formatLink(String jumpURL, String[] parms, String[] parmsName) - { - return URLRouter.getURLRoute(jumpURL, parms, parmsName, httpContext.getRequest().getContextPath(), context.getPackageName()); - } - - public String getPgmname() - { - return ""; - } - - public String getPgmdesc() - { - return ""; - } - - protected boolean isSpaRequest() - { - return httpContext.isSpaRequest(); - } - - protected boolean isSpaRequest(boolean ignoreFlag) - { - return httpContext.isSpaRequest(ignoreFlag); - } - - protected boolean isSpaSupported() - { - return true; - } - - - protected void validateSpaRequest() - { - // SPA is disabled for objects without master page. However, SPA response headers are sent anyway, so the client side - // replaces the full content using AJAX. - if (isSpaRequest()) - { - httpContext.disableSpaRequest(); - sendSpaHeaders(); - } - } - - - private static String GX_SEC_TOKEN_PREFIX = "GX_AUTH"; - - //Generates only with FullAjax and GAM disabled. - public void sendSecurityToken(String cmpCtx) - { - if (this.httpContext.wjLoc == null || this.httpContext.wjLoc.equals("") ) - { - this.httpContext.ajax_rsp_assign_hidden(getSecurityObjTokenId(cmpCtx), getObjectAccessWebToken(cmpCtx)); - } - } - - private String getSecurityObjTokenId(String cmpCtx) - { - return GX_SEC_TOKEN_PREFIX + "_" + cmpCtx + getPgmname().toUpperCase(); - } - - protected String getPgmInstanceId(String cmpCtx) - { - return String.format("%s%s", cmpCtx, this.getPgmname().toUpperCase()); - } - - private String getObjectAccessWebToken(String cmpCtx) - { - return WebSecurityHelper.sign(getPgmInstanceId(cmpCtx), "", "", SecureTokenHelper.SecurityMode.Sign, getSecretKey()); - } - - private String getSecretKey() - { - //Some random SALT that is different in every GX App installation. Better if changes over time - String hashSalt = com.genexus.Application.getClientContext().getClientPreferences().getREORG_TIME_STAMP(); - return WebUtils.getEncryptionKey(this.context, "") + hashSalt; - } - - private String serialize(double Value, String Pic) - { - return serialize(localUtil.format(Value, Pic)); - } - - private String serialize(int Value, String Pic) - { - return serialize(localUtil.format(Value, Pic)); - } - - private String serialize(short Value, String Pic) - { - return serialize(localUtil.format(Value, Pic)); - } - - private String serialize(long Value, String Pic) - { - return serialize(localUtil.format(Value, Pic)); - } - - private String serialize(Object Value, String Pic) - { - if (!StringUtils.isBlank(Pic)) { - if (Value instanceof Byte) - { - return serialize(localUtil.format(((Byte)Value).intValue(), Pic)); - } - else - { - if (Value instanceof BigDecimal) - { - return serialize(localUtil.format((BigDecimal)Value, Pic)); - } - else - { - if (Value instanceof Integer) - { - return serialize(localUtil.format(((Integer)Value).intValue(), Pic)); - } - else - { - if (Value instanceof Short) - { - return serialize(localUtil.format(((Short)Value).shortValue(), Pic)); - } - else - { - if (Value instanceof Long) - { - return serialize(localUtil.format(((Long)Value).longValue(), Pic)); - } - else - { - if (Value instanceof Double) - { - return serialize(localUtil.format(((Double)Value).doubleValue(), Pic)); - } - else - { - if (Value instanceof Float) - { - return serialize(localUtil.format(((Float)Value).floatValue(), Pic)); - } - else - { - if (Value instanceof java.util.Date) - { - return serialize(localUtil.format((java.util.Date)Value, Pic)); - } - else - { - if (Value instanceof String) - { - return serialize(localUtil.format((String)Value, Pic)); - } - } - } - } - } - } - } - } - } - } - return serialize(Value); - } - - private String serialize(Object Value) { - String strValue = ""; - if (Value instanceof BigDecimal){ - strValue = Value.toString(); - if (strValue.indexOf(".") != -1) - strValue = strValue.replaceAll("0*$", "").replaceAll("\\.$", ""); - } - else{ - if (Value instanceof java.util.Date){ - strValue = " / / 00:00:00"; - if (!Value.equals(CommonUtil.resetTime( CommonUtil.nullDate()))) { - strValue = new java.text.SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Value); - } - } - else{ - if (Value instanceof com.genexus.xml.GXXMLSerializable) { - strValue = ((com.genexus.xml.GXXMLSerializable) Value).toJSonString(false); - } - else if (Value instanceof IGxJSONSerializable) { - strValue = ((IGxJSONSerializable) Value).toJSonString(); - } - else { - strValue = Value.toString(); - } - } - } - return strValue; - } - - protected String getSecureSignedToken(String cmpCtx, Object Value) - { - return getSecureSignedToken(cmpCtx, serialize(Value)); - } - - protected String getSecureSignedToken(String cmpCtx, boolean Value) - { - return getSecureSignedToken(cmpCtx, Boolean.toString(Value)); - } - - protected String getSecureSignedToken(String cmpCtx, com.genexus.xml.GXXMLSerializable Value) - { - return getSecureSignedToken(cmpCtx, Value.toJSonString(false)); - } - - protected String getSecureSignedToken(String cmpCtx, String Value) - { - return WebSecurityHelper.sign(getPgmInstanceId(cmpCtx), "", Value, SecureTokenHelper.SecurityMode.Sign, getSecretKey()); - } - - protected boolean verifySecureSignedToken(String cmpCtx, int Value, String picture, String token){ - return verifySecureSignedToken(cmpCtx, serialize(Value, picture), token); - } - - protected boolean verifySecureSignedToken(String cmpCtx, short Value, String picture, String token){ - return verifySecureSignedToken(cmpCtx, serialize(Value, picture), token); - } - - protected boolean verifySecureSignedToken(String cmpCtx, long Value, String picture, String token){ - return verifySecureSignedToken(cmpCtx, serialize(Value, picture), token); - } - - protected boolean verifySecureSignedToken(String cmpCtx, double Value, String picture, String token){ - return verifySecureSignedToken(cmpCtx, serialize(Value, picture), token); - } - - protected boolean verifySecureSignedToken(String cmpCtx, Object Value, String picture, String token){ - return verifySecureSignedToken(cmpCtx, serialize(Value, picture), token); - } - - protected boolean verifySecureSignedToken(String cmpCtx, Object Value, String token){ - return verifySecureSignedToken(cmpCtx, serialize(Value), token); - } - - protected boolean verifySecureSignedToken(String cmpCtx, boolean Value, String token){ - return verifySecureSignedToken(cmpCtx, Boolean.toString(Value), token); - } - - protected boolean verifySecureSignedToken(String cmpCtx, com.genexus.xml.GXXMLSerializable Value, String token){ - return verifySecureSignedToken(cmpCtx, Value.toJSonString(false), token); - } - - protected boolean verifySecureSignedToken(String cmpCtx, String value, String token){ - return WebSecurityHelper.verify(getPgmInstanceId(cmpCtx), "", value, token, getSecretKey()); - } - - protected boolean validateObjectAccess(String cmpCtx) - { - if (this.httpContext.useSecurityTokenValidation()){ - String jwtToken = this.httpContext.getHeader("X-GXAUTH-TOKEN"); - jwtToken = (StringUtils.isBlank(jwtToken) && this.httpContext.isMultipartContent())? - this.httpContext.cgiGet("X-GXAUTH-TOKEN"): - jwtToken; - - if (!verifySecureSignedToken(cmpCtx, "", jwtToken)) - { - this.httpContext.sendResponseStatus(401, "Not Authorized"); - if (this.httpContext.getBrowserType() != HttpContextWeb.BROWSER_INDEXBOT) { - logger.warn(String.format("Validation security token failed for program: %s - '%s'", getPgmInstanceId(cmpCtx), jwtToken )); - } - return false; - } - } - return true; - } - - public void handleException(String gxExceptionType, String gxExceptionDetails, String gxExceptionStack) - { - } - - private GXDebugInfo dbgInfo = null; - protected void trkCleanup() - { - if(dbgInfo != null) - dbgInfo.onCleanup(); - } - - protected void initialize(int objClass, int objId, int dbgLines, long hash) - { - dbgInfo = GXDebugManager.getInstance().getDbgInfo(context, objClass, objId, dbgLines, hash); - } - - protected void trk(int lineNro) - { - if(dbgInfo != null) - dbgInfo.trk(lineNro); - } - - protected void trk(int lineNro, int lineNro2) - { - if(dbgInfo != null) - dbgInfo.trk(lineNro, lineNro2); - } - - protected void trkrng(int lineNro, int lineNro2) - { - trkrng(lineNro, 0, lineNro2, 0); - } - - protected void trkrng(int lineNro, int colNro, int lineNro2, int colNro2) - { - if(dbgInfo != null) - dbgInfo.trkRng(lineNro, colNro, lineNro2, colNro2); - } - - protected void callWebObject(String url) - { - httpContext.wjLoc = url; - } - - - public void popup(String url) - { - } - - public void popup(String url, Object[] returnParms) - { - } -} diff --git a/java/src/main/java/com/genexus/webpanels/GXWebReport.java b/java/src/main/java/com/genexus/webpanels/GXWebReport.java deleted file mode 100644 index 1978f2b51..000000000 --- a/java/src/main/java/com/genexus/webpanels/GXWebReport.java +++ /dev/null @@ -1,186 +0,0 @@ -package com.genexus.webpanels; - -import com.genexus.ModelContext; -import com.genexus.ProcessInterruptedException; -import com.genexus.db.UserInformation; -import com.genexus.internet.HttpContext; -import com.genexus.reports.GXReportMetadata; -import com.genexus.reports.IReportHandler; -import com.genexus.reports.PDFReportItext; - -public abstract class GXWebReport extends GXWebProcedure -{ - public static final int OUTPUT_RVIEWER = 1; - public static final int OUTPUT_PDF = 2; - - // Tiene que ser protected porque se pasa como par�metro en los reports - protected GXReportMetadata reportMetadata; - protected IReportHandler reportHandler; - - protected int lineHeight; - protected int Gx_line; - protected int P_lines; - protected int gxXPage; - protected int gxYPage; - protected int Gx_page; - protected String Gx_out = ""; // Esto est� asi porque no me pude deshacer de una comparacion contra Gx_out antes del ask. - protected String filename; - protected String filetype; - - public GXWebReport(HttpContext httpContext) - { - super(httpContext); - } - - protected void initState(ModelContext context, UserInformation ui) - { - super.initState(context, ui); - - httpContext.setBuffered(true); - httpContext.setBinary(true); - - reportHandler = new PDFReportItext(context); - - initValues(); - } - - protected void preExecute() - { - httpContext.setContentType("application/pdf"); - httpContext.setStream(); - - // Tiene que ir despues del setStream porque sino el getOutputStream apunta - // a otro lado. - ((PDFReportItext) reportHandler).setOutputStream(httpContext.getOutputStream()); - } - - protected void setOutputFileName(String outputFileName){ - filename = outputFileName; - } - protected void setOutputType(String outputType){ - filetype = outputType.toLowerCase(); - } - private void initValues() - { - Gx_line = 0; - P_lines = 0; - gxXPage = 0; - gxYPage = 0; - Gx_page = 0; - Gx_out = ""; // Esto est� asi porque no me pude deshacer de una comparacion contra Gx_out antes del ask. - lineHeight = 0; - } - - public void setPrinter(IReportHandler reportHandler) - { - this.reportHandler = reportHandler; - } - - public IReportHandler getPrinter() - { - return reportHandler; - } - - protected void GxEndPage() throws ProcessInterruptedException - { - if (reportHandler != null) - reportHandler.GxEndPage(); - } - - protected boolean initTextPrinter(String output, int gxXPage, int gxYPage, String iniFile, String form, String printer, int mode, int nPaperLength, int nPaperWidth, int nGridX, int nGridY, int nPageLines) - { - int x[] = {gxXPage}; - int y[] = {gxYPage}; - - getPrinter().GxRVSetLanguage(localUtil._language); - boolean ret = getPrinter().GxPrTextInit(output, x, y, iniFile, form, printer, mode, nPaperLength, nPaperWidth, nGridX, nGridY, nPageLines); - - this.gxXPage = x[0]; - this.gxYPage = y[0]; - - return ret; - } - - protected boolean initPrinter(String output, int gxXPage, int gxYPage, String iniFile, String form, String printer, int mode, int orientation, int pageSize, int pageLength, int pageWidth, int scale, int copies, int defSrc, int quality, int color, int duplex) - { - int x[] = {gxXPage}; - int y[] = {gxYPage}; - setResponseOuputFileName(); - - getPrinter().GxRVSetLanguage(localUtil._language); - boolean ret = getPrinter().GxPrintInit(output, x, y, iniFile, form, printer, mode, orientation, pageSize, pageLength, pageWidth, scale, copies, defSrc, quality, color, duplex); - - this.gxXPage = x[0]; - this.gxYPage = y[0]; - - return ret; - } - - private void setResponseOuputFileName(){ - String outputFileName = filename!=null ? filename : getClass().getSimpleName(); - String outputFileType = filetype!=null ? "." + filetype.toLowerCase(): ".pdf"; - httpContext.getResponse().addHeader("content-disposition", "inline; filename=" + outputFileName + outputFileType); - } - - protected void endPrinter() - { - getPrinter().GxEndPrinter(); - } - - protected int getOutputType() - { - return OUTPUT_RVIEWER; - } - - protected java.io.OutputStream getOutputStream() - { - throw new RuntimeException("Output stream not set"); - } - - //M�todos para la implementaci�n de reportes din�micos - protected void loadReportMetadata(String name) - { - reportMetadata = new GXReportMetadata(name, reportHandler); - reportMetadata.load(); - } - - protected int GxDrawDynamicGetPrintBlockHeight(int printBlock) - { - return reportMetadata.GxDrawGetPrintBlockHeight(printBlock); - } - - protected void GxDrawDynamicText(int printBlock, int controlId, int Gx_line) - { - reportMetadata.GxDrawText(printBlock, controlId, Gx_line); - } - - protected void GxDrawDynamicText(int printBlock, int controlId, String value, int Gx_line) - { - reportMetadata.GxDrawText(printBlock, controlId, Gx_line, value); - } - - protected void GxDrawDynamicLine(int printBlock, int controlId, int Gx_line) - { - reportMetadata.GxDrawLine(printBlock, controlId, Gx_line); - } - - protected void GxDrawDynamicRect(int printBlock, int controlId, int Gx_line) - { - reportMetadata.GxDrawRect(printBlock, controlId, Gx_line); - } - - protected void GxDrawDynamicBitMap(int printBlock, int controlId, String value, int Gx_line) - { - reportMetadata.GxDrawBitMap(printBlock, controlId, Gx_line, value, 0); - } - - protected void GxDrawDynamicBitMap(int printBlock, int controlId, String value, int aspectRatio, int Gx_line) - { - reportMetadata.GxDrawBitMap(printBlock, controlId, Gx_line, value, aspectRatio); - } - - protected void cleanup( ) - { - super.cleanup(); - } -} diff --git a/java/src/main/java/com/genexus/webpanels/IDynAjaxEventContext.java b/java/src/main/java/com/genexus/webpanels/IDynAjaxEventContext.java deleted file mode 100644 index 4d3de251b..000000000 --- a/java/src/main/java/com/genexus/webpanels/IDynAjaxEventContext.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.genexus.webpanels; - -public interface IDynAjaxEventContext -{ - void Clear(); - void ClearParmsMetadata(); - boolean isInputParm(String key); - void SetParmHash(String fieldName, Object value); - boolean isParmModified(String fieldName, Object value); - -} \ No newline at end of file From 7e8b9b5068aa4c30a8810469dd6480e25b231a60 Mon Sep 17 00:00:00 2001 From: iroqueta Date: Mon, 15 May 2023 15:38:20 -0300 Subject: [PATCH 3/4] Refactor to move FrontEnd classes to gxweb module from gxclassR module. This allow run non FrontEnd object without Frontend support classes. Issue:102619 --- .../genexus/webpanels/GXWebObjectBase.java | 25 +----------------- .../main/java/com/genexus/GXObjectBase.java | 26 ++++++++++++++++++- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/gxweb/src/main/java/com/genexus/webpanels/GXWebObjectBase.java b/gxweb/src/main/java/com/genexus/webpanels/GXWebObjectBase.java index ba4b717e3..c65510e6a 100644 --- a/gxweb/src/main/java/com/genexus/webpanels/GXWebObjectBase.java +++ b/gxweb/src/main/java/com/genexus/webpanels/GXWebObjectBase.java @@ -1,6 +1,5 @@ package com.genexus.webpanels; -import java.sql.SQLException; import org.apache.commons.lang.StringUtils; import com.genexus.*; @@ -15,7 +14,7 @@ import com.genexus.ModelContext; import com.genexus.security.GXSecurityProvider; -public abstract class GXWebObjectBase extends GXObjectBase implements IErrorHandler, GXInternetConstants, ISubmitteable +public abstract class GXWebObjectBase extends GXObjectBase implements IErrorHandler, GXInternetConstants { public static final ILogger logger = LogManager.getLogger(GXWebObjectBase.class); @@ -173,28 +172,6 @@ public void executeExternalObjectMethod(String CmpContext, boolean IsMasterPage, httpContext.executeExternalObjectMethod(CmpContext, IsMasterPage, containerName, methodName, parms, isEvent); } - /** - * @Hack: Tenemos que ejecutar el submit esto en otro thread, pues el submit es asincrono, - * pero si creamos en el fuente generado el codigo del nuevo thread, se va a crear un - * archivo nuevo xxx$N.class al compilar el xxx, que deberia ser tratado especialmente - * en el makefile (copiado al directorio de servlets, etc); asi que delegamos la - * creacion del thread a la gxclassr donde se llama al metodo a ser ejecutado - * Adem�s ahora manejamos un pool de threads en el submit - */ - public void callSubmit(final int id, Object [] submitParms) - { - com.genexus.util.SubmitThreadPool.submit(this, id, submitParms, context.submitCopy()); - } - - /** Este metodo es redefinido por la clase GX generada cuando hay submits - */ - public void submit(int id, Object [] submitParms, ModelContext ctx){ - } - public void submit(int id, Object [] submitParms){ - } - public void submitReorg(int id, Object [] submitParms) throws SQLException{ - } - public String getPgmname() { return ""; diff --git a/java/src/main/java/com/genexus/GXObjectBase.java b/java/src/main/java/com/genexus/GXObjectBase.java index 92bcf80ab..f30f5ca15 100644 --- a/java/src/main/java/com/genexus/GXObjectBase.java +++ b/java/src/main/java/com/genexus/GXObjectBase.java @@ -8,7 +8,9 @@ import com.genexus.webpanels.HttpContextWeb; import com.genexus.webpanels.WebApplicationStartup; -public abstract class GXObjectBase extends GXRestServiceWrapper{ +import java.sql.SQLException; + +public abstract class GXObjectBase extends GXRestServiceWrapper implements ISubmitteable{ public static final ILogger logger = LogManager.getLogger(GXObjectBase.class); protected ModelContext context; @@ -200,4 +202,26 @@ protected String formatLink(String jumpURL, String[] parms, String[] parmsName) { return URLRouter.getURLRoute(jumpURL, parms, parmsName, httpContext.getRequest().getContextPath(), context.getPackageName()); } + + /** + * @Hack: Tenemos que ejecutar el submit esto en otro thread, pues el submit es asincrono, + * pero si creamos en el fuente generado el codigo del nuevo thread, se va a crear un + * archivo nuevo xxx$N.class al compilar el xxx, que deberia ser tratado especialmente + * en el makefile (copiado al directorio de servlets, etc); asi que delegamos la + * creacion del thread a la gxclassr donde se llama al metodo a ser ejecutado + * Adem�s ahora manejamos un pool de threads en el submit + */ + public void callSubmit(final int id, Object [] submitParms) + { + com.genexus.util.SubmitThreadPool.submit(this, id, submitParms, context.submitCopy()); + } + + /** Este metodo es redefinido por la clase GX generada cuando hay submits + */ + public void submit(int id, Object [] submitParms, ModelContext ctx){ + } + public void submit(int id, Object [] submitParms){ + } + public void submitReorg(int id, Object [] submitParms) throws SQLException { + } } From 62e3645c5e285979a3b4cf2150b6f396a80c87e1 Mon Sep 17 00:00:00 2001 From: iroqueta Date: Tue, 16 May 2023 12:00:32 -0300 Subject: [PATCH 4/4] Refactor to move FrontEnd classes to gxweb module from gxclassR module. This allow run non FrontEnd object without Frontend support classes. Issue:102619 --- .../com/genexus/internet/HttpAjaxContext.java | 14 -------------- .../java/com/genexus/internet/HttpContext.java | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/gxweb/src/main/java/com/genexus/internet/HttpAjaxContext.java b/gxweb/src/main/java/com/genexus/internet/HttpAjaxContext.java index 12d84d2af..fd55ddc2b 100644 --- a/gxweb/src/main/java/com/genexus/internet/HttpAjaxContext.java +++ b/gxweb/src/main/java/com/genexus/internet/HttpAjaxContext.java @@ -763,20 +763,6 @@ public void SendServerCommands() } } - public void ajax_req_read_hidden_sdt(String jsonStr, Object SdtObj) - { - try - { - IJsonFormattable jsonObj; - if (jsonStr.startsWith("[")) - jsonObj = new JSONArray(jsonStr); - else - jsonObj = new JSONObject(jsonStr); - ((IGxJSONAble)SdtObj).FromJSONObject(jsonObj); - } - catch(JSONException exc) {} - } - public void ajax_rsp_assign_prop_as_hidden(String Control, String Property, String Value) { if (!this.isAjaxRequest()) diff --git a/java/src/main/java/com/genexus/internet/HttpContext.java b/java/src/main/java/com/genexus/internet/HttpContext.java index ed7a3cdcb..efe9e5b2f 100644 --- a/java/src/main/java/com/genexus/internet/HttpContext.java +++ b/java/src/main/java/com/genexus/internet/HttpContext.java @@ -4,6 +4,10 @@ import java.util.Date; import java.util.HashMap; import java.util.Hashtable; + +import json.org.json.IJsonFormattable; +import json.org.json.JSONArray; +import json.org.json.JSONException; import json.org.json.JSONObject; import org.apache.logging.log4j.Logger; @@ -935,4 +939,18 @@ public boolean willRedirect() { return wjLoc != null && wjLoc.trim().length() != 0; } + + public void readJsonSdtValue(String jsonStr, Object SdtObj) + { + try + { + IJsonFormattable jsonObj; + if (jsonStr.startsWith("[")) + jsonObj = new JSONArray(jsonStr); + else + jsonObj = new JSONObject(jsonStr); + ((IGxJSONAble)SdtObj).FromJSONObject(jsonObj); + } + catch(JSONException exc) {} + } }