c# script Sharepoint API giving 401 Error on remote server - c#

I'm using the below code for sharepoint authentication. It works perfectly fine on a local machine, but when I deploy this package on server it is giving 401 error.
class Program
{
static void Main(string[] args)
{
//Delcaring Required variable (Actual variable values have been changed to dummy one)
var webUri = new Uri("https://blahblah.sharepoint.com");
string proxy = "http://abc.abc.com:1234/";
const string userName = "abc#blahblah.com";
const string password = "123";
string SalesPOV_GUID = "6319bd1f-7f-4ffd-95dc-a992afc4da10";
string Clients_GUID = "ojfoeiawe-3abcc6-41cd-be23-cf6043671d53";
//Creating a secured sring for SharepointOnline Credentials
var securePassword = new SecureString();
foreach (var c in password)
{
securePassword.AppendChar(c);
}
//Setting up credentials for Sharepoint
var credentials = new SharePointOnlineCredentials(userName, securePassword);
//Makiing a Call
using (var client = new WebClient())
{
try
{
//setting up proxy
System.Net.WebProxy wp = new System.Net.WebProxy();
Uri newUri = new Uri(proxy);
wp.Address = newUri;
client.Proxy = wp;
}
catch (WebException e) //In package we need to fail the package on catching exception.
{
string pageContent = new StreamReader(e.Response.GetResponseStream()).ReadToEnd().ToString();
}
client.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
client.Credentials = credentials;
}
}
}

Check if your sharepoint website is set to "pass-through" authentication for the physical path.

Related

C# SharePoint Online Error : The remote server returned an error: (403) FORBIDDEN

I would like to connect a SharePoint Online with the current user on .NET with Single Sign On. I don't want to specify username and password in my code. Unfortunatly, I've the following error message on ExecuteQuery() :
The remote server returned an error: (403) FORBIDDEN
My code :
string siteCollectionUrl = "https://xxx.sharepoint.com/teams/yyyy";
System.Net.ICredentials credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
SharePoint.ClientContext context = new SharePoint.ClientContext(siteCollectionUrl);
context.Credentials = credentials;
SharePoint.Web web = context.Web;
context.Load(web);
context.ExecuteQuery();
string tt = web.Title;
Do you have an idea ?
Thanks in advance
You have to use SharePointOnlineCredentials class for authentication.
Like this:
String name = "user#xxx.onmicrosoft.com";
String password = "xxxx";
SecureString securePassword = new SecureString();
foreach (char c in password.ToCharArray())
{
securePassword.AppendChar(c);
}
var credentials = new SharePointOnlineCredentials(name, securePassword);
string siteCollectionUrl = "https://xxx.sharepoint.com/teams/yyyy";
ClientContext ctx = new ClientContext(siteCollectionUrl );
ctx.Credentials = credentials;

Download File from SharePoint Online using WebClient

