Content provider policy requests and responses

Use the Request and Response tabs to define a fine-grained control over HTTP headers, HTTP cookies, and filters. Filters provide a programmatic control over content during the request and response phases of the interaction between HCL Digital Experience and the web application.

Headers

Specify the allowed (propagated) or blocked headers in the requests and responses to and from the content provider. By default, the Web Application Bridge propagates all the client-side headers. The client-side headers are present in the request that is received from the browser. The Web Application Bridge does not propagate headers that are listed in the block field.

Click Insert Header to add custom headers. The custom headers are useful for the following scenarios:
  • To add more headers that are not there in the request from the browser
  • To add more headers that are not there in the request from the content provider
  • To use single sign-on
  • To send more information
If you add a custom header with the same name as an existing header, the custom header overrides the existing header.

Cookies

Specify the allowed or blocked cookies in the request from the browser or the response from the content provider. By default, the Web Application Bridge blocks all the client-side cookies from reaching the content provider. The client-side cookies are present in the request that is received from the browser. You need to specify the client-side cookies that need to be propagated by selecting Block all, except in the Cookies section of the Request tab and specifying individual cookies.

Click Insert Cookies to add custom cookies. The custom cookies are useful for the following scenarios:
  • To add more cookies that are not there in the request from the browser
  • To add more cookies that are not there in the response from the content provider
  • To use single sign-on
  • To send more information

If you add a custom request cookie with the same name as an existing cookie, the custom cookie overrides the existing cookie. If you add a custom response cookie, the Web Application Bridge adds a Set-Cookie header. The Web Application Bridge uses the provided name and value in responses that are sent from the Reverse Proxy servlet to the browser.

Filters

Filters are Java code that can be started on demand to run custom actions. They modify the request programmatically. Filters are extensions to core feature. Use the servlet filter API to create custom filters. The filters manipulate the request or response from the portal to the content provider. Developers create the filters. First, the administrator clicks Insert request filter to specify the set of filters that are available to apply to this policy. Then, the administrator clicks Add Filter to apply the filter to the policy.

