Upload file to the SharePoint site with Azure App credentials - sharepoint-online

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)

Related

Local files in Azure Function

I am trying to access google drive using the azure function(time-triggered), it creates a token file during runtime when permissions are given to access the drive. It stores that file locally, and the azure function works fine locally.
But when deployed I get an error where my local system path is described in an error that I receive. When I have deployed the function why is it storing my local system path?
It should access the path where the Azure function is stored.
Code
public DriveService GetService()
{
//get Credentials from client_secret.json file
UserCredential credential;
string clientSecretString = config[Constant.ClientSecret];
log.LogInformation("String value is " + clientSecretString);
byte[] clientSecret = Encoding.UTF8.GetBytes(clientSecretString);
using (var stream = new MemoryStream(clientSecret)) <----------------- Error Message
{
log.LogInformation("Current path is " + Environment.CurrentDirectory);
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(Environment.CurrentDirectory, false)).Result;
}
log.LogInformation("Completed ");
//create Drive API service.
DriveService service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = Constant.ApplicationName,
});
return service;
}
Error Message:
[Error] at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)at System.Threading.Tasks.Task1.GetResultCore(Boolean waitCompletionNotification)at System.Threading.Tasks.Task1.get_Result()at ExportSheetsToExcelPowerBi.GoogleDriveService.GetService() in C:\Users\username\Documents\Project\GoogleDriveService.cs:line
For Azure function apps there is no need to read secrets from the token file generated by Google Auth. As answered on one of your previous posts. You can configure your function app to use Google login for authentication purposes when running on Azure. To achieve this you have to generate client id and client secret using the Google sign-in for server-side apps, using this connection you can store the tokens obtained in the token store. Please refer to this document to configure your function app to use Google Login, refer to this document regarding the token store and how to retrieve and refresh the token obtained.

Authorization problem with SharePoint ClientContext created with ADAL Access Token

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.

DTD is prohibited in this XML document when using CSOM with SharePoint Online

This code snippet
string strUserName="abc";
string strPassword="123";
SecureString ssPwd = new SecureString();
strPassword.ToList().ForEach(ssPwd.AppendChar);
ClientContext context = new ClientContext(siteurl);
SharePointOnlineCredentials credentials = new SharePointOnlineCredentials(strUserName, ssPwd);
context.Credentials = credentials;
// The SharePoint web at the URL.
Web web = context.Web;
// We want to retrieve the web's properties.
context.Load(web);
// Execute the query to the server.
context.ExecuteQuery();
Creates the following error message trying to connect to SharePoint Online:
For security reasons DTD is prohibited in this XML document. To enable DTD processing set the DtdProcessing property on XmlReaderSettings to Parse and pass the settings into XmlReader.Create method.
The same thing happens using the SharePoint Client Browser downloaded from CodePlex (https://spcb.codeplex.com).
What's wrong? What can I do?

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);

Resources