tags:

views:

1073

answers:

2

My question revolves around a WCF REST Service for IIS that responds with JSONP. I took the classes in this solution: http://msdn.microsoft.com/en-us/library/cc716898.aspx and added them to mine. Things were working fine on my developer workstation using impersonation with httpTransport but when I tried to move up to the development server I ran into some security issues. These issues were solved using the configuration below and an App Pool identity user. I also configuring the IIS metabase file for NTLM only authentication (we are using IIS 6 but will be IIS 7 soon, needs to work on both) as I don't have access to make an SPN. I believe the current configuration solved my security problems but in the process my JSONP response was downgraded to regualar JSON, this is the problem. Here is the relevant configuration:

    <services>
        <service name="IS.Core.Infrastructure.RESTRouter.Transactions" behaviorConfiguration="">
            <endpoint address="" behaviorConfiguration="webHttp" binding="customBinding"
              bindingConfiguration="jsonpBinding" contract="IS.Core.Infrastructure.RESTRouter.ITransactions">
            </endpoint>
        </service>

        <service name="IS.Core.Infrastructure.RESTRouter.Queue" behaviorConfiguration="">
            <endpoint address="" behaviorConfiguration="webHttp"  binding="customBinding"
                bindingConfiguration="jsonpBinding" contract="IS.Core.Infrastructure.RESTRouter.IQueue" />
        </service>
    </services>

    <behaviors>
        <endpointBehaviors>
            <behavior name="webHttp">
                <webHttp />
            </behavior>
        </endpointBehaviors>
    </behaviors>

    <bindings>
        <customBinding>
            <binding name="jsonpBinding">
                <jsonpMessageEncoding />
                <httpsTransport
                      manualAddressing="true"
                      authenticationScheme="Ntlm" />
            </binding>
        </customBinding>
    </bindings>

    <extensions>
        <bindingElementExtensions>
            <add name="jsonpMessageEncoding"
              type="IS.Core.Infrastructure.RESTRouter.JsonpBindingExtension, RESTRouter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        </bindingElementExtensions>
    </extensions>

Here is one of the interface method definitions:

    [OperationContract]
    [WebGet(UriTemplate = "{ModelPath}/{ObjectTypeName}?callback={callback}", ResponseFormat = WebMessageFormat.Json)]
    [JSONPBehavior(callback = "callback")]
    JSONPXml NewObject(string ModelPath, string ObjectTypeName, string callback);

Here is its implementation:

    [OperationBehavior(Impersonation = ImpersonationOption.Allowed)]
    public JSONPXml NewObject(string ModelPath, string ObjectTypeName, string callback) {

        int val = getEmployeeIdByNTUsername(OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name);

        JSONPXml jsp = null;
        EntityPluginReflectorClient client = null;
        try {
            client = new EntityPluginReflectorClient();
            string output = client.NewObject(ModelPath, ObjectTypeName);
            jsp = new JSONPXml() { xml = output };
        } catch (Exception e) {
            InfrastructureLog.WriteException(this, "NewObject", e);
            jsp = getExceptionResponse(e);
        }
        finally {
            client.Close();
        }
        return (jsp);
    }

and here is the data contract:

[DataContract()]
public class JSONPXml {
    public JSONPXml() { }
    [DataMember]
    public string xml;
}

Please let me know if more information is needed and thanks for looking into this.

A: 

This may seem like an obvious one, but have you checked that you are still passing the "callback" query param in you development server?

Looking at the JSONPEncoder source it seems it will still write a JSON message to the response, even when the "callback" parameter has not been received. It will just not format the JavaScript method wrapper.

Matthew Pelser
Thanks, after your comment I did double check and the callback query param is present in both environments. One thing to note is that on my local system when I change the config from httpTransport to HttpsTransport the output becomes regular json.
Tony
Strange. You said you included the classes from the sample. If you put a breakpoint in both WriteMessage methods of the JSONPEncoderFactory are any of them hit when you make the call?
Matthew Pelser
+1  A: 

I'm not 100% sure of the answer, but here are a few things to help you narrow it down:

For starters, if you set the ProtectionLevel explicitly to either Sign or EncryptAndSign, then you must use a binding with security enabled or an exception will be thrown. That will start throwing exceptions if you try accessing it via http, which can help you figure out how you are actually accessing the service.

Secondly, since you are using a customBinding, you'll need to tell it what type of security you want in the binding. I don't think it's enough to just specify httpsTransport. The way you do that is through the security tag. From the sound of it you will need to set authenticationMode="SspiNegotiated".

According to the custom binding docs

The order in which elements appear in the stack matters, because it is the order in which operations are applied to the message. The recommended order of stack elements is the following:

Transactions (optional)

Reliable Messaging (optional)

Security (optional)

Transport

Encoder (optional)

More info on Custom Binding Security here and here Hopefully that helps.

slf