AMQP Claim Based Security

Editor
Dec 29, 2014 at 1:29 PM
Hi,
I know that from following discussion http://amqpnetlite.codeplex.com/discussions/549912 the SAS token access isn't available in the AMQP.Net Lite library.

However, I read "AMQP Claim based security" specification (https://t.co/lsvoZqPLRe) and understand that it isn't strictly related to the client implementation but it's related to some messages exchange.
I made one only change in AMQP Net Lite library : it is the implementation of a SaslExternalProfile class (for SASL "EXTERNAL") to be used instead of SaslPlainProfile when I don't specify <keyname>:<key> in the URI.
I'm able to send the SAS token to the "$cbs" endpoint as described in the specification but when I try to send a message to an event hub, I receive the following exception :

Additional information: Unauthorized access. 'Send' claim(s) are required to perform this operation. Resource: 'sb://ppatiernoeventhubs.servicebus.windows.net/ppatiernoeventhub/publishers/device1'.

The application code is the following :
var cbsLink = new SenderLink(session, "cbs-link", "$cbs");
 
var tokenMessage = new Message("SharedAccessSignature sr=sb%3a%2f%2fppatiernoeventhubs.servicebus.windows.net%2fppatiernoeventhub%2fpublishers%2fdevice1&sig=M9ZIEs%2fa9ECe03YKGfk0PUpDN1JwkL%2fOFN%2fRbCUMTcs%3d&se=1419842242&skn=EventSendKeyName");

tokenMessage.ApplicationProperties = new ApplicationProperties();
tokenMessage.ApplicationProperties["operation"] = "put-token";
tokenMessage.ApplicationProperties["Type"] = "amqp:swt";
tokenMessage.ApplicationProperties["name"] = "/ppatiernoeventhub/Publishers/device1";
 
cbsLink.Send(tokenMessage);

var sendLink = new SenderLink(
                session,
                "send-link:" + eventhubname,
                string.Format(CultureInfo.InvariantCulture, "{0}/Publishers/device1", eventhubname));

// construct message
var messageValue = Encoding.UTF8.GetBytes("i am a message.");

// here, AMQP supports 3 types of body, here we use Data.
var message = new Message(new Data() { Binary = messageValue });

sendLink.Send(message);
It seems that $cbs node didn't receive my SAS token or the message isn't well formed.

From specification you gave me, I have a way to get response message from $cbs node but I don't understand it (page. 6).
What's the receive link I need to create ?
I tried to read from the same $cbs node with no results :
var cbsLinkResp = new ReceiverLink(session, "cbs-link-resp", "$cbs");
Message cbs = cbsLinkResp.Receive();
cbsLinkResp.Accept(cbs);
Following the trace messages :

[10:11.835] SEND AMQP 3 1 0 0
[10:11.848] SEND sasl-init(mechanism:EXTERNAL,hostname:ppatiernoeventhubs.servicebus.windows.net)
[10:11.998] RECV AMQP 3 1 0 0
[10:12.215] RECV sasl-mechanisms(sasl-server-mechanisms:[PLAIN,EXTERNAL])
[10:12.470] RECV sasl-outcome(code:0,additional-data:57656C636F6D6521)
[10:12.474] SEND AMQP 0 1.0.0
[10:12.478] SEND (ch=0) open(container-id:4dca51a6-fa92-48ec-b546-64a4e5ceab44,host-name:ppatiernoeventhubs.servicebus.windows.net,max-frame-size:16384,channel-max:3)
[10:12.487] SEND (ch=0) begin(next-outgoing-id:4294967293,incoming-window:2048,outgoing-window:2048,handle-max:7)
[10:12.494] SEND (ch=0) attach(name:cbs-link,handle:0,role:False,source:source(),target:target(address:$cbs),initial-delivery-count:0)
[10:12.639] RECV AMQP 0 1 0 0
[10:12.854] RECV (ch=0) open(container-id:9fdb5adc0b524af2a3d84599510c877f_G2,max-frame-size:16384,channel-max:3,idle-time-out:240000)
[10:12.856] RECV (ch=0) begin(remote-channel:0,next-outgoing-id:1,incoming-window:2048,outgoing-window:2048,handle-max:255)
[10:12.859] RECV (ch=0) attach(name:cbs-link,handle:0,role:True,source:source(),target:target(address:$cbs),max-message-size:18446744073709551615)
[10:12.863] RECV (ch=0) flow(next-in-id:4294967293,in-window:2048,next-out-id:1,out-window:2048,handle:0,delivery-count:0,link-credit:100,available:0,echo:False)
[10:12.871] SEND (ch=0) transfer(handle:0,delivery-id:0,delivery-tag:00000000,message-format:0,settled:False,batchable:True) payload 306
[10:13.039] RECV (ch=0) disposition(role:True,first:0,settled:True,state:accepted())
[10:13.045] SEND (ch=0) attach(name:send-link:ppatiernoeventhub,handle:1,role:False,source:source(),target:target(address:ppatiernoeventhub/Publishers/device1),initial-delivery-count:0)
[10:14.092] RECV (ch=0) attach(name:send-link:ppatiernoeventhub,handle:1,role:True,max-message-size:262144)
[10:14.093] RECV (ch=0) detach(handle:1,closed:True,error:error(condition:amqp:unauthorized-access,description:Unauthorized access. 'Send' claim(s) are required to perform this operation. Resource: 'sb://ppatiernoeventhubs.servicebus.windows.net/ppatiernoeventhub/publishers/device1'. TrackingId:9fdb5adc0b524af2a3d84599510c877f_G2,TimeStamp:12/29/2014 9:00:25 AM))
[10:14.094] SEND (ch=0) detach(handle:1,closed:True)

As you can see attach on $cbs node works fine, I can send message with SAS token and receive the disposition (settled is true and state is accepted). It means that $cbs acquired message but it doesn't mean that the message is well formed of course.

Any ideas ?

Thanks,
Paolo
Coordinator
Jan 6, 2015 at 1:01 AM
I added a sample for using SAS token over the claim based security model. If you change the entity name to the event hub publisher endpoint, it should work.

The CBS spec depends on the global addressing and the management spec for doing request/response with a client side temporary node (for receiving responses). All these specs are in draft stage, so there are quite a few things that are not very clear. The sample should show how to get it work with the current Service Bus implementation.

Let me know if you have any questions.

Thanks,
Xin
Editor
Jan 6, 2015 at 6:46 PM
Hi Xin,
I was very closed to the solution :-)

