SharePointOnlineCredentials.GetAuthenticationCookie(Uri url) returns null - c#

I have created a C# application which connects to SharePoint online site. When calling the SharePointOnlineCredentials.GetAuthenticationCookie(siteURI) method sometimes it is able to fetch the cookie successfully, but sometimes the result returned is null. Why does this happen?
string siteUrl = "https://mySite.sharepoint.com/sites/TestSite";
var clientContext = new ClientContext(siteUrl);
var pswd = new SecureString();
const string mypwd = "P#ssword";
foreach (var c in mypwd.ToCharArray())
{
pswd.AppendChar(c);
}
SharePointOnlineCredentials spCred = new SharePointOnlineCredentials("username", pswd);
clientContext.Credentials = spCred;
var cookie = spCred.GetAuthenticationCookie(new Uri(siteUrl));
Web web = clientContext.Web;
clientContext.Load(web);
clientContext.ExecuteQuery();

To me it seems like the user you are using cannot access to this site. It's maybe a user right problem.
I have tested the GetAuthenticationCookie method and it return null when the user has no access rights on the site.

If user has all right access. It could be because of deprecated security protocols. Try specifying the security protocol to TLS 1.2 version.
You may use the below code::
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 |
SecurityProtocolType.Tls11 |
SecurityProtocolType.Tls |
SecurityProtocolType.Ssl3;

Related

C# WebClient DownloadFile works only once

I built a function that downloads a series of reports from my website (.NET webforms, old application), saves them as .html files in a temporary folder, zips them and return an archive to the user.
The application uses windows authentication and I managed to pass the current user credentials in the request by enabling
Credentials = CredentialCache.DefaultCredentials
Everything works seamlessly in my dev environment (both in IIS Express that on IIS), but on production server (Windows server 2008 R2, IIS 7.5) it only works if I limit the cycle to one iteration only.
It looks like the WebClient underlying connection remains open and the server refuses to open another one on the following cycle.
The error message I get is
The request was aborted: Could not create SSL/TLS secure channel.
and, enabling WCF tracing, I can narrow the issue to a "401 unauthorized" error.
Here's the significant part of my function:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls |
SecurityProtocolType.Tls12 |
SecurityProtocolType.Tls11;
foreach (var project in list.Take(1)) //fails if I try list.Take(2) or more
{
using (WebClient client = new WebClient
{
Credentials = CredentialCache.DefaultCredentials
})
{
UriBuilder address = new UriBuilder
{
Scheme = Request.Url.Scheme,
Host = Request.Url.Host,
Port = Request.Url.Port,
Path = "/ERP_ProjectPrint.aspx",
Query = string.Format("bpId={0}&bpVid={1}", project.Id, project.VersionId)
};
string fileName = project.VersionProtocol + ".html";
client.DownloadFile(address.Uri.ToString(), tempFilePath + fileName);
}
}
Any hint about IIS settings I could tweak to solve this issue?
It looks like Dispose() is not working correct within the using() statement:
using (WebClient client = new WebClient())
{ ... }
Workaround without a using() statement:
WebClient client = new WebClient();
client.DownloadFileCompleted += OnDownloadFileCompleted;
when download is completed:
client.Dispose()
It works for me.
Try moving you loop into your request, like below. Does that make a difference?
Also don't think you need to use list.Take
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls |
SecurityProtocolType.Tls12 |
SecurityProtocolType.Tls11;
System.Net.ServicePointManager.DefaultConnectionLimit = 10
using (WebClient client = new WebClient
{
Credentials = CredentialCache.DefaultCredentials
})
{
foreach (var project in list)
{
UriBuilder address = new UriBuilder
{
Scheme = Request.Url.Scheme,
Host = Request.Url.Host,
Port = Request.Url.Port,
Path = "/ERP_ProjectPrint.aspx",
Query = string.Format("bpId={0}&bpVid={1}", project.Id, project.VersionId)
};
string fileName = project.VersionProtocol + ".html";
client.DownloadFileTaskAsync(address.Uri.ToString(), tempFilePath + fileName).Wait();
}
}
}
The issue has been solved by enabling TLS 1.2 on the server: it wasn't enabled by default. Refer to https://tecadmin.net/enable-tls-on-windows-server-and-iis/.
BE AWARE that enabling it may break the RDP connection functionality to your server.
Thanks to Jokies Ding for pointing me in the right direction (see comments above)

Microsoft.SharePoint.Client.IdcrlException: 'The sign-in name or password---' Even WITH Pnp Authentication Manager

