locked
"Relay security token is required." RRS feed

  • Question

  • I have a problem getting ACS to work with my Silverlight application. (For simplicity, I’ve used a normal console app to illustrate what I’m trying to do. But I am using basicHttpBinding on the client side.)

    Everything works fine calling a REST service:

    string realm = "https://[ns].servicebus.appfabriclabs.com/RESTService.svc/";       

    WebClient client = new WebClient();

     

    string token = GetTokenFromACS(realm);

    string headerValue = string.Format("WRAP access_token=\"{0}\"", token);

    client.Headers.Add("Authorization", headerValue);

    Stream stream = client.OpenRead(realm+"Customers");

     

    However, when trying to call a regular WCF Service (basicHttpRelayBinding on server side), I get a “Relay security token is required.” exception. I’ve tried adding the header using WebOperationContext:

    Service1Client client = new Service1Client("Cloud");

    using (new OperationContextScope(client.InnerChannel))

    {

        string token = GetTokenFromACS(realm); // Same token as when calling the REST service

        string tokenHeader = string.Format("WRAP access_token=\"{0}\"", token);

        WebOperationContext.Current.OutgoingRequest.Headers.Add("Authorization",tokenHeader);

        string ret = client.GetData(123); // “Relay security token is required” Exception

    }

     

    Trace:

    POST /Service1.svc HTTP/1.1

    Content-Type: text/xml; charset=utf-8

    Authorization: WRAP access_token="net.windows.servicebus.action=Listen%2cSend&http%3a%2f%2fschemas.microsoft.com%2faccesscontrolservice%2f2010%2f07%2fclaims%2fidentityprovider=https%3a%2f%2fbLogical-sb.accesscontrol.appfabriclabs.com%2f&Audience=http%3a%2f%2fblogical.servicebus.appfabriclabs.com%2f&ExpiresOn=1312914390&Issuer=https%3a%2f%2fblogical-sb.accesscontrol.appfabriclabs.com%2f&HMACSHA256=1K7gscu5FxCGWlFLWhHEGj5359jyH%2bW6DFOe8MQNnMM%3d"

     

    I’ve also tried using OperationContext to add the envelope header…

    Service1Client client = new Service1Client("Cloud");

    using (new OperationContextScope(client.InnerChannel))

    {

        string token = GetTokenFromACS(realm); // Same token as when calling the REST service

        string tokenHeader = string.Format("WRAP access_token=\"{0}\"", token);

        OperationContext.Current.OutgoingMessageHeaders.Add(new ACSHeader(tokenHeader));

        string ret = client.GetData(123); // “Relay security token is required” Exception

    }

     

    Trace:

    POST /Service1.svc HTTP/1.1

    Content-Type: text/xml; charset=utf-8

    VsDebuggerCausalityData: uIDPozOWNE8J2a9CrpfKtndoEv8AAAAAfqwOWuc5SkaKtNffqNBLOoINjcIBjNRGkRGb0TvcRtkACQAA

    SOAPAction: "http://tempuri.org/IService1/GetData"

    Host: localhost:8789

    Content-Length: 711

    Expect: 100-continue

    Accept-Encoding: gzip, deflate

    Connection: Keep-Alive

     

    <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Header><Authorization xmlns="http://bLogical.se/ACSHeader"><Key>WRAP access_token="net.windows.servicebus.action=Listen%2cSend&amp;http%3a%2f%2fschemas.microsoft.com%2faccesscontrolservice%2f2010%2f07%2fclaims%2fidentityprovider=https%3a%2f%2fbLogical-sb.accesscontrol.appfabriclabs.com%2f&amp;Audience=http%3a%2f%2fblogical.servicebus.appfabriclabs.com%2f&amp;ExpiresOn=1312915757&amp;Issuer=https%3a%2f%2fblogical-sb.accesscontrol.appfabriclabs.com%2f&amp;HMACSHA256=y3ZuRQwVEVpO2g6lUtYcjwcda6A5eOJi5kmopyjhZdk%3d"</Key></Authorization></s:Header><s:Body><GetData xmlns="http://tempuri.org/"><value>123</value></GetData></s:Body></s:Envelope>

     

    So bottom-line, how do I add a header to the WCF call when I can only using basicHttpBinding? Is it supposed to be in the header of the envelope header? If in the envelope header, what header value and jey should I use?

    Thanks

    //Mikael


    If this answers your question, please use the "Answer" button to say so... Mikael - http://blogical.se/blogs/mikael
    Tuesday, August 9, 2011 6:45 PM

Answers

  • Mikael,

    It looks like you are SOOOO CLOSE! Not too sure where AcsHeader is coming from, but the implementation should look like this.

    After getting the token, store it like so:

     

          _token = HttpUtility.UrlDecode(reader.ReadToEnd().Split('=')[1]).Replace("&wrap_access_token_expires_in"string.Empty);
     
          var bytes = Encoding.UTF8.GetBytes(_token);
          _token = Convert.ToBase64String(bytes);
    

    Then insert as you show above with an AcsHeader implementation that looks exactly like this:

    public class AcsHeader : MessageHeader
    {
      private string _token;
      public AcsHeader(string token)
      {
        _token = token;
      }
      public override string Name
      {
        get { return "RelayAccessToken"; }
      }
     
      public override string Namespace
      {
        get { return "http://schemas.microsoft.com/netservices/2009/05/servicebus/connect"; }
      }
     
      protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
      {
        writer.WriteStartElement("wsse""BinarySecurityToken""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
        writer.WriteAttributeString("wsu""Id""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd",
                                    string.Format("uuid:{0}"Guid.NewGuid().ToString("D")));
        writer.WriteAttributeString("ValueType""http://schemas.xmlsoap.org/ws/2009/11/swt-token-profile-1.0");
        writer.WriteAttributeString("EncodingType""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
        writer.WriteString(_token);
        writer.WriteEndElement();
      }
    }

    Scott Seely
    Thursday, August 11, 2011 3:02 AM