One-Way Audio with AudioCodes and Encrypted Lync Media

This is a quick one: If you're using media encryption with the latest MSBG 1000 firmware posted to the AudioCodes website, you might find yourself experiencing issues with one-way audio. Specifically, Lync users are periodically unable to hear PSTN callers. The issue is sporadic, and may appear or disappear as the call continues, although a hold/resume tends to fix it temporarily.

After doing some packet captures you will see a bi-directional RTP stream between the gateway and Mediation server, but the Mediation server does not actually pass any RTP packets to the Lync endpoint side because it is unable to decrypt the media.

This is a known issue in the 6.40A.037.009 firmware and can be resolved by upgrading to version 6.40A.059. You'll have to call in to support to retrieve the newer firmware since the one with the issue is the latest posted to the AudioCodes website (and unfortunately very dated, seeing as it was released in May of 2012.) Happy upgrading.

Lync 2013 MCU and Old Conference Directories

After installing a Lync Server 2013 pool and moving users over, you might find they are unable to create new conferences if they are enabled for PSTN dial-in conferencing. When running a SIPStack trace you’ll find the following error during creation of the conference:

Start-Line: SIP/2.0 500 failedLookupForConferenceDirectoryOwner
ms-diagnostics: 3193;reason="Could not find a front end server that owns the given pstn meetind id."

Which might lead you to notice that Front-End is logging error Event 51048, LS MCU Factory:

McuFactory could not find the pool associated with one of the conference directories.
Failed to read pool FQDN associated with conference directory 20.

Cause: The pool associated with the conference directory does not exist anymore.
Resolution: Conference directories without a valid pool associated can be deleted using management tools.

The issue seems to be that if orphan conference directories exist, they may prevent new conferences for 2013 users. You can check for orphan directories via:

Get-CsConferenceDirectory | FT Identity,ServiceID

Review the output and check to see if there is a ServiceID matching a pool which no longer exists. BackCompatSite entries refer to OCS 2007 R2 servers added during a merge operation.

If a Service ID exists for a pool that has been deleted the conference directory cannot be moved at this point, but you can use the following command to forcefully remove it:

Remove-CsConferenceDirectory <Identity Number> –Force

Take care to make sure you’re deleting the correct identity. Removing an active conference directory will force users to reschedule meetings.

ADFS & RelayState

Active Directory Federation Services (ADFS) has been around for some time now, and many organizations use it to provide single sign-on capabilities to Office 365 without giving it a second glance, but ADFS is really a generic identity provider that can work with other Security Assertion Markup Language (SAML) 2.0 endpoints. The incredibly over-simplified gist of SAML is that some identity provider (ADFS + Active Directory) authenticates a user, hands them a token, and the user takes that token to log in to other web applications such as Office 365, Salesforce, Workday, Jobvite, or any SAML 2.0 compliant service. The benefit here is organizations have a single point of authentication in ADFS, but can use those credentials to access multiple services that they don’t necessarily host or deploy.

Often times these services will email a user with a hyperlink embedded in the message that links to a specific page or “deep link” on the service. If a user clicks on that link, it should take them directly to the referenced opportunity or page. The issue with the initial release of ADFS was that this feature did not work. The users could click one of these links and get logged in to the service, but they would always end up on the home or main page – not the link they clicked on. The reason for this is that ADFS did not support the RelayState parameter, which actually contains that end state or desired URL after login occurs. Update Rollup 2 for ADFS adds this functionality and can be downloaded from here: http://support.microsoft.com/kb/2681584 .

However, this does not mean that RelayState will begin working automagically. There are some requirements about how the URL is formatted in order for ADFS to properly consume the RelayState and send the user to the link after authentication. Those guidelines are laid out here, and includes the fact that part of it must already be URL encoded: http://technet.microsoft.com/en-us/library/jj127245(v=ws.10).aspx

So the options are to have the service provider deliver deep links in the format ADFS requires (unlikely to happen), or modify the links to the correct format. Fortunately, we can use the IIS URL Rewrite Module to match and manipulate patterns based on regular expressions (your Lync voice administrators should be very familiar with this concept.) Install the URL Rewrite module on your ADFS servers from here: http://www.iis.net/downloads/microsoft/url-rewrite

Let’s work through an example that uses the Jobvite service. I apologize for the color barf throughout the rest of the post, but I hope it highlights how everything lines up. A deep link that a user receives in an email from Jobvite resembles the following format:

https://www.jobvite.com/m/default.aspx?3EGNofwx

When a user clicks that link, Jobvite knows the tenant is enabled for SSO, and provides a redirect URL to the browser where the user should authenticate. It’s the equivalent of saying “I don’t authenticate you, but this URL (ADFS) can. Come back when you have a token that says you’ve authenticated.” In Jobvite’s case, that URL includes an identifier for ADFS to match a relying party trust (found in the loginToRp parameter), and two RelayState parameters – RelayState and Target. The values in RelayState and Target are identical, so I can only assume Jobvite is hoping the SSO provider will consume one of these. Unfortunately, ADFS doesn’t like either! This is the URL a user is redirected to by Jobvite:

https://sso.confusedamused.com/adfs/ls/idpinitiatedsignon.aspx?loginToRp=http://jobvite.com/saml&RelayState=/m/default.aspx?3EGNofwx&target=/m/default.aspx?3EGNofwx

