Identity Manipulation in UCMA-getting Impersonation to work through a mediation server

There’s a UCMA method on the Microsoft.RTC.Collaboration.Conversation class called Impersonate that lets you place an outbound call as if you were a different user.  You provide the method with a SIP URI, phone URI, and Display Name, and usually it works as expected, but there are some cases where things can fall apart pretty spectacularly if you’re not careful. 

First, let’s look at the case where things work as expected.  Say I want to create a UCMA app that accepts a call from user A (sip:cb@rnddev.computer-talk.com), does something, and then makes an outbound call to user B (sip:cbardon@rnddev.computer-talk.com).  Normally, I’d get something like this when I placed the outbound call:

image

Which is the identity of my application.  When I create my outbound call though, I could do something like this with the conversation:

conversation.Impersonate(“sip:cb@rnddev.computer-talk.com”,null,”cb”);

And then when I establish my call, the inbound call to User B would appear to be from User A, and not your app

image

If all the calls are between Lync endpoints, then everything is fine here.  What if you involve a mediation server or the PSTN though?  First, consider the case where you get an inbound call from the PSTN to your app, and then try to impersonate that caller like this:

conversation.Impersonate(“sip:+19058825000;ext=3154@rnddev.computer-talk.com;user=phone”,null,”Chris Bardon”);

You’d get a result like this:

image

Note that the URI parameter MUST be specified, but I left the phoneUri parameter blank.  This is because the uri is a phone URI already, and trying to specify the phoneUri again in this case would throw an exception.  In any case, an inbound call from the PSTN impersonates correctly.  Now, what about the case where I want to initiate a call from a Lync user out to the PSTN like this:

conversation.Impersonate(“sip:cb@rnddev.computer-talk.com;user=phone”,”tel:+19058140048”,”Chris Bardon”);

This case works just fine too (although it’s more difficult to get a screenshot of-you’ll have to trust me on this one). 

So for the last case-what happens if both the inbound and outbound call are through a mediation server?  As it turns out, this case fails rather spectacularly.  If you try something like this:

conversation.Impersonate(“sip:+19058825000;ext=3154@rnddev.computer-talk.com;user=phone”,null,”Chris Bardon”);

And place a call out to a PSTN endpoint, your app will get a 404 that looks like this:

TL_INFO(TF_PROTOCOL) [0]1F00.1B54::07/03/2012-18:58:29.425.019eda5f (SIPStack,SIPAdminLog::TraceProtocolRecord:SIPAdminLog.cpp(125))$$begin_record
Trace-Correlation-Id: 834215393
Instance-Id: 00024EB3
Direction: incoming
Peer: chrislaptop.corp.computer-talk.com:50061
Message-Type: response
Start-Line: SIP/2.0 404 Not Found
From: <sip:chrisice70_1@rnddev.computer-talk.com;gruu;opaque=app:conf:audio-video:id:1CBIIRTU>;tag=1e2d289a90;epid=72D4E27D44
To: “chrisice70_1″<sip:chrislaptop.corp.computer-talk.com@rnddev.computer-talk.com;gruu;opaque=srvr:chrisice70:_m411PC3cFaS4dn7x0olnAAA>;tag=f4a3e8bc9a;epid=E73F01CD8F
CSeq: 2034 INVITE
Call-ID: 722b999c-9af3-4fca-8e66-c9968d31dcd2
VIA: SIP/2.0/TLS 192.168.201.74:57523;branch=z9hG4bKC9BC6AB4.6E7020D901A5DDAF;branched=FALSE,SIP/2.0/TLS 192.168.201.74:58100;branch=z9hG4bK4f5e3f5;ms-received-port=58100;ms-received-cid=437600
CONTENT-LENGTH: 0
PRIORITY: Normal
SUPPORTED: Replaces
P-ASSERTED-IDENTITY: <sip:15de4e29-d190-491b-920a-f46c79f087ec@rnddev.computer-talk.com>
SERVER: RTCC/4.0.0.0 chrisice70
ms-diagnostics: 1003;reason=”User does not exist”;TargetUri=”+4165752695@rnddev.computer-talk.com”;source=”LYNC2010.rnddev.computer-talk.com”
Ms-Conversation-ID: eb54476dad1e4eada19648d1ba329373
Message-Body: –
$$end_record

The key here is the “User does not exist” flag in the ms-diagnostics, although it should be fairly obvious that the user doesn’t exist on Lync, because it’s not a user, it’s a phone number.  Digging into the logs a little more, you could look at the outbound routing log and see something like this (cleaned up for readability):

Creating a OutboundRoutingTransaction object (57)
Enter
From uri: sip:+19058825000;ext=3154@rnddev.computer-talk.com
From User Uc Enabled: False
Referrer URI: <null>
IsAvMCUDialOut: False
Alternate Tel URI: <null>
IsEmergencyCall = False
Checking for Vacant Number range. Request URI = +4165752695
Checking for Vacant number entries for +4165752695
No matching range found.
No matching Vacant Number Range found.
+4165752695 does not match any Vacant Number range
Checking for CPS range. Request URI = +4165752695
Checking for CPS entry for +4165752695
Input prefix [+] does not match that of range [ ]
No matching range found.
No matching range found
+4165752695 does not match any CPS range
Applying From URI’s outbound policy
Routing request based on caller: sip:+19058825000;ext=3154@rnddev.computer-talk.com
Caller not UC enabled.
Stamping request from non UC enabled user and sending request on its way…
Exit

