none
Service Bus Security 101

    Question

  • OK, service bus is really nifty but the security story is driving me bonkers. Can anyone provide a document/sample that illustrates an end-to-end example of how SB security is supposed to work? Is there a simply way to just say "allow all/anonymous connections"? I really just want to get my design up-and-running without being bothered by all of the ceremony security demands. On the other hand, if that is not possible,

    1. How can I connect to a queue from outside of the domain in which the service bus is hosted?

    2. How can I connect to a queue from within the same domain but under the IIS identity or the identity of a generic service account?

    I cannot get my security problems to go away; the only way I've been able to connect to the service bus is to run under the same account as the queue owner....

    Thanks.

    Tuesday, November 6, 2012 2:32 PM

All replies

  • Here is an example of how to use anonymous authentication.

    string namespaceName = "UserNamespace"; string stsUri = string.Format("sb://{0}.{1}:9355/", Environment.MachineName, Environment.GetEnvironmentVariable("USERDNSDOMAIN")); string namespaceUri = string.Format("https://{0}.{1}:9355/{2}/", Environment.MachineName, Environment.GetEnvironmentVariable("USERDNSDOMAIN"), namespaceName); string messagingUri = string.Format("sb://{0}.{1}/{2}/", Environment.MachineName, Environment.GetEnvironmentVariable("USERDNSDOMAIN"), namespaceName); TokenProvider tokenProvider = TokenProvider.CreateWindowsTokenProvider(new List<Uri>() { new Uri(stsUri) }); NamespaceManager namespaceManager = new NamespaceManager(namespaceUri, tokenProvider); QueueDescription myQueue = new QueueDescription("MyAnonymousQueue") { IsAnonymousAccessible = true }; if (namespaceManager.QueueExists(myQueue.Path)) { namespaceManager.DeleteQueue(myQueue.Path); } namespaceManager.CreateQueue(myQueue);

    // To send/receive messages anonymously, do not specify the token provider when creating messaging factory

    MessagingFactory factory = MessagingFactory.Create(messagingUri); MessageSender sender = factory.CreateMessageSender(myQueue.Path); sender.Send(new BrokeredMessage() { MessageId = "001" }); MessageReceiver receiver = factory.CreateMessageReceiver(myQueue.Path); BrokeredMessage receivedMessage = receiver.Receive(TimeSpan.FromSeconds(15)); Console.WriteLine(receivedMessage.MessageId);


    • Edited by Loc Phan Tuesday, November 6, 2012 9:27 PM
    Tuesday, November 6, 2012 8:10 PM
  • 1. How can I connect to a queue from outside of the domain in which the service bus is hosted?

    It does require a little work to have a client outside of the domain talking to serviceBus.  There are 3 things you have to do:

    a)  Make ServiceBus endpoint visible to the client.  Client might not be able to talk to SB endpoint due to firewall issue.

    b) Need to set up SB certificate on a client machine.  Even in the case of using anonymous access, SSL validation still happens when client connects to ServiceBus.

    c) You must use OAuth authentication.

    Example:

    NetworkCredential credential = new NetworkCredential("username", "password", "domainName"); // This user should be part of the domain where serviceBus is running.

    TokenProvider tokenProvider = TokenProvider.CreateOAuthTokenProvider(stsAddresses, credential);

    2. How can I connect to a queue from within the same domain but under the IIS identity or the identity of a generic service account?  You can add the account as one of the manageUsers of your namespace (e.g: Set-SBNamespace -Name myNamespace -ManageUsers iis_iusrs,johnDoe@contoso).  You can also allow the user access at a queue level when creating the queue.  For instance: myQueue.Authorization.Add(new AllowRule("issuerName", "nameidentifier", "iis_iusrs", new List<AccessRights>() { AccessRights.Listen, AccessRights.Send } ));

    Hope this helps.



    Loc Phan

    Tuesday, November 6, 2012 10:13 PM
  • Thanks for the tips but I still cannot conect to a service bus hosted in a VM on a domain and my host which is not on any domain.

    1. Service bus ports 9355 and 9354 are not being blocked by the firewall

    2. I have exported security certificate from server and imported on client

    3. Here is the code I am using:

    var connBuilder = new ServiceBusConnectionStringBuilder();
    connBuilder.ManagementPort = HttpPort;
    connBuilder.RuntimePort = TcpPort;
    connBuilder.Endpoints.Add(new UriBuilder() 
    { 
    	Scheme = "sb", 
    	Host = ServerFQDN, 
    	Path = ServiceNamespace 
    }.Uri);
    connBuilder.StsEndpoints.Add(new UriBuilder() 
    {
    	Scheme = "http", 
    	Host = ServerFQDN, 
    	Port = HttpPort, 
    	Path = ServiceNamespace 
    }.Uri);
    
    var sts = connBuilder.GetAbsoluteManagementEndpoints();
    var credential = new NetworkCredential(Username, Password, Domain);
    var tp = TokenProvider.CreateOAuthTokenProvider(sts, credential);
    var nsManager = new NamespaceManager(
    connBuilder.GetAbsoluteManagementEndpoints(), tp);
    var queues = nsManager.GetQueues();
    

    4. And Here is the error I get when I hit the GetQueues() method:

    The token provider was unable to provide a security token while

    accessing 'https://MYSERVER:9355/MYNAMESPACE/$STS/OAuth/'.

    Token provider returned message:

    'The underlying connection was closed: Could not establish trust

    relationship for the SSL/TLS secure channel.'.


    Wednesday, November 7, 2012 12:19 AM
  •  

    Hi Stephen,

    Could you try using the full domain name of the machine when building your URIs, instead of just Environment.HostName?

    In your current example the connection cannot be trusted because the client is connecting to MYSERVER, but the reply is coming from MYSERVER.MYDOMAIN (since this is the subject name of the default auto-generated certificate). This  breaks the SSL/TLS chain of trust, which expects host names to match exactly.

    Hope it helps!


    Ramiro Berrelleza

    Wednesday, November 7, 2012 12:34 AM
  • 
    
    
    
    
    
    
    

    >Could you try using the full domain name of the machine when building your URIs, instead of just Environment.HostName?

    Well, unfortunately, that doesn't work either; when I try using MYSERVER.MYDOMAIN I get the following error:

    The token provider was unable to provide a security token while

    accessing 'https://MYSERVER.MYDOMAIN:9355/MYNAMESPACE/$STS/OAuth/'.

    Token provider returned message: 'The remote name could not be resolved:

    'exa007.exaphase.dev''.


    
    

    Normally, I have no problem connecting to the domain in which the servers are hosted, e.g., Remote Desktop, Sql Management Studio, etc. From the command line though, if I ping MYSERVER it works fine and if I ping MYSERVER.MYDOMAIN it times out - which doesn't really make sense to me in the first place - but if PING can't see MYSERVER.MYDOMAIN then I wouldn't really expect SB to either.

    Note also though that with my browser I can navigate to https://MYSERVER:9355/MYNAMESPACE just fine...

    

    Wednesday, November 7, 2012 2:00 AM
  • The token provider  will use the fully qualified domain name to make requests to the STS. If that name is not being resolved,  then the communication won't be able to flow, as you mention in your post.

    To confirm, could you try to do a DNS resolution from the machine where Service Bus is installed? You can call the following from powershell:

    [System.Net.Dns]::GetHostAddresses("myserver.mydomain")

    If the address can't be resolved, then the issue is probably at the DNS or AD layer.


    Ramiro Berrelleza

    Tuesday, November 13, 2012 1:49 AM
  • Thank you for posting this code snippet. I have been fighting to get a service bus client working since yesterday and I stumbled across your post at 6:30am this morning :) 
    Tuesday, November 5, 2013 11:51 AM