none
Calling Sharepoint REST API from another application's IFRAME (javascript). RRS feed

  • Question

  • Hello, I want to upload some file to Sharepoint using REST API.

    I want to do this from another web application's iframe (javascript). In my case, this another application is MS CRM 2015.

    I Sharepoint 2013 on-premise and CRM 2015 on-premise.

    I'm using Microsoft's proposed way to do this (with library for cross domain calls - https://msdn.microsoft.com/en-us/library/office/dn735924.aspx)

    Code looks like this:

    function DoWork(fileString, filename) {

        var serverUrl = "https://sharepointsite.mydomain.com";
        var relativePath = "/dpt/imp/tcs_p/130446/Timesheets";

        $.getScript(serverUrl + "/_layouts/15/SP.RequestExecutor.js", execCrossDomainRequest);
           
        function execCrossDomainRequest() {
            var executor;

            executor = new SP.RequestExecutor("https://sharepointsite.mydomain.com/dpt/imp");
                                     
            executor.executeAsync(
                {
                    url:
                        "https://sharepointsite.mydomain.com/dpt/imp" +
                        "/_api/web/GetFolderByServerRelativeUrl('" + relativePath + "')/Files" +
                        "/Add(url='" + filename + "')",
                    method: "POST",
                    headers: { "Accept": "application/json; odata=verbose" },
                    success: function (data) {
                        console.log("succ");
                    },
                    error: function (err) {
                        console.log(err.statusText);
                    }
                }
            );
                   
        }
    }
    Code does not work at all. SP.RequestExecutor's executeAsync method never generates any network traffic (nor I get any errors in javascript). 


    My second approach is to do things manually with $.ajax jquery method.

        function DoWork(fileString, filename) {

            var serverUrl = "https://sharepointsite.mydomain.com";
            var relativePath = "/dpt/imp/tcs_p/130446/Timesheets";

            $.ajax({
                url: serverUrl + 
                "/dpt/imp/_api/web/GetFolderByServerRelativeUrl('" + relativePath + "')/Files" +
                "/Add(url='" + filename + "')",                     
                type: "POST",                    
                data: fileString,                     
                crossDomain: true,                    
                xhrFields: {
                     withCredentials: true
                },                     
                headers: {
                                     "accept": "application/json;odata=verbose",
                                     "content-type": "text/plain",
                                     "X-RequestDigest": $("#__REQUESTDIGEST").val(),
                                     "content-length": fileString.byteLength
                },
                success: function (data) {
                    console.log("succ");
                },
                error: function (err) {
                    console.log(err.statusText);
                }
            });
        }


    I always get 403-forbidden.


    Then I try another request (GET request), only to get the list of files.

    $.ajax({                  
        url: "https://sharepointsite.mydomain.com/dpt/imp/_api/web/GetFolderByServerRelativeUrl('/dpt/imp/tcs_p/130446/Timesheets')/Files",
        type: "GET",
        async: false,
        crossDomain: true,                    
        xhrFields: {
            withCredentials: true
        },
        headers: { "accept": "application/json;odata=verbose" },
        success: function (data) {
            console.log("succ");
        },
        error: function (error) {
            alert(JSON.stringify(error));
        }
    });

    This works perfectly. I see list of files in http response.

    What am I missing? 
    a) Sharepoint permissions? User has full control on "https://sharepointsite.mydomain.com/dpt/imp" site. 
        GET is possible, but POST causes 403.

    b) Some problems related to CORS ?
        I put CORS configuration in Sharepoint web.config

            <add name="Access-Control-Allow-Origin" value="https://crmsite.mydomain.com" />
       <add name="Access-Control-Allow-Credentials" value="true" />
       <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, OPTIONS" />
       <add name="Access-Control-Allow-Headers" value="Content-Type, Accept, X-Requested-With, X-File-Name"/>

    c) Why SP.RequestExecutor never creates any http request? Is this even made for calls outside sharepoint site?


    Friday, June 19, 2015 8:46 AM

