Skip to content

Commit

Permalink
fixed clientwindow handling
Browse files Browse the repository at this point in the history
  • Loading branch information
tandraschko committed Nov 14, 2023
1 parent 12a0691 commit 2b57ef0
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 219 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
import jakarta.faces.FacesException;
import jakarta.faces.context.ExternalContext;
import jakarta.faces.context.FacesContext;
import jakarta.faces.render.ResponseStateManager;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.Map;
import org.apache.deltaspike.jsf.impl.util.ClientWindowHelper;
import org.apache.deltaspike.jsf.impl.util.JsfUtils;
Expand All @@ -51,44 +51,42 @@ public class ClientSideClientWindow extends DeltaSpikeClientWindow


@Override
protected String getOrCreateWindowId(FacesContext facesContext)
public void decode(FacesContext facesContext)
{
String windowId = null;

boolean post = isPost(facesContext);

if (post)
{
windowId = getWindowIdPostParameter(facesContext);
id = getWindowIdPostParameter(facesContext);
}
else if (isNoscriptRequest(facesContext.getExternalContext()))
{
// the client has JavaScript disabled
getClientWindowConfig().setJavaScriptEnabled(false);

windowId = DEFAULT_WINDOW_ID;
id = DEFAULT_WINDOW_ID;
}
else
{
windowId = getVerifiedWindowIdFromCookie(facesContext.getExternalContext());
id = getVerifiedWindowIdFromCookie(facesContext.getExternalContext());

boolean newWindowIdRequested = false;
if (AUTOMATED_ENTRY_POINT_PARAMETER_KEY.equals(windowId))
if (AUTOMATED_ENTRY_POINT_PARAMETER_KEY.equals(id))
{
// this is a marker for generating a new windowId
windowId = generateNewWindowId();
id = generateNewWindowId();
newWindowIdRequested = true;
}

if (windowId == null || newWindowIdRequested)
if (id == null || newWindowIdRequested)
{
// GET request without windowId - send windowhandlerfilter.html to get the windowId
sendWindowHandlerHtml(facesContext.getExternalContext(), windowId);
sendWindowHandlerHtml(facesContext.getExternalContext(), id);
facesContext.responseComplete();
}
}

return windowId;
id = sanitiseWindowId(id);
}

protected boolean isNoscriptRequest(ExternalContext externalContext)
Expand Down Expand Up @@ -234,11 +232,6 @@ public String interceptRedirect(FacesContext facesContext, String url)
requestToken,
windowId);