I have signed up for the Office 365 Developer Edition with Microsoft 365 E5 Developer (without Windows and Audio Conferencing). I am writing codes to connect to the Sharepoint of developer domain. Following are my codes:
public static String GetList( ICredentials credentials)
{
var authManager = new OfficeDevPnP.Core.AuthenticationManager();
using (ClientContext clientContext =
authManager.GetWebLoginClientContext("https://xxx.sharepoint.com"))
{
clientContext.Credentials = credentials;
Web web = clientContext.Web;
clientContext.Load(web,
webSite => webSite.Title);
clientContext.ExecuteQuery();
return web.Title;
}
}
public string callSharepoint()
{
const string userName = "Username#domain.onmicrosoft.com";
const string password = "xxxx";
var securePassword = new SecureString();
foreach (var c in password)
{
securePassword.AppendChar(c);
}
var credentials = new SharePointOnlineCredentials(userName, securePassword);
var list = GetList(credentials);
return list.ToString();
}
While running, it first asks to enter Microsoft Office credentials, and then it does verification by sending code to contact number and then after verification is completed it throws an Exception on Line
clientContext.ExecuteQuery(). The Exception is as follow:
Microsoft.SharePoint.Client.IdcrlException: 'The sign-in name or password does not match one in the Microsoft account system.'
The credentials I am using is of Admin Account with role Global Administrator. I also tried to add new user account in that Active Directory and tried that credentials but still got the same exception on the same place.
I even try to remove Pnp Authorization, Enable and disable Multi factor Authorization, but no success. However, I can successfully log in into the Sharepoint site on browser by using exactly same credentials.
What I think is, there is most likely a problem in the setup which I did while setting office account developer subscription. And maybe nothing is wrong with the code because I used the same codes to log in to my organization's Sharepoint and it works perfectly fine. Maybe I need something else to be configured in my developer's Office Account.
Please let me know if anyone already has some knowledge about this problem.
You have init the credential so you could use it directly, if issue exists, should be related to your user account or license.
public static String GetList(ICredentials credentials)
{
//var authManager = new OfficeDevPnP.Core.AuthenticationManager();
//using (ClientContext clientContext =
//authManager.GetWebLoginClientContext("https://xxx.sharepoint.com/sites/lee"))
//{
//}
using (ClientContext clientContext = new ClientContext("https://xxx.sharepoint.com/sites/lee"))
{
clientContext.Credentials = credentials;
Web web = clientContext.Web;
clientContext.Load(web,
webSite => webSite.Title);
clientContext.ExecuteQuery();
return web.Title;
}
}
public string callSharepoint()
{
const string userName = "user#xxx.onmicrosoft.com";
const string password = "password";
var securePassword = new SecureString();
foreach (var c in password)
{
securePassword.AppendChar(c);
}
var credentials = new SharePointOnlineCredentials(userName, securePassword);
var list = GetList(credentials);
return list.ToString();
}
Ok I found the solution.
That is I don't need this line of code:
clientContext.Credentials = credentials;
Since MFA is enabled, so when I logged in via Pnp Authenticator, it should use that user account. Instead of the one which is passed via SharePointOnlineCredentials.

How to fix 'operation has timed out' while connecting to sharepoint on Office 365 using C#