I am using .net 4.8 WebClient and the Microsoft.SharePointOnline.CSOM package, trying to download files from SharePoint online.
const string username = "myusername#domain.com";
const string password = "mypassword";
const string url = "https://tenant.sharepoint.com/:b:/r/filepath.pdf";
var securedPassword = new SecureString();
foreach (var c in password.ToCharArray())
{
securedPassword.AppendChar(c);
}
var credentials = new SharePointOnlineCredentials(username, securedPassword);
using (var client = new WebClient())
{
client.Credentials = credentials;
client.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
client.DownloadFile(url, "C:\\temp\\test.pdf"); //this file path definitely exists
}
The error I get is a 401 unauthorized.
I logged out and logged into the SharePoint environment using the same credentials, to ensure that they are correct.
I've tried adding a couple different user agents in the header to see if that helps.
client.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");
//or
client.Headers.Add("User-Agent: Other");
But it didn't make any difference.
This is similar to Download File From SharePoint 365 which is using what looks like the same code as I am, but Download Document from SharePoint Online using c# webclient stopped working suggests that something has changed and this form of authentication no longer works for connecting to SharePoint online. However I have been unable to find any recent documentation on what we're supposed to use now.
You could refer to the code provided by official document.
https://learn.microsoft.com/en-us/sharepoint/dev/sp-add-ins/working-with-folders-and-files-with-rest
As I test,it works well.
public static void DownloadFileViaRestAPI(string webUrl, ICredentials credentials, string documentLibName, string fileName, string path)
{
webUrl = webUrl.EndsWith("/") ? webUrl.Substring(0, webUrl.Length - 1) : webUrl;
string webRelativeUrl = null;
if (webUrl.Split('/').Length > 3)
{
webRelativeUrl = "/" + webUrl.Split(new char[] { '/' }, 4)[3];
}
else
{
webRelativeUrl = "";
}
using (WebClient client = new WebClient())
{
client.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
client.Credentials = credentials;
Uri endpointUri = new Uri(webUrl + "/_api/web/GetFileByServerRelativeUrl('" + webRelativeUrl + "/" + documentLibName + "/" + fileName + "')/$value");
byte[] data = client.DownloadData(endpointUri);
FileStream outputStream = new FileStream(path + fileName, FileMode.OpenOrCreate | FileMode.Append, FileAccess.Write, FileShare.None);
outputStream.Write(data, 0, data.Length);
outputStream.Flush(true);
outputStream.Close();
}
}
static void Main(string[] args)
{
string siteURL = "https://contoso.sharepoint.com/sites/dev";
//set credential of SharePoint online
SecureString secureString = new SecureString();
foreach (char c in "password".ToCharArray())
{
secureString.AppendChar(c);
}
ICredentials credentials = new Microsoft.SharePoint.Client.SharePointOnlineCredentials("amos#contoso.onmicrosoft.com", secureString);
//set credential of SharePoint 2013(On-Premises)
//string userName = "Administrator";
//string password = "xxxxxxx";
//string domain = "CONTOSO";
//ICredentials credentials = new NetworkCredential(userName, password, domain);
DownloadFileViaRestAPI(siteURL, credentials, "lib", "test.css", "c:\\SPFX\\");
Console.WriteLine("success");
Console.ReadLine();
}

403 error on Client.executeQuery()

