12

I have a SharePoint 2013 SharePoint Hosted app, and I've got some code that works swimmingly well when it's pointed to the host site collection. Part of the requirement is to have it point to a user specified site collection. When I specify another site collection in my farm, it errors:

Access denied. You do not have permission to perform this action or access this resource

Is this possible? I'm guessing this is a security thing in the app model.

Update Adding some code, since it sounds like this should work. Also my app has Tenant Write permissions.

                var reqExecutor = new SP.RequestExecutor(appWebUrl);
                var url = appWebUrl + "/_api/SP.AppContextSite(@TargetSite)/web/lists/getByTitle(@TargetLibrary)/RootFolder/folders(@TargetFolderName)/files/" +
                        "add(url=@TargetFileName,overwrite='true')?" +
                        "@TargetSite='" + targetSiteUrl + "'&" +
                        "@TargetLibrary='" + targetLibrary + "'&" +
                        "@TargetFileName='" + fileName + "'&" +
                        "@TargetFolderName='" + folderName + "'";

                console.log('uploadDocToLibrary ' + url);
                reqExecutor.executeAsync({
                    url: url,
                    method: "POST",
                    headers: {
                        "Accept": "application/json; odata=verbose"
                    },
                    contentType: "application/json;odata=verbose",
                    binaryStringRequestBody: true,
                    body: fileData,
                    success: function (x, y, z) {
                        console.log("Successful upload, updating metadata");
                        getDocumentListItem(libraryName, fileName);
                    },
                    error: function (x, y, z) {
                        updateDivStatus('Error: ' + x.statusText);
                        console.log(x.body + " " + z);
                    }
                });

Another Update I switched from REST to CSOM, just to see, and I'm still getting access denied.

            function getTargetSiteName() {
                var context = new SP.ClientContext(appWebUrl);
                var hostContext = new SP.AppContextSite(context, targetSiteUrl);

                var web = hostContext.get_web();
                context.load(web);
                context.executeQueryAsync(
                    function () {
                        alert(web.get_title());
                    },
                    function (sender, args) {
                        alert(args.get_message());
                    });
            }

Update Appears to be a bug or a limitation with SharePoint Hosted apps... testing out a provider hosted instead.

2
  • Have you tried granting Tenant permissions to the App?
    – Brian P
    May 16, 2013 at 15:41
  • I removed my previous comment, I added Tenant and it's still not working, getting same error. May 16, 2013 at 16:59

8 Answers 8

4

I think I had the same problem and here is the solution I found.

(and I think it is what Robert means, actually)

var hostweburl;
var appweburl;

var clientContext;
var appContextSite;
var web;

$(document).ready(function () {
    hostweburl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));

    appweburl = decodeURIComponent(getQueryStringParameter("SPAppWebUrl"));

    $.getScript(hostweburl + "/_layouts/15/" + "SP.RequestExecutor.js", execCrossDomainRequest);
});

function execCrossDomainRequest() {
    clientContext = new SP.ClientContext(appweburl);

    appContextSite = new SP.AppContextSite(clientContext, 'http://the-collection-to-reach');

    web = appContextSite.get_web();

    clientContext.load(web);

    clientContext.executeQueryAsync(onRequestSucceeded, onRequestFailed);
}

function onRequestSucceeded() {
    alert(web.get_url());
}

function onRequestFailed(sender, args) {
    alert('Error: ' + args.get_message());
}

So far so good. It works.

I also had to grant my sharepoint-hosted app some rights (example):

<AppPermissionRequests>
  <AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="FullControl" />
  <AppPermissionRequest Scope="http://sharepoint/content/sitecollection" Right="FullControl" />
  <AppPermissionRequest Scope="http://sharepoint/content/tenant" Right="FullControl" />
</AppPermissionRequests>
1
  • this code does not work for me. I still get access denied!. did you find any solution ?
    – Pouyan
    Jan 29, 2014 at 11:46
2

Have you looked at the last part of this article from MSDN?

Cross-site collection calls A different problem that is often lumped into the same cross-domain category is issuing calls to SharePoint across sites or across site collections. For example, an app installed at http://contoso.sharepoint.com/site1 wants to retrieve a list from http://contoso.sharepoint.com/site2.

On the surface this looks like a cross-domain problem, but it is not. It's actually a traversal problem inside SharePoint resources. What you really want is for your app to talk to your allowed endpoint (your app web) and from there you want to internally proxy the call to a different site collection.

So, does that mean that you are out of luck if you want to use JavaScript? Nope, we actually have a pretty handy object for you named AppContextSite. All you have to do is set AppContextSite to point to the target web you want to talk to.

There is also a code example in the article

EDIT after code snippet added

How are you getting the reference to SP.RequestExecutor.js? Per the blog post above you should load it from the host web:

// Load the .js files using jQuery's getScript function.
    $.getScript(
        hostweburl + "/_layouts/15/SP.RequestExecutor.js",
        continueExecution);

// After the cross-domain library is loaded, execution
    //  continues to this function.
    function continueExecution() {
        var executor;

        // Initialize your RequestExecutor object.
        executor = new SP.RequestExecutor(appweburl);

        // You can issue requests here using the executeAsync method
        // of the RequestExecutor object.
    }