"Operation has timed out" error while connecting to Office 365 Sharepoint from asp.net web application
I have tried finding answers and implementing solutions like below:
How to connect to SharePoint on Office 365 with CSOM from C#?
Also some blogs suggested making an asynchronous query, which does not throw error but also does not give any results.
Also tried setting timeout property without any help.
Below is my code:
SharePointOnlineCredentials networkCredential = new
SharePointOnlineCredentials(SharePointUser, SharePointPassword);
Context = new ClientContext(SharePointURL);
Context.Credentials = networkCredential;
Web = Context.Web;
Context.Load(Web);
Context.ExecuteQuery();`
Also, strangely I am able to connect and get data using Console application, but I need to get this working in web application.
After a lot of search I realized that we need proxy to connect to Sharepoint Online and implemented following code to achieve
clientContext.ExecutingWebRequest += (s, e) =>
{
e.WebRequestExecutor.WebRequest.Proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
};
Add clientContext.RequestTimeout = -1 in the code, the code below for your reference.
string siteUrl = "https://tenant.sharepoint.com/sites/lz";
string userName = "lz#tenant.onmicrosoft.com";
string password = "xxx";
var securePassword = new SecureString();
foreach (char c in password.ToCharArray()) securePassword.AppendChar(c);
using (ClientContext clientContext = new ClientContext(siteUrl))
{
clientContext.Credentials = new SharePointOnlineCredentials(userName, securePassword);
clientContext.RequestTimeout = -1;
var web = clientContext.Web;
clientContext.Load(web);
clientContext.ExecuteQuery();
}

Upload document to Sharepoint 2013 Online using webservices

I have a client who is implementing customer portals in Sharepoint 2013 Online. The current program distributes documents to the customers by mail. Now we have to upload the documents to the customer portal.
I try to use the copy webservice in sharepoint. I created a test project and added the webservice as Web Reference and wrote the following testcode:
static void Main(string[] args)
{
string baseUrl = "https://mycustomer.sharepoint.com/sites/";
string customer = "customerportalname";
string serviceUrl = "/_vti_bin/copy.asmx";
string destinationDirectory = "/folder/";
string fileName = "uploaded.xml";
string username = "username#outlook.com";
string password = "password";
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml("<fiets><onderdeel>voorwiel</onderdeel><onderdeel>achterwiel</onderdeel><onderdeel>trappers</onderdeel><onderdeel>stuur</onderdeel><onderdeel>frame</onderdeel></fiets>");
byte[] xmlByteArray;
using (MemoryStream memoryStream = new MemoryStream())
{
xmlDocument.Save(memoryStream);
xmlByteArray = memoryStream.ToArray();
}
string destinationUrl = string.Format("{0}{1}{2}{3}", baseUrl, customer, destinationDirectory, fileName);
string[] destinationUrlArray = new string[] { destinationUrl };
FieldInformation fieldInfo = new FieldInformation();
FieldInformation[] fields = { fieldInfo };
CopyResult[] resultsArray;
using (Copy copyService = new Copy())
{
copyService.PreAuthenticate = true;
copyService.Credentials = new NetworkCredential(username, password);
copyService.Url = string.Format("{0}{1}", baseUrl, serviceUrl);
copyService.Timeout = 600000;
uint documentId = copyService.CopyIntoItems(destinationUrl , destinationUrlArray, fields, xmlByteArray, out resultsArray);
}
}
When I execute the code I recieve the following error:
The request failed with the error message:
--
<html><head><title>Object moved</title></head><body>
<h2>Object moved to here.</h2>
</body></html>
--
It looks like I'm not authenticated and get redirected. The credentials however are correct.
Does anyone have an idea? Thanks in advance!
UPDATE
To be able to connect to SharePoint 2013 Online you have to attach the Office 365 authentication cookies as explained in this post.
My problem however is that there is also an ADFS involved. How can I autheticate against the ADFS?
This error most probably occurs due to incorrect authentication mode.
Since SharePoint Online (SPO) uses claims-based authentication, NetworkCredential Class can not be utilized for authentication in SPO.
In order to perform the authentication against the ADFS in SPO you could utilize SharePointOnlineCredentials class from SharePoint Online Client Components SDK.
How to authenticate SharePoint Web Services in SharePoint Online (SPO)
The following example demonstrates how to retrieve authentication cookies:
private static CookieContainer GetAuthCookies(Uri webUri, string userName, string password)
{
var securePassword = new SecureString();
foreach (var c in password) { securePassword.AppendChar(c); }
var credentials = new SharePointOnlineCredentials(userName, securePassword);
var authCookie = credentials.GetAuthenticationCookie(webUri);
var cookieContainer = new CookieContainer();
cookieContainer.SetCookies(webUri, authCookie);
return cookieContainer;
}
Example
string sourceUrl = "https://contoso.sharepoint.com/Documents/SharePoint User Guide.docx";
string destinationUrl = "https://contoso.sharepoint.com/Documents/SharePoint User Guide 2013.docx";
FieldInformation[] fieldInfos;
CopyResult[] result;
byte[] fileContent;
using(var proxyCopy = new Copy())
{
proxyCopy.Url = webUri + "/_vti_bin/Copy.asmx";
proxyCopy.CookieContainer = GetAuthCookies(webUri, userName, password);
proxyCopy.GetItem(sourceUrl,out fieldInfos,out fileContent);
proxyCopy.CopyIntoItems(sourceUrl,new []{ destinationUrl}, fieldInfos, fileContent, out result);
}
References
Remote Authentication in SharePoint Online Using Claims-Based
Authentication
SharePoint Online Client Components SDK
In my case (on premise) i have that error. when i changed at iis SharePoint authentication for web application , and disable "Forms Authentication". Now, i canĀ“t enter to SharePoint by UI, but the Web Service works... So I have revert and I have been looking and...
[Paul stork] The Web Application for this site is running in Classic Mode rather than Claims mode. This can happen if you create the web app using Powershell or upgrade from 2010. You can use PowerShell to change it.
http://technet.microsoft.com/en-us/library/gg251985.aspx
I have tried the Web Service in another new application created by UI in Central Administration (in same farm) and it had worked. The problem was the web application.
To try:
http://sharepointyankee.com/2011/01/04/the-request-failed-with-the-error-message-object-moved-sharepoint-2010-web-services-fba/
Extend your mixed authentication web application, and create a zone just for Windows Authentication, then change the Web Reference URL in the properties of your web service, to use that extended URL and port. You should have no issues of this kind anymore.

Google Analytics Api on Azure

I want to use the google analytics api in my MVC website, im authenticating using the api service account and oauth2 with have no issues on my localhost but as soon as I deploy to Azure i get a 502 error:
"502 - Web server received an invalid response while acting as a
gateway or proxy server. There is a problem with the page you are
looking for, and it cannot be displayed. When the Web server (while
acting as a gateway or proxy) contacted the upstream content server,
it received an invalid response from the content server."
heres my code:
const string ServiceAccountUser = "xxxxxxxxxx-cpla4j8focrebami0l87mbcto09j9j6k#developer.gserviceaccount.com";
AssertionFlowClient client = new AssertionFlowClient(
GoogleAuthenticationServer.Description,
new X509Certificate2(System.Web.Hosting.HostingEnvironment.MapPath("/Areas/Admin/xxxxxxxxxxxxxxxxxx-privatekey.p12"),
"notasecret", X509KeyStorageFlags.Exportable))
{
Scope = AnalyticsService.Scopes.AnalyticsReadonly.GetStringValue(),
ServiceAccountId = ServiceAccountUser //Bug, why does ServiceAccountUser have to be assigned to ServiceAccountId
//,ServiceAccountUser = ServiceAccountUser
};
OAuth2Authenticator<AssertionFlowClient> authenticator = new OAuth2Authenticator<AssertionFlowClient>(client, AssertionFlowClient.GetState);
I cant figure out whats causing it? Am im missing something within Azure?
Thanks for any help.
I also ran into the same issue but passing X509KeyStorageFlags.MachineKeySet into the constructor as well fixed the issue for me.
X509Certificate2 certificate = new X509Certificate2(file, "key", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);
After hours of pain on this exact same problem, I found a work around by piecing together various sources of info.
The problem arises from trying to read the p12 file from the Azure web site, i.e. this line in my code fails
var key = new X509Certificate2(keyFile, keyPassword, X509KeyStorageFlags.Exportable);
No idea why, but it works if you split the file into a cer and key.xml file?
Firstly, extract these files, (I just used a console app)
// load pfx/p12 as "exportable"
var p12Cert = new X509Certificate2(#"c:\Temp\xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-privatekey.p12", "notasecret", X509KeyStorageFlags.Exportable);
// export .cer from .pfx/.p12
File.WriteAllBytes(#"C:\Temp\MyCert.cer", p12Cert.Export(X509ContentType.Cert));
// export private key XML
string privateKeyXml = p12Cert.PrivateKey.ToXmlString(true);
File.WriteAllText(#"C:\Temp\PrivateKey.xml", privateKeyXml);
Then copy them to your website then load them in like so
//Store the authentication description
AuthorizationServerDescription desc = GoogleAuthenticationServer.Description;
//Create a certificate object to use when authenticating
var rsaCryptoServiceProvider = new RSACryptoServiceProvider();
rsaCryptoServiceProvider.FromXmlString(File.ReadAllText(keyFile));
var key = new X509Certificate2(certFile) {PrivateKey = rsaCryptoServiceProvider};
//Now, we will log in and authenticate, passing in the description
//and key from above, then setting the accountId and scope
var client = new AssertionFlowClient(desc, key)
{
//cliendId is your SERVICE ACCOUNT Email Address from Google APIs Console
//looks something like 12345-randomstring#developer.gserviceaccount.com
//~IMPORTANT~: this email address has to be added to your Google Analytics profile
// and given Read & Analyze permissions
ServiceAccountId = clientId,
Scope = "https://www.googleapis.com/auth/analytics.readonly"
};
//Finally, complete the authentication process
//NOTE: This is the first change from the update above
var auth = new OAuth2Authenticator<AssertionFlowClient>(client, AssertionFlowClient.GetState);
//First, create a new service object
//NOTE: this is the second change from the update
//above. Thanks to James for pointing this out
var gas = new AnalyticsService(new BaseClientService.Initializer { Authenticator = auth });
This now works for me and I hope it helps you.

Categories

Resources