I am trying to retrieve some information from a Office 365 site. I am getting a inconsistent 403 error on executeQuery call. This happens irregularly and is solved by IISReset. Please help.
ClientContext clientContext = new ClientContext(Constants.SP_URL);
{
SecureString passWord = new SecureString();
foreach (char c in Constants.SP_SERVICE_PASS.ToCharArray()) passWord.AppendChar(c);
var cred = new SharePointOnlineCredentials(Constants.SP_SERVICE_ACC, passWord); ;
clientContext.Credentials = new SharePointOnlineCredentials(Constants.SP_SERVICE_ACC, passWord);
Web web = clientContext.Web;
string docLibraryName = Constants.SP_PUBLISHED_LIB;
var list = clientContext.Web.Lists.GetByTitle(docLibraryName);
clientContext.Load(list);
**clientContext.ExecuteQuery();**
Here is what you need to get a client context and load your data.This authenticate you against SP Online in office 365. I do not know how would you say i reset my IIS. This is not applicable unless you connect to a local SP instance.
private void AutheticateO365(string url, string password, string userName)
{
Context = new ClientContext(url);
var passWord = new SecureString();
foreach (char c in password.ToCharArray()) passWord.AppendChar(c);
Context.Credentials = new SharePointOnlineCredentials(userName, passWord);
var web = Context.Web;
Context.Load(web);
Context.ExecuteQuery();
}

Authenticating Sharepoint site from background service and uploading file

I'm trying to authenticate up against Sharepoint so that it's possible for me to upload files onto a specific Sharepoint site.
I'm trying to use an X.509 certificate to retrieve the access token, but I keep getting (401): Unauthorized.
Here's the way I try to retrieve the access token with the certificate:
string authority = SettingsHelper.Authority;
string clientID = SettingsHelper.ClientId;
string serverName = SettingsHelper.SharepointServerName;
//Retreive the certificate path
string certFile = Server.MapPath(SettingsHelper.CertificatePath);
string certPassword = SettingsHelper.CertificatePassword;
AuthenticationResult authenticationResult = null;
AuthenticationContext authenticationContext = new AuthenticationContext(authority);
//Create the certificate file, using the path (certFile), password (certPassword) and the MachineKeySet
X509Certificate2 cert = new X509Certificate2(certFile, certPassword, X509KeyStorageFlags.MachineKeySet);
//Create the ClientAssertionCertificate using the clientID and the actual certificate
ClientAssertionCertificate cac = new ClientAssertionCertificate(clientID, cert);
//Retreive the access token using the serverName and client assertion
authenticationResult = authenticationContext.AcquireToken(serverName, cac);
And here's how I try to upload a specific file onto a specific Sharepoint list:
WebRequest request = null;
HttpWebResponse response = null;
byte[] bytesToUpload = bytes;
var returnValue = "";
string requestUriString = string.Format("{0}/_api/web/GetFolderByServerRelativeUrl(#sru)/Files/Add(url=#fn,overwrite=true)?#sru='{1}'&#fn='{2}'", url, HttpUtility.UrlEncode(serverRelativeUrl), HttpUtility.UrlEncode(fileName));
request = (HttpWebRequest)HttpWebRequest.Create(requestUriString);
request.Method = "POST";
(request as HttpWebRequest).Accept = "*/*";
request.ContentType = "application/json;odata=verbose";
request.Headers.Add("Authorization", String.Format("Bearer {0}", authenticationResult.AccessToken));
request.ContentLength = bytesToUpload.Length;
// Write the local file to the remote system
using (Stream requestStream = request.GetRequestStream())
{
BinaryWriter writer = new BinaryWriter(requestStream);
writer.Write(bytesToUpload, 0, bytesToUpload.Length);
writer.Close();
}
// Get a web response back
response = (HttpWebResponse)request.GetResponse();
using (StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.Default))
{
returnValue = sr.ReadToEnd();
sr.Close();
}
if (request.RequestUri.ToString().Contains("GetFolderByServerRelativeUrl") == true)
{
returnValue = "";
}
Some of the variables comes from the parameters:
UploadEmail(System.IO.File.ReadAllBytes(emlFilePath), "https://(blablabla).sharepoint.com", "sites/(bla)/(bla)/Emails", email.Subject + ".msg");
I'm not sure what's wrong, and I'm definitely not sure how to fix this.
NOTE: Please don't tell me to use NetworkCredentials, I'd rather use the certificate or something else, but not NetworkCredentials
EDIT
Managed to debug the code and find this in the response header of the WebRequest:
The better approach would be using the SharePoint Client Side Object Model (as hbulens suggested in comments).
Here's the code that uploads the file to the library in O365 (just replace the string literals with your own details):
string username = "YOUR_USERNAME";
string password = "YOUR_PASSWORD";
string siteUrl = "https://XXX.sharepoint.com";
ClientContext context = new ClientContext(siteUrl);
SecureString pass = new SecureString();
foreach (char c in password.ToCharArray()) pass.AppendChar(c);
context.Credentials = new SharePointOnlineCredentials(username, pass);
Site site = context.Site;
context.Load(site);
context.ExecuteQuery();
Web web = site.OpenWeb("YOUR_SUBSITE");
context.Load(web);
context.ExecuteQuery();
List docLib = web.Lists.GetByTitle("YOUR_LIBRARY");
context.Load(docLib);
FileCreationInformation newFile = new FileCreationInformation();
string filePath = #"YOUR_LOCAL_FILE";
newFile.Content = System.IO.File.ReadAllBytes(filePath);
newFile.Url = System.IO.Path.GetFileName(filePath);
Microsoft.SharePoint.Client.File uploadFile = docLib.RootFolder.Files.Add(newFile);
context.Load(uploadFile);
context.ExecuteQuery();
You can run it in console application. Two dll's that you need to reference are:
Microsoft.SharePoint.Client.dll
Microsoft.SharePoint.Client.Runtime.dll

vsphere api to change ip address of VirtualMachine