I didn't understand that I needed to set the "ReplyTo" property to get the response for SAS token sent.
The second problem was the "Type" application property ... I used the "amqp:swt" I found in the documentation not the value you set.

Now it works.

However, I'm wrong or it works only for .Net and not for .Net MF ? I haven't tested yet ...

Thanks,
Paolo.
Editor
Jan 7, 2015 at 8:08 AM
Hi Xin,
as I said ... the CBS can't work on .Net MF due to the use of ConnectionFactory not available in the .Net MF project.
I think that we can simply add the use of SslExternalProfile inside the Connect() method of Connection class at the following source code :
if (this.address.User != null)
            {
                SaslTransport saslTransport = new SaslTransport(tcpTransport);
                saslTransport.Open(this.address.Host, new SaslPlainProfile(this.address.User, this.address.Password));
                transport = saslTransport;
            }
The problem is that with ConnectionFactory you can set to use SASL External with amqpsettings.
In the Connection class we don't have this logic.

Paolo
Coordinator
Jan 8, 2015 at 1:05 AM
I changed the code a little bit so now you should be able to create a Connection with a SaslProfile, in addition to the Address. For sasl external profile, you can simply use SaslProfile.External. It should allow you to implement cbs on NETMF (I haven't tried it so let me know if there are other issues).

Thanks,
Xin
Editor
Jan 9, 2015 at 11:58 AM
Hi Xinchen,

I tried to run ServiceBus.Cbs example on .Net MF. Of course I needed to change some utility classes (for URL encoding, for HMAC, ...) that aren't available on .Net MF and it seems to work fine.
In the weekend (and next week), I'll formalize better my example on .Net MF and write a blog post.
If you want, we can put the article in the "Documentation" section too and add my Net MF example in the project.


Paolo.