1

I am working on an ArcGIS WAB app that needs to reference proprietary lightning strike data which is only provided through the vendor as a secured WFS service. Ideally, this would be a layer inside a WebMap in AGOL that is consumed by WAB. To access the service, I need to provide a Basic Authorization header, which there is no way to specify that in AGOL to my knowledge. So far this is what I have tried:

  1. modified the .NET proxy provided by ESRI (see proxy code at bottom of post)
  2. Tested the proxy to make sure requests were going through with the header, this was successful. enter image description here
  3. Tried to add a "layer from the web" in an AGOL WebMap, with the proxy url in front of the actual WFS url.
  4. This part works, as it will set the request parameter to GetCapabilities, which returns a valid list of layers available in the WFS service. Awesome! enter image description here
  5. But here is where things break down...Once I choose a layer from the drop down, AGOL must have some internal validation which strips out my proxy and substitutes it with the default myorg.maps.arcgis.com/sharing/proxy that AGOL uses. Obviously, I get an error here because that proxy doesn't know to add my auth header:

enter image description here

By using Fiddler, I was able to see the proxy is no longer being used:

enter image description here

So with all those things failing, because I'm creating a custom widget anyways, I thought the next best thing would be to just create a new WFSLayer() and add my proxy to the esriConfig (wfs layers require a proxy anyways) to add manually from the widget. This also did not work, as for some reason a preflight OPTIONS request is getting sent to the proxy, and it simply does not respond with anything. The weird thing is, if I copy and paste the same request that the JS API makes into the browser window, the request returns back the data (this is a GET request though). This is the JS code I'm using:

// set proxy for WFS layer
esriConfig.defaults.io.proxyUrl = 'https://my-domain.com/folder/proxy2/proxy.ashx';

var wfs = new WFSLayer();
wfs.fromJson({
  "url": "https://weather-services.domain.com/basic/wfs_v1/wfs.wsgi",
  "version": "1.0.0",
  "name": "LIGHTNING_STROKES",
  "maxFeatures": 1000
});
this.map.addLayer(wfs);

And here are the modifications I added to the .net proxy:

First, added an element to the proxy.config:

<OGCServer domain="weather-services.domain.com" header="Authorization" headerValue="Basic some_basic_auth_string"/>

Then in the proxy.ashx I created a new class to handle the OGCResource from the config:

public class OGCResource
{
    string domain;
    string header;
    string headerValue;

    private OGCResource()
    {
    }

    public OGCResource(String domain)
    {
        this.domain = domain;
    }

    [XmlAttribute("domain")]
    public string Domain
    {
        get { return domain; }
        set { domain = value; }
    }

    [XmlAttribute("header")]
    public string Header
    {
        get { return header; }
        set { header = value; }
    }

    [XmlAttribute("headerValue")]
    public string HeaderValue
    {
        get { return headerValue; }
        set { headerValue = value; }
    }
}

then exposed it to the ProxyConfig object:

  // OGC configs
    [XmlElement("OGCServer")]
    public OGCResource OGCServer
    {
        get { return ogcServer; }
        set { ogcServer = value;  }
    }

And finally, modified the doHttpRequest() method to check if the request is going to the WFS service domain:

private System.Net.WebResponse doHTTPRequest(string uri, byte[] bytes, string method, string referer, string contentType, System.Net.NetworkCredential credentials = null)
    {
        System.Net.HttpWebRequest req = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(uri);
        req.ServicePoint.Expect100Continue = false;
        req.Referer = referer;
        req.Method = method;
        ProxyConfig config = ProxyConfig.GetCurrentConfig();

        if (config.ogcServer != null)
        {
            if (uri.Contains(config.ogcServer.Domain)) {
                // add custom auth header for DTN lightning service
                log(TraceLevel.Info, "added custom header to ogc service request");
                req.Headers.Add(config.ogcServer.Header, config.ogcServer.HeaderValue);
            }
        }

        // Use the default system proxy
        req.Proxy = SYSTEM_PROXY;

        if (credentials != null)
            req.Credentials = credentials;

        if (bytes != null && bytes.Length > 0 || method == "POST") {
            req.Method = "POST";
            req.ContentType = string.IsNullOrEmpty(contentType) ? "application/x-www-form-urlencoded" : contentType;
            if (bytes != null && bytes.Length > 0)
                req.ContentLength = bytes.Length;
            using (Stream outputStream = req.GetRequestStream()) {
                outputStream.Write(bytes, 0, bytes.Length);
            }
        }
        return req.GetResponse();
    }

Has anyone ever been able to get something like this to work before? I cannot find any documentation on using secured WFS layers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.