Authorization problem with SharePoint ClientContext created with ADAL Access Token - sharepoint

I am trying to automatize the provision of a SharePoint Online Site Collection. I am doing it with SharePoint CSOM. If I create the ClientContext(Microsoft.SharePoint.Client) object
with SharePointOnlineCredentials, everthing works fine such as creating sub sites/list/libraries, upload custom master pages, setting web properties etc. (By the way we are using Publishing Site)
ClientContext ctx = new ClientContext(contextWebUrl);
SecureString sec_pass = new SecureString();
Array.ForEach(contextPassword.ToArray(), sec_pass.AppendChar);
sec_pass.MakeReadOnly();
ctx.Credentials = new SharePointOnlineCredentials(contextUserName, sec_pass);
return ctx;
But i don't have user's password on production environment because we have to use ADAL authentication and we have only Access Token. So i have to create ClientContext object by using this token. Like;
ClientContext ctx = new ClientContext(siteUrl);
ctx.ExecutingWebRequest += delegate (object sender, WebRequestEventArgs e)
{
e.WebRequestExecutor.WebRequest.Headers.Add("Authorization", "Bearer " + siteToken.AccessToken);
if (digestValue != null)
{
e.WebRequestExecutor.WebRequest.Headers.Add("X-RequestDigest", digestValue.FormDigestValue);
e.WebRequestExecutor.WebRequest.Accept = "application/json;odata=verbose";
}
};
return ctx;
by this way getting something from SharePoint works but if i try to _set_ something such as create a subsite or deploy a master page to catalogs library i am getting 401 as below.
Access denied. You do not have permission to perform this action or access this resource
I thought that it was an update issue but even though i have used X-RequestDigest nothing changed.
Some people have encountered same issue when uploading documents but all answers are about using rest api directly and this cant solve my issue.

The token which is being used in second method is related to application client Id.
So Azure application needs necessary permission as similar as user's. In Azure Portal/Azure Active Directory, i gave AllSites.FullControl permission to the application which i use to signin and get access token.
Hereby this problem has been resolved.

Related

Upload file to the SharePoint site with Azure App credentials

I have
Registered Azure Application
that have full control permissions to the SharePoint site
and these variables
SharePoint Site Url
TenantId
ClientId
ClientSecret
I need to upload a document to the SharePoint Site Folder.
I tried to use PnP Core SDK but I am not able to configure the Authentication, it seems that there is no authentication provider to just accept plain password (UsernamePasswordAuthenticationProvider does not accept name of the application as a username).
Overall the PnP Core SDK is adding a lot of complexity to my console application because it depends on Microsoft.Extensions.Hosting.Host.
is there a way how to authenticate via PnP or should I use REST API directly?
Alternatively the PnP Framework that will be deprecated (if I understand the documentation correctly) can authenticate towards Azure Application, but this is only documentation I found.
Any idea or recommendation?
Update
When I try this (PnP Framework)
using Microsoft.SharePoint.Client;
using PnP.Core.Model.SharePoint;
using PnP.Framework;
ClientContext context =
new AuthenticationManager()
.GetACSAppOnlyContext(
siteUrl: "siteUrl",
appId: "clientId",
appSecret: "password");
IFolder? folder = (IFolder?)context.Web.Folders.Where(f => f.Name == directory).FirstOrDefault();
if (folder == null) throw new Exception("Folder not found.");
folder.Files.Add(filename, content, overwrite);
I am getting this exception
Microsoft.SharePoint.Client.CollectionNotInitializedException: 'The
collection has not been initialized. It has not been requested or the
request has not been executed. It may need to be explicitly
requested.'
Any Idea how to explicitly request the collection?
According to my research and testing, if you want to connect to SharePoint Online with Azure App credentials, you can use the following code, and then upload file to SharePoint:
string siteUrl = "https://contoso.sharepoint.com/sites/demo";
using (var cc = new AuthenticationManager().GetACSAppOnlyContext(siteUrl, "[Your Client ID]", "[Your Client Secret]"))
{
cc.Load(cc.Web, p => p.Title);
cc.ExecuteQuery();
Console.WriteLine(cc.Web.Title);
};
Here is a document about upload file to SharePoint, you can refer to the code in this document: Upload a document to a SharePoint list from Client Side Object Model
Also, you can try to install Microsoft.SharePointOnline.CSOM to fix the error:
Microsoft.SharePoint.Client.CollectionNotInitializedException: 'The
collection has not been initialized. It has not been requested or the
request has not been executed. It may need to be explicitly
requested.'
More information for reference: Granting access using SharePoint App-Only
Create ClientContext
using Microsoft.SharePoint.Client;
using PnP.Framework;
ClientContext _context =
new AuthenticationManager()
.GetACSAppOnlyContext(
siteUrl: siteUrl,
appId: appId,
appSecret: appSecret);
Method for uploading the file
public void UploadFile(Stream stream, string listTitle, string directory, string filename, bool overwrite)
{
List list = _context.Web.Lists.GetByTitle(listTitle);
var url = Path.Combine(directory, filename);
var file = new FileCreationInformation() { ContentStream = stream, Overwrite = overwrite, Url = url };
var addedFile = list.RootFolder.Files.Add(file);
_context.Load(addedFile);
_context.ExecuteQuery();
}
Call example
UploadFile(stream, "Documents", "Shared Documents/FooSubFolder/", "filename.txt", true)