8
  • I am using the AppContextSite already, added code above May 16, 2013 at 16:59
  • Sorry but I see no code May 16, 2013 at 17:01
  • sorry, just added May 16, 2013 at 17:02
  • Updated with more from the article, specifically an interesting part about how to load the SP.RequestExecutor :) May 16, 2013 at 17:09
  • 1
    Did you read the updated article where he states Please note that in order for cross-site collection calls to work your app must be deployed as a tenant scoped app by an administrator; this is currently a security restriction of the API. Nov 5, 2013 at 10:57
0

If you've done everything right which is mentioned in the above steps. Try deploying your app through app catalogue to the target site. It will solve the problem.

0

Apps can be deployed in 2 scopes:

1) Web Scope: Where you can only access data from the host web and the app web.

2) Tenant Scope: Where you can access data from any site collection in the Tenant provided you have the right permissions set in the AppManifest.

I believe your requirement calls for a Tenant Scoped App.

The scope is decided only by how you deploy your app. See these links for further details:

Tenancies and deployment scopes for apps for SharePoint

Batch Install SharePoint Apps in Tenant Scope

3
  • Thanks for your answer, and I agree, I do need Tenant Scope, but as I previously noted, I tried that and still received the error. I was working with MS closely on this project and their team had the same problem. Sadly, I have moved to another project and not sure if it is still an issue. Jan 29, 2014 at 19:09
  • I am pretty sure this is in fact a bug. I have tenant scope added, and it does not work when posting May 6, 2014 at 22:47
  • Did you deploy your app through the AppCatalog? Deploying it from visual studio will not work. May 7, 2014 at 9:15
0

It could be this,

Access data from an additional remote host in a SharePoint-hosted app

By default, a SharePoint-hosted app is allowed to issue cross-domain calls to the host web, provided that it has proper permissions. However, a SharePoint-hosted app can also specify a remote host in the AllowedRemoteHostUrl attribute of its AppPrincipal.

How to: Access SharePoint 2013 data from apps using the cross-domain library

0

Well here I quote my experience. As far as developing app for cross site collection access is concerned, my code is working perfectly fine and I am able to access the list on other site collections without any problem. Now there is a punch here and it has been mentioned by other fellas overhere a number of times. I deploy my app directly onto the app catalog and use the following code:

function CrossDomainAccess(){
var executor = new SP.RequestExecutor(SPAppWebUrl);
var newHostWeb = "http://server/sites/yoursitecollection/";
var url = SPAppWebUrl + "/_api/SP.AppContextSite(@target)/web?" + "@target='" + newHostWeb + "'";

executor.executeAsync({
    url: url,
    method: "GET",
    crossDomain: true,
    headers: { "Accept": "application/json; odata=verbose" },
    success: function (data)
    {
        alert(data.body);
        // var jsonObject = JSON.parse(data.body);
    },
    error: function (data, errorCode, errorMessage)
    {
        alert(errorMessage);
    }
});}

I used JSOM as well and it also worked fine. What I have done is that I deploy my app using visual studio directly on to the app catalog site collection (Using site URL property of the project). By doing that I turned my web scoped app to tenant scoped app. Please correct me if I am wrong! BTW my app is SharePoint Hosted app. Remember that you cannot deploy an app onto the catalog using normal farm admin account. it has to be managed account that you create for app development (which already has farm admin rights). Furthermore I could deploy my app, debug it and redeploy during debug session using Fast Deployment Tool. Hope this brief description helps. Cheers Vaqar

0

Code sample: Client Side function for cross-site collections call, can throw the 'Access denied. You do not have permission to perform this action or access this resource.' error.

$.getScript("/_layouts/15/SP.RequestExecutor.js");

    function execCrossDomainRequest() {
    var executor;
    executor = new SP.RequestExecutor(appweburl);
    executor.executeAsync(
          {
            url: appweburl + "/_api/SP.AppContextSite(@target)/web?@target='[CROSS-SITECOLLECTIONURL]',
            method: "GET",
            headers: { "Accept": "application/json; odata=verbose" },
            success: successHandler,
            error: errorHandler
          }
      );
    }

    function successHandler(data) {
        alert(jsonObject.d.Title);
    }

    function errorHandler(data, errorCode, errorMessage) {
     alert("Could not complete cross-domain call: " + errorMessage);
    }

Solution (for Sharepoint-hosted App)

  1. Add tenant Read permission on the AppManifest.xml

    AppPermissionRequest Scope="http://sharepoint/content/tenant" Right="Read"

  2. Deploy App to the APP Catalog and publish it via App 'Deployment' to the pretended site collections.

-1

This new article should clarify what you can or can't do:

http://blogs.msdn.com/b/vesku/archive/2015/11/20/automating-add-in-app-installation-to-sharepoint-sites-using-csom.aspx

2
  • Please do not provide link only answers. Nov 23, 2015 at 3:47
  • Please don’t add just a link as answer to a question. If the link breaks, the answer you provided will not be useful for future visitors. Provide an answer of your own and use the link as reference. If needed, you can block quote the content from your link. More information is found in our help center, especially How do I write a good answer
    – Benny Skogberg
    Nov 23, 2015 at 7:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.