Why is my admin not able to act as a delegate? How can I check whether delegation is even setup? These are great questions and it occurred to me after I spent some time searching that no one has ever bothered to explain exactly how delegation works. With that in mind I present the following – which some may find useful when debugging while others simply find it interesting to know.
While this may not be completely obvious, delegation is a presence feature whose configuration is well documented in MS-PRES. This covers in gory details how to add, change, and remove a delegate. What it does not cover at all is how the delegate and delegator learn of the relationship and how this information is stored.
No delegation configured
So let’s start at the very beginning with two users – Boss and Admin – who do not have a delegation relationship setup. We are about to configure this, but before we do we need to examine sign in for both users. During sign in both users will self subscribe using a message similar to the following (note that some headers have been removed for brevity).
SUBSCRIBE sip:email@example.com SIP/2.0Via: SIP/2.0/TLS 192.168.0.240:52386From: <sip:firstname.lastname@example.org>;tag=bd94be2ff5;epid=fc44a406d8To: <sip:email@example.com>Call-ID: 0423f26f9e6c40db8dda82276cbddd9dCSeq: 1 SUBSCRIBEContact: <sip:firstname.lastname@example.org;opaque=user:epid:zov38nE9AlKRNqjgsU-A_AAA;gruu>Event: vnd-microsoft-roaming-selfAccept: application/vnd-microsoft-roaming-self+xmlSupported: com.microsoft.autoextendSupported: ms-benotifySupported: ms-piggyback-first-notifyContent-Type: application/vnd-microsoft-roaming-self+xml- <roamingList xmlns="http://schemas.microsoft.com/2006/09/sip/roaming-self"> <roaming type="categories"/> <roaming type="containers"/> <roaming type="subscribers"/> <roamingEx xmlns="http://schemas.microsoft.com/2007/09/sip/roaming-self-ex" type="delegates"/> </roamingList>
The two that we care about are the subscribers and delegates categories. As we will see shortly, these will be key to understanding delegation. Before we setup delegation, however, let’s have boss add admin as a contact and see what happens. We’ll skip the details of adding a contact though and instead concentrate on the prompted subscriber – that prompt that tells admin that boss added her as a contact. How does she receive this notification – through the subscribers category subscription of course.
NOTIFY sip:192.168.0.240:52807;transport=tls;ms-opaque=a589590cd5;ms-received-cid=1ABE500;grid SIP/2.0To: <sip:email@example.com>;tag=de5be0b9f5;epid=fc44a406d8Content-Length: 636From: <sip:firstname.lastname@example.org>;tag=79520080Call-ID: 904acbdc96704c16afe7206e92e7fd09CSeq: 4 NOTIFYRequire: eventlistContent-Type: application/vnd-microsoft-roaming-self+xmlEvent: vnd-microsoft-roaming-selfSupported: ms-dialog-route-set-update
- <roamingData xmlns="http://schemas.microsoft.com/2006/09/sip/roaming-self" sub="http://schemas.microsoft.com/2006/09/sip/presence-subscribers"> - <subscribers xmlns="http://schemas.microsoft.com/2006/09/sip/presence-subscribers"> + <subscriber user="email@example.com" displayName="MrBoss Bosso" acknowledged="false" type="sameEnterprise"> - </subscribers>
Let’s not acknowledge it just yet, but instead take a look at what we have in the database. You’ll need to look at the database for admin’s FE, which if you do not know where it is located you can find with
Get-CsUserPoolInfo firstname.lastname@example.org | select-object PrimaryPoolPrimaryRegistrar
Now at the database the following will provide the prompted subscriber list.
select r1.UserAtHost as Publisher, r2.UserAtHost as Subscriber, p.Permanent, p.AuthMask, p.Ackd, convert(varchar(4000), convert(varbinary(4000), p.Context)) as Context
from rtc.dbo.PromptedSubscriber as p
inner join dbo.Resource as r1
on r1.ResourceId = p.PublisherId
inner join rtc.dbo.Resource as r2
on r2.ResourceId = p.SubscriberId
where r1.UserAtHost = 'email@example.com'
Notice that Ack’d is 0, but what is more interesting is the Context.
<subscriptionContext xmlns="http://schemas.microsoft.com/2008/09/sip/SubscriptionContext" majorVersion="1" minorVersion="0">
This is not overly interesting, but play along for now. No ack the prompted subscriber message and query the table again. Since the prompted subscriber is ack’d, we have removed the row from the database.
Now let’s add admin as a delegate for boss. The following message from boss sets up the delegation.
06/16/2014|15:44:25.561 F30:64C INFO :: SERVICE sip:firstname.lastname@example.org SIP/2.0From: <sip:email@example.com>;tag=d24448c9c5;epid=18dfefe32cTo: <sip:firstname.lastname@example.org>Call-ID: bb1ff151b5364659a7c0dad4dcdc85c8CSeq: 1 SERVICEContact: <sip:email@example.com;opaque=user:epid:MRVYui97X1WRenSBv44FiwAA;gruu>Content-Type: application/msrtc-setdelegate+xml- <setDelegates xmlns="http://schemas.microsoft.com/2007/09/sip/delegate-management" version="7"> <delegate uri="sip:firstname.lastname@example.org" action="add"/> </setDelegates>
Boss will then see the following NOTIFY, telling her that the delegation has been configured. Note that this time it was sent back in the 200 OK response instead of in a separate NOTIFY. This happened because we indicated support for best effort NOTIFY (BENOTIFY) in the supported: ms-benotify header when we setup the subscription.
SIP/2.0 200 OKFrom: "MrBoss Bosso"<sip:email@example.com>;tag=d24448c9c5;epid=18dfefe32cTo: <sip:firstname.lastname@example.org>;tag=91831FC8D1A4176B2C748B9E0BB2DA10Call-ID: bb1ff151b5364659a7c0dad4dcdc85c8CSeq: 1 SERVICEContent-Type: application/vnd-microsoft-roaming-self+xml
- <roamingData xmlns="http://schemas.microsoft.com/2006/09/sip/roaming-self" del="http://schemas.microsoft.com/2007/09/sip/delegates"> - <delegates xmlns="http://schemas.microsoft.com/2007/09/sip/delegates" version="8"> <delegate uri="email@example.com" publish="false" redelegate="false"/> - </delegates>
We can see that the delegation has been configured by examining the Delegate table on admin’s front end.
select r1.UserAtHost as Delegator, r2.UserAtHost as Delegate, d.AuthMask from rtc.dbo.Delegate as d
on r1.ResourceId = d.DelegatorId
inner join dbo.Resource as r2
on r2.ResourceId = d.DelegateId
where r1.UserAtHost = 'firstname.lastname@example.org'
What is important to note here about delegation is this is the final source of information about delegation. In various cases when the server needs to know if a delegate relation exists, it will send a message to boss’s front end, which will in turn lookup the relationship in this table. Only the delegate table on the boss’s front end matters – not the table on the admin’s front end.
Now comes the disclaimer – you may actually see these rows in other front ends because they are automatically replicated to the backup front ends. Therefore you may see the rows on admin’s FE if that FE is a backup for boss’s.
Now the question will naturally arise – how does admin learn that she is a delegate for boss? A quick examination of the delegate table on her FE will bring up nothing – so how is this stored and sent. The answer is related to the prompted subscriber notification sent earlier. A prompted subscriber message is sent to admin with one key difference.
NOTIFY sip:192.168.0.240:52807;transport=tls;ms-opaque=a589590cd5;ms-received-cid=1ABE500;grid SIP/2.0To: <sip:email@example.com>;tag=de5be0b9f5;epid=fc44a406d8From: <sip:firstname.lastname@example.org>;tag=79520080Call-ID: 904acbdc96704c16afe7206e92e7fd09CSeq: 8 NOTIFYRequire: eventlistContent-Type: application/vnd-microsoft-roaming-self+xmlEvent: vnd-microsoft-roaming-selfSupported: ms-dialog-route-set-update
- <roamingData xmlns="http://schemas.microsoft.com/2006/09/sip/roaming-self" sub="http://schemas.microsoft.com/2006/09/sip/presence-subscribers"> - <subscribers xmlns="http://schemas.microsoft.com/2006/09/sip/presence-subscribers"> - <subscriber user="email@example.com" displayName="MrBoss Bosso" acknowledged="false" type="sameEnterprise"> - <context> - <subscriptionContext xmlns="http://schemas.microsoft.com/2008/09/sip/SubscriptionContext" majorVersion="1" minorVersion="0"> - <watcher> <contactList/> - </watcher> <delegation/> - </subscriptionContext> - </context> - </subscriber> - </subscribers>
That little node called “delegation” is the key. You can see this context also if querying the PromptedSubscriber table. This element informs the client that this is no normal prompted subscriber but instead a delegation configuration. Admin now knows that she is a delegate for boss.
Unlike an actual prompted subscriber, however, the client never acknowledges it and the entry remains in admin’s prompted subscriber table until the relationship is removed. From the server’s perspective, this is simply an unacknowledged prompted subscriber and each time admin signs and self subscribes to her subscribers the server will respond with this one.
So, now both admin and boss are aware of the delegation relationship. Boss will continue to see the relationship returned in the delegates category subscription each time she signs in and admin will continue to see the relationship in the subscribers category subscription with a context that contains the delegation element each time she signs in. The Delegate table on boss’s front end will remain the master arbiter of delegate decisions until boss is moved to another machine or a failover occurs.