How to access Microsoft Office 365 Planner programmatically

I am trying to access Microsoft Office 365 Planner using CSOM and Azure App. Whenever I try to access planner using group Id i am getting the below error:
401 - Unauthorized: Access is denied due to invalid credentials. You do not have permission to view this directory or page using the credentials that you supplied.
I have given the required permissions to Azure Graph api.
Application - Read Groups All, Read and Write Groups All.
Delegated - Tasks.ReadWrite
Below is the sample code that i am using:
//Querying plans in current group await
graphClient.Groups[groupId].Planner.Plans.Request().GetAsync();
Is there any option to achieve this. I need to access the planner and need to create Buckets and plans based on Office 365 group.
Any help is much appreciated. Thanks in advance.
You should be using Microsoft Graph rather than Azure AD Graph API.
https://learn.microsoft.com/en-us/graph/planner-concept-overview
Also, you need to authenticate with your user credentials to access the Planner. You can change the GetAccessToken method to authenticate this way (example from linked blog).
private async Task<string> GetAccessToken(string resourceId, string userName, string password)
{
try
{
var authority = ConfigurationManager.AppSettings["ida:AuthorizationLoginUri"] + ConfigurationManager.AppSettings["ida:TenantId"];
var authContext = new AuthenticationContext(authority);
var credentials = new UserPasswordCredential(userName, password);
var authResult = await authContext.AcquireTokenAsync(resourceId, ConfigurationManager.AppSettings["ida:ClientIdNativeClient"], credentials);
// Get the result
return authResult.AccessToken;
}
catch (Exception ex)
{
// TODO: handle the exception
return;
}
You need to also ensure that your app is registered properly in the portal. Please check out this helpful blog that shows how to get past the error you described when accessing the planner:
https://karinebosch.wordpress.com/2017/12/18/microsoft-graph/

Sharepoint Client Authentication

I'm developing a web application that uses Office 365 authentication.
I need to access users' SharePoint files. The app is a Multi-Tenant application, it means that I don't know the Sharepoint URL, but I can use Microsoft Discover API to discover the Sharepoint URL of the current user.
I want to acess sharepoint files using the Microsoft.Sharepoint.Client library. Consider the following code:
ClientContext context = new ClientContext("https://discoveredserver.sharepoint.com");
// The SharePoint web at the URL.
Web web = context.Web;
// We want to retrieve the web's properties.
context.Load(web);
I get a 403 not authorized because the client object doesn't have the credentials. The problem is that I can't set credentials during runtime because I don't have it, the only thing that I have is the Bearer token, which allows the connection to the Sharepoint API, using an HTTP header authorization.
Is there any way to set the Bearer token in the Sharepoint client to call Sharepoint Web Services?
The following example demonstrates how to explicitly specify Bearer Token in ClientContext:
public static ClientContext GetClientContext(Uri webUri)
{
var ctx = new ClientContext(webUri);
ctx.ExecutingWebRequest += delegate(object sender, WebRequestEventArgs e)
{
string realm = TokenHelper.GetRealmFromTargetUrl(webUri); //get the realm
string accessToken = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal, webUri.Authority, realm).AccessToken; //get access token
e.WebRequestExecutor.WebRequest.Headers.Add("Authorization", "Bearer " + accessToken);
};
return ctx;
}
Usage
using (var ctx = GetClientContext(webUri))
{
ctx.Load(ctx.Web);
ctx.ExecuteQuery();
}
The ACS-based access token used by a SharePoint provider-hosted app cannot be used for other services such as the Discovery Service.
http://blogs.msdn.com/b/kaevans/archive/2015/03/20/an-architecture-for-sharepoint-apps-that-call-other-services.aspx
If you need to use the Discovery Service or other services protected by Azure AD, you will need to first authenticate the user using Azure AD.
http://blogs.msdn.com/b/kaevans/archive/2015/03/23/using-openid-connect-with-sharepoint-apps.aspx
Once authenticated, you need to request an access token specific to the resource requested. My example shows Exchange Online, but you can change this to use the SharePoint Online API easily.
http://blogs.msdn.com/b/kaevans/archive/2015/03/23/call-o365-exchange-online-api-from-a-sharepoint-app.aspx
use the secure setting
string pass="your password"
SecureString password = new SecureString();
foreach (var item in pass.ToCharArray())
{
password.AppendChar(item);
}
var ctx = new ClientContext("yourSiteName");
ctx.Credentials = new SharePointOnlineCredentials(username, password);

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

