2

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&username=alexander@domain.company.com&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!

Alexander Johansen
  • 522
  • 1
  • 14
  • 28

4 Answers4

3

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.

James
  • 5,812
  • 5
  • 26
  • 30
0

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.

leopik
  • 2,323
  • 2
  • 17
  • 29
  • I already tried to implement and use that function. It did not make any difference. Still the same 409 error. – Alexander Johansen Oct 06 '14 at 10:45
  • Hmm ... I was pretty sure it was that. Well, maybe try to use the helper libraries? They're quite helpful + you don't have to write everything yourself – leopik Oct 06 '14 at 11:42
  • If he uses a static endpoint it changes the response code (assuming the application is still valid) from 201 (created) to 200 (OK). At this point the original application would is returned. – ShelbyZ Oct 13 '14 at 14:00
0

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

Massimo Prota
  • 1,226
  • 7
  • 14
  • I tried to use the auto-discovery and retrieve all the URL's from the response I got. I read the UCWA documentation about creating an application and did the steps exactly as described, but it still goes 409: Conflict. I am trying to read and understand the example code from Microsoft, but the object-model is a little over my head. If I ever figure it out: I will post the answer. I will update the code to my current code shortly. – Alexander Johansen Oct 08 '14 at 07:47
  • it sounds then even more weird, also because based on documentation 409 isn't really a status code expected to be returned by this operation. The only possible return code listed is 403 -> [applications](http://ucwa.lync.com/documentation/Resources-applications) – Massimo Prota Oct 08 '14 at 09:44
0

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!

Kippr
  • 76
  • 5