turdus-merula
turdus-merula

Reputation: 8854

How to access the UCWA endpoint for Lync Online (Office 365)?

The UCWA documentation states that UCWA is currently available only to customers who have Lync on-premises.

Nonetheless, if using Lync Connectivity Analyzer against an Office 365 account, it seems that in can connect to the UCWA service: Completed tests for Mobility (UCWA) service. Furthermore, if I inspect the web requests performed by this tool (with Fiddler, for example), I can take the authentication token it obtained (somehow) from Office 365 and use it to make requests against UCWA.

Links:

Upvotes: 4

Views: 2846

Answers (2)

Stephen McDaniel
Stephen McDaniel

Reputation: 2968

It does look like Office 365 exposes at least a decent subset of the UCWA functionality. The Lync Connectivity Analyzer is actually a .NET application so it's not terribly difficult to leverage it directly to do the heavy lifting. It's not quite as nice as using a 'friendly' library but it has worked well for me in my various prototyping. With the code below, I'm able to get the web ticket value and the UCWA base URL (via auto-discovery) and then go to town querying the API. It's not the prettiest code but it works.

Note: You'll need to add references to the managed DLLs in the Lync Connectivity Analyzer. For me, that meant:

  • Credentials.dll
  • LyncConnectivityAnalyzer.Logging.dll
  • LyncConnectivityAnalyzer.Resources.dll
  • LyncWebServices.dll
  • Utilities.dll

You'll also need the unmanaged DLLs (maybe just one but I did both) copied to the same folder as your app (e.g. the \bin\ folder).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Security;
using System.Threading.Tasks;
using LyncConnectivityAnalyzer.Logging;
using Microsoft.LyncServer.WebServices;
using Microsoft.Utilities.Credentials;

namespace SM.CoolStuff
{
    /// <summary>
    /// Helper class for performing auto-discovery and authentication to the Lync/Skype UCWA sevice on Office365
    /// </summary>
    public class SkypeHelper
    {
        private string _webTicket;
        private string _ucwaRootPath;
        private readonly ILyncLogging _logger = new Logger();

        /// <summary>
        /// Initializes the connection/authentication/etc.  Once this method completes, <see cref="_webTicket"/> and <see cref="_ucwaRootPath"/> will
        /// be populated.
        /// </summary>
        private async Task Initialize(string userName, SecureString password)
        {
            //Setup the credential
            var userCreds = new Credentials
            {
                UPN = userName,
                SecurePassword = password,
                credsType = CredInputType.CredDialog,
                URI = userName
            };

            //Perform auto-discovery to get the UCWA path
            //We'll just always allow redirects
            ValidateRedirectRequestDelegate alwaysAllowRedirect = (logger, url, destinationUrl) => true;
            var adm = new AutoDiscoverManager(_logger, "http://lyncdiscover." + userCreds.Domain, userCreds.URI, userCreds, alwaysAllowRedirect);
            await adm.StartDiscoveryJourney();

            //Save the path
            _ucwaRootPath = adm.GetAutoDiscoverAddress().ExternalUcwa;

            //Setup the 'validator' that does all the heavy lifting
            var webServicesValidation = new WebServicesValidation(_logger, _ucwaRootPath, userCreds)
            {
                HttpRequestBody = ApplicationPostBody,
                customHeaders = CustomHeaders,
                getPost = HttpMethod.Post
            };

            //Make a first request that should gracefully fail with 'authorization required'
            await webServicesValidation.CheckURL(_ucwaRootPath, false);

            //Now authorize the request
            await webServicesValidation.TryURLAuth(_ucwaRootPath);

            //Use some ugly reflection to get the ticket value.  There may be a better way but this works
            _webTicket = (string)WebTicketField.GetValue(webServicesValidation);
        }

        /// <summary>
        /// Example usage
        /// </summary>
        public async Task DoSomethingOnSkype()
        {
            //If you already have a SecureString, might as well use that.  Otherwise, convert an 'insecure' string to be 'Secure'
            var secureString = new SecureString();
            "TopSecret".ToList().ForEach(secureString.AppendChar);

            //Do the initialization
            await Initialize("[email protected]", secureString);

            //TODO: Use _webTicket and _host to query something
        }

        private static readonly string ApplicationPostBody =
            string.Concat(
                "<input xmlns=\"http://schemas.microsoft.com/rtc/2012/03/ucwa\"><property name=\"culture\">en-US</property><property name=\"endpointId\">44:D8:84:3C:68:68</property><property name=\"type\">Phone</property><property name=\"userAgent\">",
                //TODO: Your app name here
                "LyncConnectivityAnalyzer", "/",
                //TODO: Your app version here
                "5.0.8308.582",
                " (Windows OS 6.0)</property></input>");

        private static readonly Dictionary<string, string> CustomHeaders = new Dictionary<string, string>
        {
            {"Accept", "application/vnd.microsoft.com.ucwa+xml"},
            {"Content-Type", "application/vnd.microsoft.com.ucwa+xml"},
            {"X-MS-Namespace", "internal"},
            {"Connection", "keep-alive"},
            {"Proxy-Connection", "keep-alive"}
        };

        private static readonly FieldInfo WebTicketField = FindWebTicketField();

        private static FieldInfo FindWebTicketField()
        {
            var fieldInfo = typeof(WebServicesValidation).GetField("_webticket", BindingFlags.Instance | BindingFlags.NonPublic);
            if (fieldInfo == null)
            {
                throw new ApplicationException("Could not find private _webticket field");
            }
            return fieldInfo;
        }
   }
}

Upvotes: 4

Massimo Prota
Massimo Prota

Reputation: 1236

you did quite some investigation, and based on my information the WebTicket should be a possible authentication token for UCWA.

Unfortunately, the documentation is still correct in saying UCWA is only supported for on-prem installation at this moment. For Lync Online / Office 365 it isn't enabled yet.

There's a feature request on Office's User Voice that you can vote and follow. As you can read there are announcements to be expected soon in this

https://officespdev.uservoice.com/forums/224641-general/suggestions/5857717-ucwa-for-lync-365

Upvotes: 5

Related Questions