I have a DEV environment where I develop my code and I use a local Sharepoint.
I have a TEST environment where I deploy my application and use a Sharepoint on the TEST server.
I am using Sharepoint 2010.
I have a client object model that I am using to save a document in a sharepoint server.
I am using the Microsoft.Sharepoint.Client library for the following code;
public void Save(byte[] file, string url)
{
using (var context = new ClientContext(this.SharepointServer))
{
var list = context.Web.Lists.GetByTitle(this.DocumentLibrary);
var fileCreationInformation = new FileCreationInformation
{
Content = file,
Overwrite = true,
Url = url
};
var uploadFile = list.RootFolder.Files.Add(fileCreationInformation);
uploadFile.ListItemAllFields.Update();
context.ExecuteQuery();
}
}
}
When I run this code in my development environment, the document is saved on the Sharepoint as intended.
When I deploy to the test environment when the document is saved to a different Sharepoint server, I get the following exception:
Microsoft.SharePoint.Client.ServerUnauthorizedAccessException: Access denied. You do not have permission to perform this action or access this resource.
So there is a permissions issue here.
However when I change my code on the development server to save the document to the Sharepoint on the Test server, it works. The same Sharepoint that would not save the document from my deployed application on Test. I am also logging in with forms authentication with the same user name and password.
So why might this happen and where should I look to fix it?
I found what I was missing
I needed to set the credentials for the context;
context.Credentials = new NetworkCredential(this.UserName, this.Password, this.Domain);

impersonate as different user inside the webpart code

I use the sharepoint lists as a database.
I want to somehow impersonate as different user inside the webpart code
and than as this user I will have both write and edit permission to the list.
My goal is to be able to have full premission only through the webpart code.
I am using MOSS 2007.
SPSecurity.RunWithElevatedPrivilieges() will execute your code as the system account, i.e. the account under which the application pool runs, which might or might not be what you want to do. For example, if you have a workflow attached to the list which is supposed to trigger when new items are added to the list, it will not fire if you insert a new list item under the credentials of the system account (this was a security fix introduced in SharePoint 2007 SP 1). In that case you will have to perform the insert operation under a different account that has the correct permissions on the list.
You can get the UserToken for any user using the following code:
SPUserToken userToken = null;
SPSecurity.RunWithElevatedPrivileges(() =>
{
using (SPSite site = new SPSite(SPContext.Current.Site.ID))
{
using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))
{
userToken = web.AllUsers["domain\\username"].UserToken;
}
}
});
Replace the "domain\username" with the correct windows account name. Then you can pass this user token to one of the overloads of the SPSite object constructor to execute the code under this user's credentials like so:
using (SPSite site = new SPSite(SPContext.Current.Site.ID, userToken))
{
using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))
{
// This code will execute under the credentials of the userToken user
}
}
Hope this helps.
You are looking for SPSecurity.RunWithElevatedPrivileges Method.

Resources