Search code examples
wcf-bindingidentityserver2

WS-Trust MEX endpoint in IdentityServer 2 returns HTTP 400 for GET requests


We've customised IdentityServer 2 to provide identity federation capability into Azure AD (for Office 365, etc). This has a WS-Federation endpoint for the passive requester flow and WS-Trust for active clients. The MEX endpoint for WS-Trust should return the WSDL for the WS-Trust SOAP in response to both a POST (as Lync uses) and GET (as Windows 10 sign in uses). Unfortunately, it is returning HTTP 400: ws-trust system.servicemodel.protocolexception "There is a problem with the XML that was received from the network".

As can be seen in the source: https://github.com/IdentityServer/IdentityServer2/blob/master/src/Libraries/Thinktecture.IdentityServer.Protocols/WSTrust/TokenServiceHostFactory.cs

var host = new WSTrustServiceHost(config, baseAddresses);

// add behavior for load balancing support
host.Description.Behaviors.Add(new UseRequestHeadersForMetadataAddressBehavior());

// modify address filter mode for load balancing
var serviceBehavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
serviceBehavior.AddressFilterMode = AddressFilterMode.Any;
serviceBehavior.IncludeExceptionDetailInFaults = true;

An instance of System.ServiceModel.Security.WSTrustServiceHost is being stood up to handle calls to WS-Trust, and handle its metadata. Checking the ServiceMetadataBehavior that is added by default in WSTrustServiceHost ctor, we can see that it does enable metadata for GET over both HTTP and HTTPS. http://referencesource.microsoft.com/#System.ServiceModel/System/ServiceModel/Security/WSTrustServiceHost.cs,8c80389f2532b060,references

So I'm a little confused why https://myhost.com/issue/wstrust/mex returns the metadata when hit with a POST, but returns 400 when you send it a GET. The exception is being thrown in a EnqueueMessageAsyncResult.CompleteParseAndEnqueue() in System.ServiceModel http://referencesource.microsoft.com/#System.ServiceModel/System/ServiceModel/Channels/HttpPipeline.cs,b347567a68ab778c,references

Any help greatly appreciated!


Solution

  • For others stuck in the same place, I have explicitly set the TokenServiceHostFactory to respond to HTTP GET.

    // added for AAD Windows 10 sign in - device requests metadata with GET
    ServiceMetadataBehavior metad = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
    if (metad == null)
        metad = new ServiceMetadataBehavior();
    for (int i = 0; i < baseAddresses.Length; i++)
    {
        // there will be two bindings: one for http and one secure
        switch (baseAddresses[i].Scheme)
        {
            case "http":
                metad.HttpGetEnabled = true;
                metad.HttpGetUrl = new Uri(baseAddresses[i], "/issue/wstrust/mex");
                break;
            case "https":
                metad.HttpsGetEnabled = true;
                metad.HttpsGetUrl = new Uri(baseAddresses[i], "/issue/wstrust/mex");
                break;
        }
    }