Basically, this is the outbound routing engine deciding how to route the call to +4165752695.  It determines that the from URI isn’t a UC enabled user, decides that the call doesn’t fall under the unassigned number range, and that it’s not a call park orbit.  It then decides to route the call based on the from user’s policy, which, since the from user isn’t a UC enabled user, is nothing. 

This actually falls under a case that’s documented on NextHop with respect to meeting joins, and the solution that they mention, creating static routes, might very well work.  I wasn’t able to get it working that way, and I managed to find a better alternative.  I did like Mike Stacy’s Post on creating static routes though, but in this case, circumventing all the normalization and routing rules seemed wrong, and like something that’d be difficult to get customers for this app to do.

The key to the solution was the “IsAvMCUDialOut” line-if an MCU dial out worked, then there must be a way to route like this, right?  As it turns out, an AVMCU call not only sets this flag, but also the “ReferrerURI” flag, which translates into the Referred-by header.  Simple enough then, I just added this to my outbound call establish:

outboundCallLegSettings.CallEstablishOptions.Headers.Add(new SignalingHeader(“REFERRED-BY”, “<sip:cb@rnddev.computer-talk.com>”));

Which also proceeded to fail.  As it turns out, Lync expects the referred-by header to be signed, so that it looks something like this:

REFERRED-BY: <sip:cbardon@rnddev.computer-talk.com>;ms-identity=”MIIBxQYJKoZIhvcNAQcCoIIBtjCCAbICAQExCzAJBgUrDgMCGgUAMAs GCSqGSIb3DQEHATGCAZEwggGNAgEBMGowXDETMBEGCgmSJomT8ixkARkW A2NvbTEdMBsGCgmSJomT8ixkARkWDWNvbXB1dGVyLXRhbGsxFjAUBgoJkiaJk/I sZAEZFgZybmRkZXYxDjAMBgNVBAMTBXJuZENBAgodMhniAAAAAAC0MAkGBSs OAwIaBQAwDQYJKoZIhvcNAQEBBQAEggEAKu4exuDavlYfjaJVJqu43mAZ+IK5My XKMkXAZoVm9dT8SS5col2meENQtdVhWRvcb7jGhbLAjpggPpvfQ2CD6CbkScwj5H5 jgcxX9tA4iIT4a3QiMSZA/A7tfVPJ9ipexBro/18eHEur2gpxY82QhNFXgcAzeofFTP+QB REIopLqWqgFlVccZcoUP6sC02L4qbxb1gzouyO+2lEUf+IVCdATMlBleWxQht7l6Dgc9Y 0xEutsWPg8a9ym5Q19rWb14OHUVxmCgFHJ6y56R3/aSUceQ844j/fhCRDctTa4zs6L/ GN5+H7z60vLUuME1utyiJOpXaZ1PB38mkig6KyCIA==:Tue, 03 Jul 2012 18:58:23 GMT”;ms-identity-info=”sip:LYNC2010.rnddev.computer-talk.com:5063;transport=Tls”;ms-identity-alg=rsa-sha1

Instead of this (which is what my message looked like):

REFERRED-BY: <sip:cbardon@rnddev.computer-talk.com>;

Now, there’s no documentation on how this hash is generated that I could find, so I tried some other solutions:

  • Setting P-Asserted-Identity directly?  Nope, Lync won’t let you modify a header after it’s been set.
  • Modifying P-Asserted-Identity in an MSPL script (actually an MSPL managed code app)?  This would work, but took a lot of work to set up.
  • Setting P-Preferred-Identity?  Had no effect…
  • Setting P-Session-On-Behalf-Of (which I stole from a delegate invite)?  Nope, no good.
  • Setting the Remote-Party-ID header?  Still nothing…
  • Mashing in Referred-By manually with a captured signature?  Strangely enough, this worked, but was in no way a manageable solution

Finally, I was looking through the CallEstablishOptions class again, and came across a property called Transferor.  I set it like this:

outboundCallLegSettings.CallEstablishOptions.Transferor = “sip:chrisice70_1@rnddev.computer-talk.com”

And the PSTN call went through with the correct caller ID.  I tried a Lync endpoint again and got a toast window that looked like this:

image

Which had the correct information on it as well.  Now, if only this had been a little more obvious in the documentation (say, when I searched the UCMA docs for Referred-By)…

So, to summarize, if you want to impersonate a mediation server endpoint back to a mediation server, you not only have to impersonate the caller, but you have to set the Transferor property on the CallEstablishOptions to make sure that the call is routed.  I’ve chosen to set this property in all cases, since it simplifies the code, but if you wanted to only set it in certain cases you would certainly have the option.  Keep in mind though, telling how a call is going to be routed from within your UCMA application can be tricky, and is subject to change based on the server configuration.  Also, using the Lync Server Logging Tool and Snooper is a great way to trace what’s going on with the server.  I never would have figured this out had I not compared my failed trace to a successful conference dial out trace and noticed the referrer information. 

Has anyone else run into the same problem, or encountered a case where this doesn’t solve their problem?  Leave a comment or drop me an email if you have.

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

3 Responses to Identity Manipulation in UCMA-getting Impersonation to work through a mediation server

  1. Pingback: UCMA patches are important, even if the descriptions are vague | Chris Bardon

  2. Avennite says:

    I’ve given multiple tries to this an non of this works. Non impersonated phone calls using the application endpoint work over PSTN however if i try to impersonate i get a 400. Any advice?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s