2
votes

I have been trying for the past couple of days to develop an application for our Lync service at work using the UCWA API from Microsoft (a REST API). To get an application working: I first have to submit it to the API using a POST request to a certain URL. First, I have to authenticate with the server, and I do that by posting a username and a password credential to the API. I then get an access token back which I can use to make further requests to the API by posting the token inside the header of each request. I have been able to get an access token working, but when I try to register the application by posting a HTTP request to https://lyncextws.company.com/ucwa/oauth/v1/applications: Things will start to go wrong.

All this is done through one JavaScript file working with iframes to bypass the Same-origin policy.

This is what my code currently looks like:

<!DOCTYPE html>
<html lang="no">
    <head>
        <meta charset="UTF-8" />
        <title>PresInfoDisp</title>
    </head>
    <body>
        <iframe src="https://lyncextws.company.com/Autodiscover/XFrame/XFrame.html" id="xFrame" style="display: none;"></iframe>
        <script type="text/javascript" src="jquery.js"></script>
        <script type="text/javascript">

        var access_token;

        var stage = 0;

        // CONNECT AND AUTHENTICATE WITH LYNC UCWA SERVICE
        function connectAndAuthenticate() {

            stage = 1;

            var request = { 
              accepts: 'application/json', 
              type: 'POST', 
              url: 'https://lyncextws.company.com/WebTicket/oauthtoken',
              data: 'grant_type=password&[email protected]&password=somePassword'
            }; 
            document.getElementById('xFrame').contentWindow.postMessage(JSON.stringify(request), 'https://lyncextws.company.com/WebTicket/oauthtoken');
        }

        // REQUEST A USER RESOURCE
        function getUserResourceAuthRequest() {

            stage = 0;

            var request = { 
              accepts: 'application/json', 
              type: 'GET', 
              url: 'https://lyncextws.company.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=company.com'
            }; 
            document.getElementById('xFrame').contentWindow.postMessage(JSON.stringify(request), 'https://lyncextws.company.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=company.com');

        }

        function getUserResource() {

            stage = 2;

            var request = { 
              accepts: 'application/json', 
              type: 'GET', 
              url: 'https://lyncextws.company.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=company.com',
              headers: {Authorization: "Bearer "+access_token}
            }; 
            document.getElementById('xFrame').contentWindow.postMessage(JSON.stringify(request), 'https://lyncextws.company.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=company.com');

        }

        // REGISTER APPLICATION RESOURCE
        function registerApplication() {

            stage = 3;

            var request = { 
              accepts: 'application/json', 
              type: 'POST', 
              url: 'https://lyncextws.company.com/ucwa/oauth/v1/applications',
              headers: {Authorization: "Bearer "+access_token},
              data: {'userAgent': 'InfoDisp1',  'endpointId' : '2d9dc28d-4673-4035-825c-feb64be28e4e', 'culture': 'en-US'}
            }; 
            document.getElementById('xFrame').contentWindow.postMessage(JSON.stringify(request), 'https://lyncextws.company.com/ucwa/oauth/v1/applications');

        }

        // GRAB A LIST OF CONTACTS
        function listContacts() {

            stage = 4;

            var request = { 
              accepts: 'application/json', 
              type: 'GET', 
              url: 'https://lyncextws.company.com/ucwa/oauth/v1/applications',
              headers: {Authorization: "Bearer "+access_token}
            }; 
            document.getElementById('xFrame').contentWindow.postMessage(JSON.stringify(request), 'https://lyncextws.company.com/ucwa/v1/applications');

        }

        this.receiveMessage = function(message) { 

            switch(stage) {
                case 1:

                    var beforeReplace = message.data.replace("/\\/g", "");
                    var json = jQuery.parseJSON(beforeReplace);
                    var json2 = jQuery.parseJSON(json.responseText);
                    access_token = json2.access_token;
                    console.log(json2.access_token);
                    console.log(message);

                    getUserResource();

                    break;
                case 0:
                    console.log(message);

                    connectAndAuthenticate();

                    break;

                case 2:

                    var beforeReplace = message.data.replace("/\\/g", "");
                    var json = jQuery.parseJSON(beforeReplace);
                    var json2 = jQuery.parseJSON(json.responseText);
                    console.log(json2._links.applications.href);

                    window.setTimeout(function(){registerApplication()}, 5000);

                    break;
                case 3:

                    console.log(message);

                    break;
                case 4:



                break;
            }


        }; 
        window.addEventListener('message', this.receiveMessage, false);


        $(window).load(function() {
            getUserResourceAuthRequest();
            //console.log(access_token);
        });

        </script>
    </body>
</html>

When I run this code: The last ajax query returns the error 409: Conflict, when it should be returning 201: Created

This is what my browser (Google Chrome) outputs: What my browser outputs in the developer console in Google Chrome

The 401: Unauthorized error is supposed to happen, but the 409 Conflict, should not happen. So here is my question: Can anyone spot why I get this 409 error instead of the 201 I should be getting?

The example code from Microsoft seems to work fine, but I want to avoid using that as it will take me a very long time to familiarize myself with it.

If there is missing data you need to spot the issue: Let me know in the comments, and i'll provide it!

4
Is the endpointId always that static string? - leopik
@user1680977 Yes. If I would acquire it from somewhere? Where would it be? - Alexander Johansen
What does your request header/body look like for the POST on applications? What does the response header/body look like? - ShelbyZ

4 Answers

3
votes

If you replace

data: {'userAgent': 'InfoDisp1',  'endpointId' : '2d9dc28d-4673-4035-825c-feb64be28e4e', 'culture': 'en-US'} 

with a string of that data instead I.E.

data: "{'userAgent': 'InfoDisp1',  'endpointId' : '2d9dc28d-4673-4035-825c-feb64be28e4e', 'culture': 'en-US'}" 

it seems that data expects a string and in your example you are passing it a JSON object. Doing that makes your example work for me.

0
votes

The problem seems to be with your static endpointId.

In their original helper libraries they have a method called generateUUID() which is in GeneralHelper. The best idea would be to use that method, however, if you feel like creating ayour own, go for it. The main point is that each of your application must have different endpointId.

0
votes

Are you omitting the autodiscovery process for brevity only, or are you really skipping the autodiscovery in your code and assuming the URI where to post the 'create application'?

It seems more the second case to me, and this isn't right: the URI where to create the application needs to be retrieved from the response of the user resource request (within getUserResource in the code you posted). You have a link called applications there; its value contains the correct URI where to create the application.

http://ucwa.lync.com/documentation/KeyTasks-CreateApplication

P.S. I post here as well about the endpointId, seen I can't comment above It is allowed to use the same application's endpointId on different clients. It is absolutely not to be assumed anyway that applications on different clients using the same endpointId will result in the same base application resource URI

0
votes

I was getting this same problem using curl to experiment with this API, and failed at this same point until I figured out that in that case I needed to set content-type header to json:

curl -v --data "{'userAgent': 'test', 'endpointId': '54321', 'culture':'en-US', 'instanceID':'testinstance'}" --header 'Content-Type: application/json' --header 'Authorization: Bearer cwt=AAEBHAEFAAAAAAA..' 'https://lyncserver.com/ucwa/oauth/v1/applications'

That did the trick!