Now the user’s browser flips to the ADFS link and logs in. Afterwards, the user is dumped back in to the main Jobvite page because the RelayState parameter didn’t match ADFS’s expected format. There are no errors, and a user is now logged in to Jobvite, but they didn’t end up on the URL they clicked in the email. It’s more of an annoyance than a major issue, but it can be fixed. The format ADFS wants to see looks like this and the part in italics must be URL encoded.

https://sso.confusedamused.com/adfs/ls/idpinitiatedsignon.aspx?RelayState=RPID=[Relying Party ID]&RelayState=[Relay State]

Covering how regular expressions or the rewrite module works is outside the scope of this article, but to be quick:

1. We match a specific URL and pattern received by the IIS server.

2. We then “rewrite” or modify that URL before it is actually processed and delivered to the ADFS application.

Start by opening the URL Rewrite module and click “Add Rule(s).” Select “Blank rule” and click OK.

First we need to set a match URL. The URL is in this window is really just the FQDN part of the URL, so in this example it would be sso.confusedamused.com. I’ve simply entered .* as the match URL pattern to allow any FQDN that points to this server to be accepted. I could use DNS to reach this server via sso.confusedamused.com, adfs.confusedamused.com, yourmomgoestocollege.confusedamused.com, or anything else and it would still match.

image

Next, we need a pattern to match. Expand the Conditions section and press “Add". The condition input we’ll check is the {REQUEST_URI}, which refers to everything after the FQDN we just checked. The pattern we’ll use looks like this.

^(.*)/adfs/ls/idpinitiatedsignon.aspx\?loginToRp=(.*)&RelayState=(.*)&(.*)$

image

In English, the pattern means “Must start with”, “any string” (that’s the .* part), followed by the exact text “/adfs/ls/idpinitiatedsignon.aspx\?” (we have to escape the “?” with a “\”), followed by loginToRp=”, capture the next “any string” (because this one is in parentheses it means we’re capturing this data to re-use in the rewrite later), followed by the exact string “&RelayState=”, capture the next string, followed by the exact string “&”, capture the next string, and finally, “must end with”. Technically, we don’t need to capture that last string because it just contains the target=/m/default.aspx?3EGNofwx part, which we already know is identical to the RelayState parameter passed right before it. But you get the idea.

For reference, here is the URL again that matches the above pattern. The colors should line up.

https://sso.confusedamused.com/adfs/ls/idpinitiatedsignon.aspx?loginToRp=http://jobvite.com/saml&RelayState=/m/default.aspx?3EGNofwx&target=/m/default.aspx?3EGNofwx

In the Action section the type we’ll select is rewrite. Remember how we “captured” some parts of text in the pattern previously? Those line up to variables that we can now reuse and reference in the rewrite pattern in the format {C:[Variable Number]}. So we have {C:1} that matches the first string we captured, and {C:2} matches the second one, etc. {C:1} actually refers to the very beginning of our pattern (the first (.*)), so the text we’re interested in starts at {C:2} which is the Relying Party ID, and includes {C:3}, our RelayState link. 

Just to refresh, the end-state we need to get to is this, and we have to URL encode everything after the first RelayState=:

https://sso.confusedamused.com/adfs/ls/idpinitiatedsignon.aspx?RelayState=RPID=[Relying Party ID]&RelayState=[Relay State]  

The URL Rewrite module actually includes a function to URL Encode a section of text so the rewrite to use will look like this:

adfs/ls/idpinitiatedsignon.aspx?RelayState={UrlEncode:RPID={C:2}&RelayState={C:3}}

image 

After that, simply select “Stop processing of subsequent rules” and uncheck the box “Append query string.” The end result is that the original link returned by Jobvite that ADFS doesn’t recognize…

https://sso.confusedamused.com/adfs/ls/idpinitiatedsignon.aspx?loginToRp=http://jobvite.com/saml&RelayState=/m/default.aspx?3EGNofwx&target=/m/default.aspx?3EGNofwx 

… will be transformed into this URL before it hits ADFS. The user experience is now that a deep link works as expected. A user that is not logged in to Jobvite can click a URL from an email, be seamlessly authenticated via ADFS, and end up on the URL they clicked on.

https://sso.confusedamused.com/adfs/ls/idpinitiatedsignon.aspx?RelayState=RPID%3Dhttp%3A%2F%2Fjobvite.com%2Fsaml%26RelayState%3D%2Fm%2Fdefault.aspx%3F3EGNofwx

To recap – the process goes:

1. User clicks link in email: https://www.jobvite.com/m/default.aspx?3EGNofwx

2. Jobvite redirects user to this link: https://sso.confusedamused.com/adfs/ls/idpinitiatedsignon.aspx?loginToRp=http://jobvite.com/saml&RelayState=/m/default.aspx?3EGNofwx&target=/m/default.aspx?3EGNofwx

3. URL Rewrite module matches the redirect link pattern and modifies the link to the following before delivering to ADFS: https://sso.confusedamused.com/adfs/ls/idpinitiatedsignon.aspx?RelayState=RPID%3Dhttp%3A%2F%2Fjobvite.com%2Fsaml%26RelayState%3D%2Fm%2Fdefault.aspx%3F3EGNofwx

You can create as many rewrite rules as necessary in case different service providers each send unique formats with the RelayState parameter.