How to deal with a controller which could be called either with http either with https (Twitter Follow up)

Topics: Customizing Orchard, Troubleshooting, Writing modules
Sep 14, 2013 at 6:49 PM
Edited Sep 14, 2013 at 6:59 PM
The problem: I have a page which user could choose to have either displayed in http either in https (page from the admin in this case, but could apply to any page).
Using the ssl module written by Sebastien and reworked to have it running by Bertrand, you may decide or not to have your admin pages secured or not by an ssl certififcate.

My module contains a part which have content item settings, in their editor I call using ajax a controller action to bring back a json list to update a <select>.

On the first writting I simply used a normal controller whith [httpPost] attribute.
I had forgotten that using the ssl module I have choosen to have the admin under https.
Using this all the ajax calls were placed using an https target url and received a 'moved' answer with the good http protocol and port....could be nice, but my call is transformed from a POST in a GET and is missing the original data I was sending with this kind of code
var srvurl = $("#ajaxurl").val();
    $.ajax({
        url: srvurl ,
        type: 'POST',
        dataType: "",
        data: formToJSON($(this).val()),
        error: function (xhr, ajaxOptions, thrownError) {
           /* $("#loader").hide();*/
            return false;
        },
        success: function (data, textStatus, jqXHR) {
            var items = [];
            $(data).each(function (index, item) {
                items.push('<option>' + item + '</option>');
            });
            $('.propertyname').empty().append.apply($('.propertyname'), items);
            }
        });
with in my view
<input id="ajaxurl" type="hidden" value='@Url.Action("GetProperties","ConnectorFeeder", new { area = "Datwendo.ConnectorFeeder"})' />
and
@using(Script.Head()) {
<script type="text/javascript">
//<![CDATA[
    var antiForgeryToken = '@Html.AntiForgeryTokenValueOrchard()';
//]]>
</script>
}
I found no way to have a controller action able to answer either in http, either in https, so I decided to make an https only controller, adding the attribute
[RequireHttps]

but here still 404 answers, I don't understand why ? I had to add the attributes
    [HttpPost]
    [RequireHttps]
    [Themed(false)]
    public JsonResult GetProperties(string partName)
so my code is working only for admin secured by ssl, if user want an http admi, he will have to change my code !!! no very cool, why not also trying to use silex to start Orchard .....

This said, I am unable to use JQuery and send json data to Orchard due to the anti-forgery, no way to say I am sending
with these parameters
                dataType: "json",
                contentType: 'application/json',
                data: formToJSON(....),
but this is another problem....
This thread is a bargain: 2 problems for only one thread.
Last but not least, I am quite satisfied with the actual ssl module and its ability to select the pages to secure by ssl, only need an 'all ssl option', eventually....
Coordinator
Sep 14, 2013 at 8:56 PM
That's why in the new ssl module, there's an API to get a secure URL. This way, you get a URL for your POST that won't get redirected and changed into a GET.

There will be an all SSL option, yes.
Mar 10, 2014 at 10:19 AM
Edited Mar 10, 2014 at 10:22 AM
I've run across a similar issue when using the new Orchard.SecureSocketsLayer module in conjunction with ajax requests (in my case using sky walker's nice new IDeliverable.AjaxWidget).

When performing an Ajax call the request will generally be made over the same transport as the page that the request was made from (ie. ajax over http for a page loaded via http and ajax over https for a page loaded via https).

The scenario now arises where we have an ajax widget that is loaded on many pages throughout a website, where some of those pages are http and some are https (controlled via the ssl module's "Enable SSL on specific pages" option (and associated url patterns).

The problem is, with SSL redirection enabled, the module will either force a route to always be http (if it doesn't match a URL pattern) or always be https (if it's listed in the URL pattern). This breaks ajax when viewing a page over SSL, as the ajax request may be redirected to http (and you're generally not allowed to call https over ajax from a http page - and vice versa). If you add the route for the ajax request to the URL pattern, then it will work for pages over SSL but then stop working for pages over HTTP.

A simple fix I think for the ajax case is to modify the SecureSocketsLayerFilter.OnActionExecuting method to do nothing if the request is an ajax request, because generally ajax calls should be getting made over the same transport as the page, and so redirection shouldn't be necessary.

Changing....
public void OnActionExecuting(ActionExecutingContext filterContext) {
    var settings = _sslService.GetSettings();

    if (!settings.Enabled) {
        return;
    }
to this....
public void OnActionExecuting(ActionExecutingContext filterContext) {
    var settings = _sslService.GetSettings();

    if ((!settings.Enabled) ||
            filterContext.RequestContext.HttpContext.Request.IsAjaxRequest()) {
        return;
    }
resolves the problem for ajax requests.

Is this something we could look at getting put into core?

I still think there may be scenarios where specific pages (or ajax actions) need to support both http and https, so I really think the ssl module needs an additional configuration field to allow a list of "ignore" routes to be specified. Any routes that match these patterns should not be redirected either way (http -> https OR https -> http).

If we were to consider this, then I guess the ajax specific solution that I've implemented above could be left out, as we could then simply add the ajax route to the ignore pattern.