Answers

  • Hi,

    Let me first try to explain why it's working or not work in different scenarios:

    • SPRequestExecutor: Works perfectly for SharePoint Apps - because when the app is installed, SharePoint configure some permission things internally which gives app the access it's needed (some client id, secret id things). In your case it's not an app rather another full-fledged site - and SharePoint has no idea how to act with this external site.
    • jQuery Get: It works mostly because get request is not harmful. It's not requesting data and most of the time works in CORS scenarios - but still depends.
    • jQuery Post: Here it comes.. Post is always posting data to server - so means changes in server data. So doesn't work in your case

    Just think of a scenario, you have opened your facebook in a tab and a 'bad' site in another tab. What if the bad site post a message to your facebook (by using jQuery Post) - you are logged in to facebook? For security POST is not supported across domain by default.

    And for your information I would not make changes in SharePoint web config file without knowing the impact.. In my experience if you play with SharePoint nuts and bolts, you will break something somewhere. For example maybe adding the 'access control allow' will break copying files in 'windows explorer view', just as an example.

    Enough about the problem. Let's take about solution. If possible I would go with server side coding option - safe and secure. The idea is to upload file inside CRM (or probably send file content to CRM custom service) and the CRM service will post data to SharePoint. Since it's server side code, not CORS problem exists.

    Microsoft added support for CORS in Office 365 (so in SharePoint Online) using Azure AD - details: https://msdn.microsoft.com/en-us/office/office365/howto/create-web-apps-using-CORS-to-access-files-in-Office-365. But I don't think the feature is available out of the box in SharePoint. It's more like Azure AD feature.

    There's some solutions - like you are trying to add access control but again it's not full-proof solution - I once tried solution like this but in some cases (due to IE security policy) it didn't work.

    Long story short, as far as I know there's no easy solution to your problem, you may hack around but may pose security risk.


    Thanks,
    Sohel Rana
    http://ranaictiu-technicalblog.blogspot.com

    • Marked as answer by bt_programmer Friday, June 19, 2015 11:14 AM
    Friday, June 19, 2015 9:41 AM

All replies

  • Hi,

    Have you given the write permission to your SharePoint App on the target site collection or web ? If not give the same and check whether you are able to post files through App.

    SP.RequestExecutor method is a just an Microsoft's alternate approach to CORS.

    Check this link for more info on the SP.RequestoExecutor


    Murugesa Pandian| MCPD | MCTS |SharePoint 2010

    Friday, June 19, 2015 9:17 AM
  • Hi,

    Let me first try to explain why it's working or not work in different scenarios:

    • SPRequestExecutor: Works perfectly for SharePoint Apps - because when the app is installed, SharePoint configure some permission things internally which gives app the access it's needed (some client id, secret id things). In your case it's not an app rather another full-fledged site - and SharePoint has no idea how to act with this external site.
    • jQuery Get: It works mostly because get request is not harmful. It's not requesting data and most of the time works in CORS scenarios - but still depends.
    • jQuery Post: Here it comes.. Post is always posting data to server - so means changes in server data. So doesn't work in your case

    Just think of a scenario, you have opened your facebook in a tab and a 'bad' site in another tab. What if the bad site post a message to your facebook (by using jQuery Post) - you are logged in to facebook? For security POST is not supported across domain by default.

    And for your information I would not make changes in SharePoint web config file without knowing the impact.. In my experience if you play with SharePoint nuts and bolts, you will break something somewhere. For example maybe adding the 'access control allow' will break copying files in 'windows explorer view', just as an example.

    Enough about the problem. Let's take about solution. If possible I would go with server side coding option - safe and secure. The idea is to upload file inside CRM (or probably send file content to CRM custom service) and the CRM service will post data to SharePoint. Since it's server side code, not CORS problem exists.

    Microsoft added support for CORS in Office 365 (so in SharePoint Online) using Azure AD - details: https://msdn.microsoft.com/en-us/office/office365/howto/create-web-apps-using-CORS-to-access-files-in-Office-365. But I don't think the feature is available out of the box in SharePoint. It's more like Azure AD feature.

    There's some solutions - like you are trying to add access control but again it's not full-proof solution - I once tried solution like this but in some cases (due to IE security policy) it didn't work.

    Long story short, as far as I know there's no easy solution to your problem, you may hack around but may pose security risk.


    Thanks,
    Sohel Rana
    http://ranaictiu-technicalblog.blogspot.com

    • Marked as answer by bt_programmer Friday, June 19, 2015 11:14 AM
    Friday, June 19, 2015 9:41 AM
  • Thank you Sohel.

    If you can tell me what do you mean by "CRM custom service" ?

    The only way I can send data to server-side in CRM is by creating annotation entity with attachment, extracting file attachment in CRM plugin and then send it to Sharepoint from plugin.

    These seems to be the easiest way (without making additional web sites, services etc.)

    I know I'am going outside scope of original question, 

    but this was my intention all along - to post file to SharePoint from CRM, but not by using standard SharePoint list component (because it has some limitations)

    Friday, June 19, 2015 10:10 AM
  • Hi,

    By 'CRM Custom Service' I tried to mean any way to send data through from browser to CRM server to SharePoint server instead of browser to SharePoint server. Since I've no idea about CRM I was thinking like a kind of service - which I think called 'plugin' in CRM.

    SharePoint has list as well as library and you can upload file in both of them and it depends on your information architecture and business requirements - the best place to upload...


    Thanks,
    Sohel Rana
    http://ranaictiu-technicalblog.blogspot.com

    Friday, June 19, 2015 10:33 AM