url = JsfUtils.addParameter(facesContext.getExternalContext(),
url,
true,
ResponseStateManager.CLIENT_WINDOW_URL_PARAM,
windowId);
url = JsfUtils.addParameter(facesContext.getExternalContext(),
url,
true,
Expand All @@ -260,7 +253,7 @@ public boolean isInitialRedirectSupported(FacesContext facesContext)
@Override
public Map<String, String> getQueryURLParameters(FacesContext facesContext)
{
return null;
return Collections.emptyMap();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,45 +36,40 @@ public abstract class DeltaSpikeClientWindow extends ClientWindow
*/
public static final String DEFAULT_WINDOW_ID = "default";

private String id;
private int maxWindowIdCount = 10;
protected String id;
protected int maxWindowIdCount = 10;

public DeltaSpikeClientWindow()
{
this.maxWindowIdCount = ClientWindowHelper.getMaxWindowIdLength();
}

@Override
public void decode(FacesContext facesContext)
{
id = getOrCreateWindowId(facesContext);

if (id != null)
{
id = sanitiseWindowId(id);
if (id.length() > this.maxWindowIdCount)
{
id = id.substring(0, this.maxWindowIdCount);
}
}
}

@Override
public String getId()
{
return id;
}

/**
/**
* We have to escape some characters to make sure we do not open
* any XSS vectors. E.g. replace (,<, & etc to
* prevent attackers from injecting JavaScript function calls or html.
*/
protected String sanitiseWindowId(String windowId)
{
return StringUtils.removeSpecialChars(windowId);
if (windowId == null)
{
return null;
}

windowId = StringUtils.removeSpecialChars(windowId);
if (windowId.length() > this.maxWindowIdCount)
{
windowId = windowId.substring(0, this.maxWindowIdCount);
}
return windowId;
}

protected String generateNewWindowId()
{
//X TODO proper mechanism
Expand Down Expand Up @@ -121,9 +116,7 @@ protected ClientWindowConfig getClientWindowConfig()
{
return BeanProvider.getContextualReference(ClientWindowConfig.class);
}

protected abstract String getOrCreateWindowId(FacesContext facesContext);


/**
* @return true if the implementation possible sends an initial redirect.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
import org.apache.deltaspike.jsf.impl.util.ClientWindowHelper;

import jakarta.faces.context.FacesContext;
import jakarta.faces.render.ResponseStateManager;
import java.util.HashMap;
import java.util.Collections;
import java.util.Map;
import org.apache.deltaspike.core.api.provider.BeanProvider;
import org.apache.deltaspike.core.util.StringUtils;
Expand All @@ -31,52 +30,42 @@
public class LazyClientWindow extends DeltaSpikeClientWindow
{
@Override
protected String getOrCreateWindowId(FacesContext facesContext)
public void decode(FacesContext facesContext)
{
String windowId = ClientWindowHelper.getInitialRedirectWindowId(facesContext);
id = ClientWindowHelper.getInitialRedirectWindowId(facesContext);

if (StringUtils.isEmpty(windowId))
if (StringUtils.isEmpty(id))
{
windowId = getWindowIdParameter(facesContext);
id = getWindowIdParameter(facesContext);
}

boolean post = isPost(facesContext);

if (StringUtils.isEmpty(windowId) && post)
if (StringUtils.isEmpty(id) && post)
{
windowId = getWindowIdPostParameter(facesContext);
id = getWindowIdPostParameter(facesContext);
}

if (StringUtils.isEmpty(windowId))
if (StringUtils.isEmpty(id))
{
id = generateNewWindowId();

JsfModuleConfig jsfModuleConfig = BeanProvider.getContextualReference(JsfModuleConfig.class);
if (jsfModuleConfig.isInitialRedirectEnabled() && !post)
{
ClientWindowHelper.handleInitialRedirect(facesContext, generateNewWindowId());
id = sanitiseWindowId(id); // handleInitialRedirect already takes the id, just be sure and sanitise now
ClientWindowHelper.handleInitialRedirect(facesContext, id);
facesContext.responseComplete();
windowId = null;
}
else
{
windowId = generateNewWindowId();
}
}

return windowId;
id = sanitiseWindowId(id);
}

@Override
public Map<String, String> getQueryURLParameters(FacesContext facesContext)
{
String windowId = getId();
if (windowId == null)
{
return null;
}

Map<String, String> parameters = new HashMap<>();
parameters.put(ResponseStateManager.CLIENT_WINDOW_URL_PARAM, windowId);
return parameters;
return Collections.emptyMap();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
*/
package org.apache.deltaspike.jsf.impl.listener.request;


import org.apache.deltaspike.core.spi.activation.Deactivatable;
import org.apache.deltaspike.core.util.ClassDeactivationUtils;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ public void attachWindow(FacesContext facesContext)
{
facesContext.getExternalContext().setClientWindow(new ClientSideClientWindow());
}
facesContext.getExternalContext().getClientWindow().decode(facesContext);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import jakarta.faces.FacesException;
import jakarta.faces.context.ExternalContext;
import jakarta.faces.context.FacesContext;
import jakarta.faces.render.ResponseStateManager;

import org.apache.deltaspike.jsf.api.config.base.JsfBaseConfig;

Expand Down Expand Up @@ -56,12 +57,12 @@ public static String constructRequestUrl(ExternalContext externalContext)
{
url += externalContext.getRequestPathInfo();
}

url = JsfUtils.addRequestParameters(externalContext, url, true);
//TODO check if it isn't better to fix addRequestParameters itself
//only #encodeResourceURL is portable currently
url = externalContext.encodeResourceURL(url);
// always remove jfwid to force adding new jfwid as JSF impl otherwise just ignores it
url = JsfUtils.removeUrlParameter(url, ResponseStateManager.CLIENT_WINDOW_URL_PARAM);
url = externalContext.encodeRedirectURL(url, null);

return url;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@
import java.lang.reflect.InvocationTargetException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.apache.deltaspike.core.util.StringUtils;

public abstract class JsfUtils
Expand All @@ -65,7 +67,7 @@ public static Set<RequestParameter> getViewConfigPageParameters()
{
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();

Set<RequestParameter> result = new HashSet<RequestParameter>();
Set<RequestParameter> result = new HashSet<>();

if (externalContext == null || //detection of early config for different mojarra versions
externalContext.getRequestParameterValuesMap() == null || externalContext.getRequest() == null)
Expand Down Expand Up @@ -105,7 +107,7 @@ public static String addPageParameters(ExternalContext externalContext, String u
for (String parameterValue : requestParam.getValues())
{
if (!url.contains(key + "=" + parameterValue) &&
!url.contains(key + "=" + encodeURLParameterValue(parameterValue, externalContext)))
!url.contains(key + "=" + encodeUrlParameterValue(parameterValue, externalContext)))
{
if (!existingParameters)
{
Expand Down Expand Up @@ -139,7 +141,7 @@ public static String addParameter(ExternalContext externalContext, String url, b
{
// don't append if already available
if (url.contains(name + "=" + value)
|| url.contains(name + "=" + encodeURLParameterValue(value, externalContext)))
|| url.contains(name + "=" + encodeUrlParameterValue(value, externalContext)))
{
return url;
}
Expand Down Expand Up @@ -184,7 +186,7 @@ public static String addRequestParameters(ExternalContext externalContext, Strin
for (String value : entry.getValue())
{
if (!url.contains(entry.getKey() + "=" + value) &&
!url.contains(entry.getKey() + "=" + encodeURLParameterValue(value, externalContext)))
!url.contains(entry.getKey() + "=" + encodeUrlParameterValue(value, externalContext)))
{
if (StringUtils.isEmpty(entry.getKey()) && StringUtils.isEmpty(value))
{
Expand Down Expand Up @@ -214,7 +216,7 @@ protected static void appendUrlParameter(StringBuilder url, String name, String
{
if (encode)
{
url.append(encodeURLParameterValue(name, externalContext));
url.append(encodeUrlParameterValue(name, externalContext));
}
else
{
Expand All @@ -225,14 +227,33 @@ protected static void appendUrlParameter(StringBuilder url, String name, String

if (encode)
{
url.append(encodeURLParameterValue(value, externalContext));
url.append(encodeUrlParameterValue(value, externalContext));
}
else
{
url.append(value);
}
}

public static String removeUrlParameter(String url, String name)
{
if (url == null || !url.contains(name) || (!url.contains("?") && !url.contains("&")))
{
return url;
}

String[] array = url.split("\\?");
String params = Arrays.asList(array[1].split("&"))
.stream()
.filter(item -> !item.split("=")[0].equalsIgnoreCase(name) && !"".equals(item.split("=")[1]))
.collect(Collectors.joining("&"));
if (params == null || params.isBlank())
{
return array[0];
}
return String.join("?", array[0], params);
}

/**
* Encodes the given value using URLEncoder.encode() with the charset returned
* from ExternalContext.getResponseCharacterEncoding().
Expand All @@ -242,7 +263,7 @@ protected static void appendUrlParameter(StringBuilder url, String name, String
* @param externalContext current external-context
* @return encoded value
*/
public static String encodeURLParameterValue(String value, ExternalContext externalContext)
public static String encodeUrlParameterValue(String value, ExternalContext externalContext)
{
// copied from MyFaces ServletExternalContextImpl.encodeURL()
try
Expand Down Expand Up @@ -309,7 +330,7 @@ public static void tryToRestoreMessages(FacesContext facesContext)

@SuppressWarnings({ "unchecked" })
List<FacesMessageEntry> facesMessageEntryList = windowMetaData.getFacesMessageEntryList();
List<FacesMessage> originalMessageList = new ArrayList<FacesMessage>(facesContext.getMessageList());
List<FacesMessage> originalMessageList = new ArrayList<>(facesContext.getMessageList());

if (facesMessageEntryList != null)
{
Expand Down
Loading

0 comments on commit 2b57ef0

Please sign in to comment.