locked
Elevate Privileges using App Only calls in Cloud Business App (HTML) RRS feed

  • Question

  • I would like to give my customers a way to provision sharepoint subsites that include certain artifacts that require sharepoint owner privileges such as modifying a master page.

    Right now, the client would select a certain person, and then hit a button in the HTML tier that calls an API to create the subsite.  Eventually the code moves to:

    using(ServerApplicationContext sac = ServerApplicationContext.CreateContext())

    {

    var ctx = sac.application.sharepoint.gethostwebcontext();

    .....start CSOM code

    }  (disregard spelling errors)

    This all works fine until the permission level exceeds the user's permission level.  I have set the appweb scope to"Site Collection" with full control. 

    What I cannot seem to figure out is if there is a built in way to shift from app+user over to apponly context for the elevated permissions.

    I suspect someone will tell me to add the tokenhelper class and treat the server tier like any other app; however, I suspect that lightswitch has this ability built-in, or I am going about this the wrong way.

    Any help would be appreciated.

    BTW- if tokenhelper is the answer, would really appreciate a link to everything needed to install.  I don't think that this class is a standalone nuget package.


    Jeff Childers

    Monday, June 1, 2015 5:23 AM

All replies

  • Monday, June 1, 2015 12:37 PM
  • I don't think it is a scope issue, but just in case I tried that and it didn't work.

    What I really need is to create an apponly context.  To do that I need the sharepoint context token.  Otherwise, I would have to re-tool the sharepoint authentication scheme which would defeat the purpose of a lightswitch app - MVC would be easier.

    What complicates the problem is that there is no page context when the webapi is called.  

    Any other ideas on how to get an app-only ClientContext?


    Jeff Childers

    Monday, June 1, 2015 7:05 PM
  • Monday, June 1, 2015 8:06 PM
  • Sorry, I have not done this, but are you saying you've granted 'SiteCollection - Full Control' in appmanifest.xml of SharePoint project and tried:

    serverContext.Application.SharePoint.GetHostWebClientContext()

    but the resulting context didn't allow full control?

    It's my understanding that GetHostWebContext() results in the AppOnly permissions granted in appmanifest.xml.

    You could also do this in JavaScript like so:

    http://www.sharepointnutsandbolts.com/2013/05/sp2013-host-web-apps-provisioning-files.html

    HTH,

    Josh

    Monday, June 1, 2015 9:48 PM
  • Ok now that Josh has got my brain back on track, here is some code that may be helpful when exploring Cloud Business Apps (LightSwitch) and SharePoint when making calls on serverContext.Application.SharePoint.GetHostWebClientContext():

    Exploring SharePoint 2013 Visual Studio Cloud Business Apps (LightSwitch)


    Unleash the Power - Get the LightSwitch 2013 HTML Client / SharePoint 2013 book

    http://LightSwitchHelpWebsite.com

    Monday, June 1, 2015 10:12 PM
  • You are correct josh.  Scope is set for site collection in app manifest with full control set.  also, I have the app only = true switch set. Haven't tried turning off app only, but that shouldn't make a difference.

    I can provision an entire site without issue using CSOM, but a non-administrator account cannot.  this is all done via webapi calls. 

    I can also confirm that if the user does not have view permissions for a list, they also can't view that data when the list is an oob sharepoint entity displayed using oob screens.

    I am using LS as a sharepoint workflow engine.  I need to be able to cue server side code via web API calls. 


    Jeff Childers

    Tuesday, June 2, 2015 12:34 AM
  • Links aren't really relevant.  this is an authorization problem.  I cannot find anywhere that lightsitch can take advantage of app only calls.  when a sharepoint project is attached, it appears all sharepoint calls are app+ user only. 

    Unfortunately, there is a work around using token helper and the new clientcontext helper for ACS, but neither is suited for webApi. Ī figured the since Microsoft built lightswitch html with that in mind, they would have created a means to get an app only context, but it appears only user contexts are part of the API 


    Jeff Childers

    Tuesday, June 2, 2015 12:42 AM
  • Any more ideas?


    Jeff Childers

    Tuesday, June 2, 2015 6:43 PM
  • Jeff,

    You're right, OAuth in Cloud Business App is a black box that does indeed use app+user authorization and there is no known way to get app-only context from the LS API. 

    It looks like tokenhelper is the way to do it with ACS.

    http://blogs.msdn.com/b/kaevans/archive/2013/02/23/sharepoint-2013-app-only-policy-made-easy.aspx 

    An alternative is the recently added ability to Authenticate from Azure AD:

    http://blogs.msdn.com/b/richard_dizeregas_blog/archive/2015/05/03/performing-app-only-operations-on-sharepoint-online-through-azure-ad.aspx

    It really is quite sad that all this auth stuff seems so difficult. 

    This nuget added to your WebAPI project will add SP references and also SharePointContext Helper which is built on TokenHelper for sharepoint.

    http://www.nuget.org/packages/AppForSharePointWebToolkit/ 

    http://blogs.msdn.com/b/officeapps/archive/2013/11/07/announcing-the-new-sharepointcontext-helper-in-apps-for-sharepoint-2013.aspx

    HTH,

    Josh

     

    Tuesday, June 2, 2015 7:26 PM
  • Josh,

    I think we are on the same page.  I hate having to sort through this stuff when it is hard to distinguish multiple mutually exclusive techniques, as well as, some that can be meshed together.  Here is what I have found is the case in Lightswitch.

    1. Selecting App Only Calls works if you are displaying something using the OOB screens.

    2. If you are using CSOM to interact with sharepoint, then "gethostwebclientcontext" is app+user and will not exceed the user's rights.

    3. Users can use the SharepointACSContext.cs on any sever aspx page to elevate permissions (make sure that you use the pre_init redirect); however, that will not work in webAPI because no page is actually opened.

    4. What is good about lightswitch is one thing:  ServerApplicationContext.Application.SharePoint actually has all the data you need.  I can't figure out how to pull it out directly, but what you can get is "ServerApplicationContext.Application.SharePoint.HostUrl".

    5. With that bit of information, which is obtained by design for you and available within the server context, you now can do something that is very harder in all other platforms- you can get the appOnlyAccessToken in the webAPI.  Bravo Lightswitch.

    So here is the code I settled on.  I hope this helps someone else out. 

      
    Uri targetUri = sac.Application.SharePoint.HostUrl;
    
    string realm = TokenHelper.GetRealmFromTargetUrl(targetUri);
    
    var appOnlyAccessToken = TokenHelper.GetAppOnlyAccessToken(
          "00000003-0000-0ff1-ce00-000000000000", //Constant
           targetUri.Authority,              
           realm);
    
    var ctx = TokenHelper.GetClientContextWithAccessToken(targetUri.toString(),appOnlyAccessToken.AccessToken);
    

    6.  Now, if MS would just give me a SharePoint Enhanced Rich Text Editor for lightswitch and a work around for the multi-select with fill in fields (many-to-many), I would be cooking with fire.


    Jeff Childers

    Tuesday, June 2, 2015 11:25 PM
  • Jeff, thanks for the update. Would like to here more about #6. Not sure I understand your request.
    Tuesday, June 2, 2015 11:32 PM
  • First, I think I spoke too soon. I struggle with authentication/authorization. My solution above works on my local box, but does not work when deployed to azure. Can't understand why, but it appears to get the correct context, but when I add "web.Context" in the webAPI, azure refuses to even step into my webAPI.  So for example,

    Web web = ctx.Site.OpenWeb(Intials);

    WebCollection collSubWeb = web.Webs;

    Works.  I can debug azure remotely and see that steps are executing.

    But if I add to the above, "web.Context.Load(collSubWeb);" it won't even open the API.

    Assuming that I can get the clientContext, or clientRuntimeContext in a webAPI, lightswitch will be a fantastic SharePoint tool for provisioning sites, creating word documents, controlling licenses, off loading certain list forms, etc.  I know that this can be done with MVC as well, but I am a sole proprietor that had never written anything but jQuery prior to 3 months ago (although I did use C++ in getting my eng degree so I am not totally without training).  Lightswitch bridges the gap pretty well.

    Being able to remotely provision will free me up to make money at my primary job.   Until I get this figured out, I can 't hire someone to do it for me.  Right now demand for provisioning is too high to support.  The product is selling, and word of mouth is incredible.

    So, for the moment, I am stuck, and lightswitch seems to be the most logical solution.

    As for item 6, I am using third party tools to fill in gaps. For example, I need to create a field where my users can input paragraphs that include italics, images, tables, etc.  Sharepoint's enhanced rich text field does this.   I know that I can create a custom field to edit and display HTML, but none of them are easy and their footprint is too large.

    The second problem is when you have a sharepoint field that is a multiselect with input.  That field is read only in lightswitch as a multi-multi field.  There are solutions out there for that too, but once again, the time it takes makes keeping that function in sharepoint more efficient. 

    Frankly, if lightswitch would support it, I would use it for all of sharepoints forms, and store the data in sharepoint.


    Jeff Childers

    Thursday, June 4, 2015 2:23 PM
  • Hi Jeff,

    Sorry to hear the saga continues.  You have me interested and I'd like to test the app-only CSOM.  No promises, but post your code and I'll try it when I can.

    I understand about SP multi-select and rich text editor.  I have not seen a solution for multi-select but Dale has a nice sample project comparing LS integration of 3 rich text editors here:

    https://github.com/dwm9100b/lswRichTextEditors

    HTH,

    Josh

    Thursday, June 4, 2015 3:30 PM
  • Josh,

    The saga does continue.  I know that I had this working in the past, and I know that I am programming everything correctly. 

    So I have worked in this all day and here is what I have realized.  I went back to step 1.5 and tried to implement http://lightswitchhelpwebsite.com/Blog/tabid/61/EntryId/3265/Implementing-Documents-in-a-SharePoint-2013-Cloud-Business-App-LightSwitch.aspx

    That solution does not work when published to Azure, but it does work locally on my machine.

    The only thing different, is that I am using VS 2015RC.  So, my next option is to delete and start over with the prior version.

    This problem is failing silently.  Cannot seem to even get an error using the azure remote debug service.  Locally, works like a champt.

    Any ideas?


    Jeff Childers

    Thursday, June 4, 2015 10:14 PM
  • Here is the code from that solution that does not work. Just paste it in any lightswitch app, ensure you have the latest sharepoint online csom nugget package, and call it with a get from any button in the HTML project. I have pasted both codes below for you.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using Microsoft.LightSwitch.Server;
    using Microsoft.LightSwitch.Security;
    using Microsoft.LightSwitch.Security.Server;
    using LightSwitchApplication;
    
    namespace LightSwitchApplication
    {
        /// <summary>
        /// Summary description for Test
        /// </summary>
        public class Test : IHttpHandler
        {
    
            public void ProcessRequest(HttpContext context)
            {
                using(ServerApplicationContext sac = ServerApplicationContext.CreateContext())
                {
                    var currentUser = sac.Application.User;
                    if(currentUser.IsAuthenticated)
                    {
                        // Call the SharePoint CSOM API
                        var clientContext = sac.Application.SharePoint.GetHostWebClientContext();
                        // Get the current web 
                        Microsoft.SharePoint.Client.Web web = clientContext.Web;
                        clientContext.Load(clientContext.Web);
                        clientContext.ExecuteQuery();
                    }
    
    
                    context.Response.ContentType =  "text/plain";
                    context.Response.Write("helelo");
                }            
            }
    
            public bool IsReusable
            {
                get
                {
                    return false;
                }
            }
        }
    }

    myapp.ViewTalent.Test_execute = function (screen) {
    
        // Using a Promise object we can call the CallGetUserName function
    
        msls.promiseOperation(CallTest).then(function PromiseSuccess(PromiseResult) {
            alert(PromiseResult);
        });
    
    };
    
    // This function will be wrapped in a Promise object
    
    function CallTest(operation) {
    
        $.ajax({
            type: 'post',
            data: {},
            url: '../Test.ashx',
            success: operation.code(function AjaxSuccess(AjaxResult) {
                operation.complete(AjaxResult);
            })
        });
    };


    Jeff Childers

    Thursday, June 4, 2015 10:17 PM
  • Well, I threw up a virtual machine, loaded VS 2013 pro on it.  Installed Azure 2.6, Office tools, 2013 SP Online CSOM, and SPMeta2, everything works, AND no it uses app only permissions.

    We may have a problem with VS 2015 RC's Lightswitch module that handles Sharepoint calls.

    The symptoms appear very similar to those found in the 2013 RC related to having a time zone that was east of UTC.

    Now to reload all home and work computers, again, to get rid of 2015 RC.

    Thanks for the help guys, a lot of nothing.  Stand by for 2015 though.


    Jeff Childers

    Friday, June 5, 2015 3:45 AM
  • Just was checking the thread and realized my last sentence doesn't say what I wanted to say. 

    Trying to convey that it was a lot of work for nothing.  Not that your assistance was "a lot of nothing". 


    Jeff Childers

    Friday, June 5, 2015 7:18 PM