4

I am attempting to forward custom parameters to a RESTful API server and return the proxied response to the client-facing server. I don't want the client to have access to or be able to read the API HTTP request/response interactions, so I decided to perform this action using a reverse proxy. I have no problem forwarding the request and returning a response. The problem lies in the authentication. The client-facing server always wants to redirect to the login page because it doesn't believe the client is authenticated. I have tried using HTTPS and HTTP with similar results.

I have been researching this problem for quite some time and found quite a variety of answers, none of which seem to quite encompass my specific use case. I am following this example, which is the closest to what I specifically need. However, the credentials portion the author commented out (//request.Credentials = CredentialCache.DefaultCredentials;) doesn't seem to cover the authentication portion I am attempting to implement. Please help me understand this problem and solution.

Here is the code I am using from the controller:

public ActionResult ProxyEndpoint(string custom_string, string another_custom_string)
{
    //Bunch of code here to grab the remoteUrl from AppConfig and do stuff to the parameters and store them in queryString, unnecessary to show here.

    //Here's the important bits:
    remoteUrl = remoteUrl + "?" + queryString; // create my remoteUrl
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(remoteUrl);
    request.Credentials = CredentialCache.DefaultCredentials;
    // Also tried this to no avail:
    request.Credentials = CredentialCache.DefaultNetworkCredentials;
    return ProxyActionResult(request.GetResponse());
}

Here is the ProxyActionResult class:

public class ProxyActionResult : ActionResult
{
    WebResponse _response;

    public ProxyActionResult(WebResponse response)
    {
        _response = response;
    }

    public override void ExecuteResult(ControllerContext controllerContext)
    {
        HttpContextBase httpContext = controllerContext.HttpContext;
        WebResponse response = _response;

        // Read the byte stream from the response:
        Stream responseStream = response.GetResponseStream();

        // Pulled this next piece from http://www.codeproject.com/Articles/7135/Simple-HTTP-Reverse-Proxy-with-ASP-NET-and-IIS
        // Seemed to fit our use case.
        if ((response.ContentType.ToLower().IndexOf("html") >= 0) || (response.ContentType.ToLower().IndexOf("javascript") >= 0))// || (response.ContentType.ToLower().IndexOf("image") >= 0))
        {
            //If the response is HTML Content, parse it like HTML:
            StreamReader readStream = new StreamReader(responseStream, Encoding.Default);

            String content;

            content = ParseHtmlResponse(readStream.ReadToEnd(), httpContext.Request.ApplicationPath);

            //Write the updated HTML to the client(and then close the response):
            httpContext.Response.Write(content);
            httpContext.Response.ContentType = response.ContentType;

            response.Close();
            httpContext.Response.End();
        }
        else
        {
            // If the response is not HTML Content, write the stream directly to the client:
            var buffer = new byte[1024];
            int bytes = 0;
            while ((bytes = responseStream.Read(buffer, 0, 1024)) > 0)
            {
                httpContext.Response.OutputStream.Write(buffer, 0, bytes);
            }
            // from http://www.dotnetperls.com/response-binarywrite
            httpContext.Response.ContentType = response.ContentType; // Set the appropriate content type of the response stream.
            // and close the stream:
            response.Close();
            httpContext.Response.End();
        }
        //throw new NotImplementedException();
    }
    // Debating whether we need this:
    public string ParseHtmlResponse(string html, string appPath)
    {
        html = html.Replace("\"/", "\"" + appPath + "/");
        html = html.Replace("'/", "'" + appPath + "/");
        html = html.Replace("=/", "=" + appPath + "/");
        return html;
    }
4
  • It would help if you know what/how authentication mechanism the API requires. That would pretty much dictate if you actually can do what you are planning to do (assuming I understood your question - re: "proxy" for who?) Commented Mar 9, 2016 at 23:05
  • There is no authentication required for the API. It can be accessed via a simple GET Commented Mar 10, 2016 at 21:30
  • Confused...I meant the (remote) api you are proxying for and the reason you're sending some credentials request.Credentials = CredentialCache.DefaultCredentials; to it... Commented Mar 10, 2016 at 22:44
  • Exactly, I can perform a simple GET request to the remote API and it doesn't request any credentials. That's why I was confused as to why it keeps redirecting me to the Login page. I actually figured it out, however. It turns out that the remote server, which is running ArcGIS OpenLayers had a setting that required crossOrigin authentication. I commented out the crossOrigin authentication and it worked perfectly. Nothing was wrong with my code that I posted here. Thanks for the help! Commented Mar 12, 2016 at 20:07

1 Answer 1

2

It turns out that nothing is wrong with the reverse proxy code. The remote server was an ArcGIS OpenLayers API and it had a setting that said crossOrigin: anonymous. I commented out this setting and it worked perfectly.

Check out the documentation if you have this particular ArcGIS OpenLayers problem: http://openlayers.org/en/v3.14.2/apidoc/ol.source.ImageWMS.html

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.