Complete the following steps to create custom filters:
  1. Create a Java file with one of the following sample codes.
    The following code inserts a sample header and cookie into a request that goes from the portal to the content provider site:
    
    /* @copyright module */
    /*                                                                            */
    /*  DISCLAIMER OF WARRANTIES:                                                 */
    /*  -------------------------                                                 */
    /*  The following [enclosed] code is sample code created by IBM Corporation.  */
    /*  This sample code is provided to you solely for the purpose of assisting   */
    /*  you in the development of your applications.                              */
    /*  The code is provided "AS IS", without warranty of any kind. IBM shall     */
    /*  not be liable for any damages arising out of your use of the sample code, */
    /*  even if they have been advised of the possibility of such damages.        */
    
    package com.ibm.wps.wab.filter;
    
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.net.HttpURLConnection;
    import java.net.URLEncoder;
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    import java.util.TreeMap;
    
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    
    import com.ibm.portal.um.PumaHome;
    import com.ibm.portal.um.PumaProfile;
    import com.ibm.portal.um.User;
    import com.ibm.portal.um.exceptions.PumaException;
    
    import com.ibm.wps.vwat.servlet.ReverseProxyRequest;
    
    @SuppressWarnings("unused")
    public class SampleRequestFilter implements Filter {
    
        private ReverseProxyRequest reverseProxyRequest = null;
       
        @Override
        public void destroy() {
            // TODO Auto-generated method stub
    
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
            this.reverseProxyRequest  = (ReverseProxyRequest)request;
           
            //add a custom cookie
            String cookieName = "TestCookieName";
            String cookieValue = "TestCookieValue";       
            addCookie(cookieName, cookieValue);
           
            //add a custom header
            String headerName = "TestHeaderName";
            String headerValue = "TestHeaderValue";
            addHeader(headerName, headerValue);
           
           
            //Please not do not remove this
            chain.doFilter(request, response);
        }
    
        public void addCookie(final String name, String value) {
            if (name == null || name.trim().length() == 0) {
                return;
            }
            if (value != null) {
                value = value.trim();
            }
            else {
                value = "";
            }       
           
            String cookieHeader = reverseProxyRequest.getConnection().getRequestProperty("Cookie");   
            if(cookieHeader != null)
                cookieHeader = cookieHeader + ";" + name + "=" + value;
            else
                cookieHeader = name + "=" + value;   
           
            reverseProxyRequest.getConnection().setRequestProperty("Cookie", cookieHeader);
           
        }
       
        public void addHeader(final String name, final String value) {
           
            if (name == null || name.trim().length() == 0) {
                return;
            }
            this.reverseProxyRequest.getConnection().addRequestProperty(name, value);   
        }
       
        @Override
        public void init(FilterConfig arg0) throws ServletException {
            // TODO Auto-generated method stub
    
        }
    
    }
    The following code is a response filter:
    
    /* @copyright module */
    /*                                                                            */
    /*  DISCLAIMER OF WARRANTIES:                                                 */
    /*  -------------------------                                                 */
    /*  The following [enclosed] code is sample code created by IBM Corporation.  */
    /*  This sample code is provided to you solely for the purpose of assisting   */
    /*  you in the development of your applications.                              */
    /*  The code is provided "AS IS", without warranty of any kind. IBM shall     */
    /*  not be liable for any damages arising out of your use of the sample code, */
    /*  even if they have been advised of the possibility of such damages.        */
    
    package com.ibm.wps.wab.filter;
    
    import java.io.IOException;
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.UnsupportedEncodingException;
    import java.util.Collection;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.zip.GZIPInputStream;
    import java.util.zip.GZIPOutputStream;
    
    import javax.servlet.ServletOutputStream;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    
    import com.ibm.wps.vwat.servlet.ReverseProxyRequest;
    import com.ibm.wps.vwat.servlet.ReverseProxyResponse;
    
    @SuppressWarnings("unused")
    public class SampleRequestFilter implements Filter {
    
        private ReverseProxyResponse reverseProxyResponse = null;
        private String encoding = null;
        private Map<String, String> matchAndReplace = null;
       
        @Override
        public void destroy() {
            // TODO Auto-generated method stub
    
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
            this.reverseProxyResponse  = (ReverseProxyResponse)response;
           
            String contentType = reverseProxyResponse.getHeaderValue("Content-Type");
    
            if(contentType != null && contentType.equals("text/html; charset=UTF-8")){
                    Collection<String> headers = reverseProxyResponse.getConnection().getHeaderFields().keySet();
                    String[] names = headers.toArray(new String[headers.size()]);
                    for (int i = 0; i < names.length; i++) {
                        String header = names[i];
                        if (header.trim().equalsIgnoreCase("Content-Encoding")) {
                            encoding = reverseProxyResponse.getConnection().getHeaderField(header);
                            break;
                        }
                    }
                    ResponseWrapper wrapper = new ResponseWrapper(reverseProxyResponse, encoding);   
                    wrapper.setMatchAndReplace();
            }
           
           
            //Please not do not remove this
            chain.doFilter(request, wrapper);
        }
       
        @Override
        public void init(FilterConfig arg0) throws ServletException {
            // TODO Auto-generated method stub
    
        }
    
        class ResponseWrapper extends ReverseProxyResponse{
    
            private static final int BYTE_BUFFER_SIZE = 8192;
            ReverseProxyResponse proxyResponse;
            private String encoding = null;
            private int contentLength = -1;
            private boolean _changed = false;
            private ReverseProxyResponse response = null;
            private Map<String, String> matchAndReplace = null;
    
        public ProxyResponseWrapper(ReverseProxyResponse resp, String encoding) throws UnsupportedEncodingException {
            super(resp, resp.getConnection());
            isDebugEnabled = true;
            response = resp;
        }
       
        public void setMatchAndReplace() {
            Map<String, String> replacers = new HashMap<String, String>();
            replacers.put("top","self");
            if (replacers != null && replacers.size() != 0) {
                matchAndReplace = replacers;
            }
        }
    
        @Override
        public ServletOutputStream getOutputStream() throws IOException {
            BaseOutputStreamWrapper streamWrapper = new BaseOutputStreamWrapper(super.getOutputStream());
            return streamWrapper;
        }
    
        class BaseOutputStreamWrapper extends ServletOutputStream {
    
            private static final int BYTE_BUFFER_SIZE = 4 * 1024;
            private ServletOutputStream originalStream = null;
    
            public BaseOutputStreamWrapper(final ServletOutputStream originalStream) {
                this.originalStream = originalStream;
            }
    
            @Override
            public void write(byte[] arg0, int arg1, int arg2) throws IOException {
               
                if (contentType == null || !contentType.contains("text/html")) {
                    super.write(arg0, arg1, arg2);
                    return;
                }
                ByteArrayInputStream bios = new ByteArrayInputStream(arg0);
                InputStream in = bios;
                if (encoding != null && encoding.indexOf("gzip") != -1) {
                    in = new GZIPInputStream(bios, BYTE_BUFFER_SIZE);
                }
                byte[] resultInBytes = IOSupport.readStream(in);
                contentLength = resultInBytes.length;
                if (charset == null || charset.trim().isEmpty()) {
                    charset = "UTF-8";
                }
                String original = new String(resultInBytes, charset);
                String modified = new String(original);
                if (isDebugEnabled) {
                    LOGGER.text(Logger.TRACE_HIGH, METHOD_NAME, "Checking for text replacements.");
                }
                if (matchAndReplace != null && matchAndReplace.size() != 0) {
                    Iterator<String> iter = matchAndReplace.keySet().iterator();
                    while (iter.hasNext()) {
                        String key = iter.next();
                        if (modified.contains(key)) {
                            if (isDebugEnabled) {
                                LOGGER.text(Logger.TRACE_HIGH, METHOD_NAME, "Attempting replacement for " + key);
                            }
                            modified = modified.replace(key, matchAndReplace.get(key));
                            _changed = true;
                        }
                    }
                }
                if (isDebugEnabled) {
                    LOGGER.text(Logger.TRACE_HIGH, METHOD_NAME, "Replacements if found, have been done.");
                }
                if (_changed) {
                    resultInBytes = modified.getBytes(charset);
                    contentLength = resultInBytes.length;
                    response.setContentLength(contentLength);
                    ByteArrayOutputStream baos = null;
                    if (encoding != null && encoding.indexOf("gzip") != -1) {
                        baos = new ByteArrayOutputStream();
                        GZIPOutputStream zipOut = new GZIPOutputStream(baos);
                        if (resultInBytes != null) {
                            zipOut.write(resultInBytes, 0, contentLength);
                        }
                        zipOut.finish();
                        zipOut.flush();
                        contentLength = baos.size();
                        response.setContentLength(contentLength);
                        ByteArray bytes = new ByteArray(bytePool);
                        bytes.reset();
                        bytes.ensureCapacity(BYTE_BUFFER_SIZE);
                        bytes.append(baos.toByteArray());
                        bytes.empty(this.originalStream);
                    }
                    else {
                        in = new ByteArrayInputStream(resultInBytes, 0, contentLength);
                        boolean done = false;
                        int count = 0;
                        ByteArray bytes = new ByteArray(bytePool);
                        bytes.reset();
                        bytes.ensureCapacity(BYTE_BUFFER_SIZE);
                        while (!done) {
                            int read = bytes.fill(in);
                            if (read == -1) {
                                done = true;
                            }
                            else {
                                count += read;
                                bytes.empty(this.originalStream);
                            }
                        }
                    }
                }
                else {
                    super.write(arg0, arg1, arg2);
                }
            }
        }
        }
    
    
    }
    
  2. Complete the following steps to engage the filter:
    Note: In a clustered environment, the filter jar file should be put on all nodes.
    1. Create a filter component Java file with at least one class that implements the javax.servlet.Filter interface.
    2. Compile the filter component Java file against the following items:
      • VWAT servlet (runtime.jar in the wp_profile/installedApps/cell-name/wp.vwat.servlet.ear.ear/wp.vwat.servlet.war/WEB-INF/lib directory)
      • VWAT engine JAR files (in the PortalServer\bp\wp.vwat.engine\shared\app\wp.vwat.engine.jar directory)
      • All portal and IBM® WebSphere® Application Server Java archive and compressed files
      Tip: Use the Rational Application Developer Portal project because it already has the correct build paths for HCL Digital Experience and IBM WebSphere Application Server.
    3. Build a .jar file with the compiled class files.
    4. Place the .jar file in the PortalServer/shared/app directory.
      Note: In a clustered environment, place the .jar file in the PortalServer/shared/app directory of each node.
    5. Restart the WebSphere_Portal server.
      Note: In a clustered environment, also restart all the nodes.