I'm new to the vsphere api and I'm trying to change the network settings of a virtual machine from dynamic ip to static ip but I can't find the setting.
Here's the code I have so far, it connects to vsphere, finds the virtual machine, and changes the name of the VM.
I assume there is a setting in the VirtualMachineConfigSpec that will also change the network settings, but I can't find it.
VimClient vimClient = new VimClient();
ServiceContent serviceContent = vimClient.Connect("https://[MY ADDRESS]/sdk");
UserSession us = vimClient.Login("[USERNAME]","[PASSWORD]");
ManagedObjectReference _svcRef = new ManagedObjectReference();
_svcRef.Type = "ServiceInstance";
_svcRef.Value = "ServiceInstance";
NameValueCollection filterForVM = new NameValueCollection();
filterForVM.Add("Name","[VIRTUAL MACHINE NAME]");
VirtualMachine vm = (VirtualMachine)vimClient.FindEntityView(typeof(VirtualMachine),null,filterForVM,null);
VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec();
vmConfigSpec.Name = "[NEW NAME]"; // change the VM name
vmConfigSpec.???? // how to set the ip address
vm.ReconfigVM_Task(vmConfigSpec);
vimClient.Disconnect();
VMware API don’t have a setting to set IP address on virtual machine guest OS, because the IP address setting depends on version guest OS. You could use two ways to do it:
1) You could use GuestOperationsManager from VMware vSphere API to launch the script of IP address setting on guest OS.
Prerequisites:
You should write scripts of IP address setting for each supported OS (Linux, Windows, etc.)
VMware Tools must be installed on each supported VM (for use GuestOperationsManager).
Update2. The following simplified example of running a script on the guest OS. This example does not include error handling, getting logs of the script, VM power on, etc.
using System;
using System.IO;
using System.Net;
using Vim25Api;
namespace RunScriptOnGuestOsTest
{
class Program
{
static void Main(string[] args)
{
var program = new Program();
program.RunScriptInGuestOs(
"https://10.1.1.10/sdk",
"root",
"vmware",
"c:\\temp\\test.bat",
"vm-73",
"Administrator",
"P#ssword",
"c:\\test.bat",
String.Empty);
}
public void RunScriptInGuestOs(string vCenterUrl, string vCenterUserName, string vCenterPassword, string scriptFilePatch, string vmKey, string username, string password, string destinationFilePath, string arguments)
{
var service = CreateVimService(vCenterUrl, 600000, true);
var serviceContent = RetrieveServiceContent(service);
service.Login(serviceContent.sessionManager, vCenterUserName, vCenterPassword, null);
byte[] dataFile;
using (var fileStream = new FileStream(scriptFilePatch, FileMode.Open, FileAccess.Read))
{
dataFile = new byte[fileStream.Length];
fileStream.Read(dataFile, 0, dataFile.Length);
}
FileTransferToGuest(service, vmKey, username, password, destinationFilePath, dataFile);
RunProgramInGuest(service, vmKey, username, password, destinationFilePath, arguments);
}
private static VimService CreateVimService(string url, int serviceTimeout, bool trustAllCertificates)
{
ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
return new VimService
{
Url = url,
Timeout = serviceTimeout,
CookieContainer = new CookieContainer()
};
}
private ServiceContent RetrieveServiceContent(VimService service)
{
var serviceInstance = new ManagedObjectReference
{
type = "ServiceInstance",
Value = "ServiceInstance"
};
var content = service.RetrieveServiceContent(serviceInstance);
if (content.sessionManager == null)
{
throw new ApplicationException("Session manager is null.");
}
return content;
}
private void FileTransferToGuest(VimService service, string vmKey, string username, string password, string fileName, byte[] fileData)
{
var auth = new NamePasswordAuthentication { username = username, password = password, interactiveSession = false };
var vmRef = new ManagedObjectReference { type = "VirtualMachine", Value = vmKey };
var fileMgr = new ManagedObjectReference { type = "GuestFileManager", Value = "guestOperationsFileManager" };
var posixFileAttributes = new GuestPosixFileAttributes();
posixFileAttributes.ownerId = 1;
posixFileAttributes.groupId = 1;
posixFileAttributes.permissions = (long)0777; //execution file
var requestUrl = service.InitiateFileTransferToGuest(fileMgr, vmRef, auth, fileName, posixFileAttributes, fileData.Length, true);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(requestUrl);
request.ContentType = "application/octet-stream";
request.Method = "PUT";
request.ContentLength = fileData.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(fileData, 0, fileData.Length);
requestStream.Close();
request.GetResponse();
}
private void RunProgramInGuest(VimService service, string vmKey, string username, string password, string programPath, string arguments)
{
var auth = new NamePasswordAuthentication { username = username, password = password, interactiveSession = false };
var vmRef = new ManagedObjectReference { type = "VirtualMachine", Value = vmKey };
var progSpec = new GuestProgramSpec { programPath = programPath, arguments = arguments };
var processMgr = new ManagedObjectReference { type = "GuestProcessManager", Value = "guestOperationsProcessManager" };
var result = service.StartProgramInGuest(processMgr, vmRef, auth, progSpec);
}
}
}
2) You could use DHCP server to manage distributing IP addresses. Using VMware API, you can get MAC address of virtual machine. Next you should set up DHCP server for distributing desired IP addresses on obtained MAC addresses.
Prerequisites:
Each VM must be set up to obtain IP address from DHCP server.
DHCP server which can be configured to fit your needs.

Categories

Resources