Sharepoint 2010 ClientContext with kerberos & a 401 unauthorised - sharepoint

I can get a remote console app talking to a NTLM Sharepoint site with ClientContext and I can it talking to a remote Kerberos Sharepoint box with HttpWebRequest.GetResponse();
But I cannot get it talking to the Kerberos Sharepoint box with CientContext. Any additional pointers would be gratefully recieved.
string siteURL = "http://my.remote.sharepoint";
ClientContext ctx = new ClientContext(siteURL);
CredentialCache cc = new CredentialCache();
cc.Add(new Uri(siteURL), "Kerberos", CredentialCache.DefaultNetworkCredentials);
ctx.AuthenticationMode = ClientAuthenticationMode.Default;
ctx.Credentials =cc;
/////////////////////////////////////////////////////////////////////////////////
// This code confirms that I can access "my.remote.sharepoint" with KRB
// HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(siteURL);
// myHttpWebRequest.Credentials = cc;
// myHttpWebRequest.UseDefaultCredentials = true;
// HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
/////////////////////////////////////////////////////////////////////////////////
Web remoteWeb = ctx.Web;
ctx.Load(remoteWeb);
ctx.ExecuteQuery();
//401 unauthorised returned from here
Wireshark suggests that it returns the initial 401 & then gives up! Any ideas

Please check if a SPN is registered for that host and a reverse DNS entry exists.

Related

Querying On-premise SharePoint using Azure AD MFA through C# app

I'm trying to use Microsoft.Identity.Client and Microsoft.SharePoint.Client libraries to authenticate to an On-premise SharePoint server and then query it.
I obtain the Azure AD access token from which the SharePoint server is a part of like following:
private readonly string[] m_scopes = { "user.read", "https://sql.azuresynapse-dogfood.net/user_impersonation" };
var publicAppBuilder = PublicClientApplicationBuilder.Create("MyClientId").WithAuthority("https://login.microsoftonline.com/a******com.onmicrosoft.com");
publicAppBuilder.WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient");
var app = publicAppBuilder.Build();
AuthenticationResult result = null;
result = app.AcquireTokenInteractive(m_scopes).ExecuteAsync().GetAwaiter().GetResult();
if (result != null)
{
m_mediator.AccessToken = result.AccessToken;
}
When I get the access token I put it in the request header as follows:
args.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + m_mediator.AccessToken;
Which is inside the ClientContext.ExecutingWebRequest subscribed method:
clientContext.ExecutingWebRequest += (sender, args) =>
which is triggered by
context.ExecuteQuery();
The remote server returned an error: (401) Unauthorized.
or
The remote server returned an error: (403) Forbidden.
How can I establish the connection? I want to avoid using app-only registration, I want to authenticate using Azure AD MFA (Interactive) method.Please note that I have all the permissions needed and I am an admin on both Azure AD where SharePoint is joined, as well on the SharePoint server itself. I authenticate through the browser just fine.
I've tried multiple things so far:
I tried creating a separate request where I forward the previously acquired accessToken as Authorization: Bearer token
I tried reading the FedAuth from the authentication connection window, so I can forward it in my HTTP request but with no success
I tried creating a "Web browser" using a WebBrowser C# class and reading the cookies that are on a browser level like the following: cookieContainer = webBrowser1.Document.Cookie; but I had no success.
I'm expecting to Authenticate via Azure AD and then connect to SharePoint in order to query it
To resolve the error "The remote server returned an error: (401)
Unauthorized", please try checking the following:
Check whether your URL is correct:
The SharePoint Online URL must always start with HTTPS.
$SiteURL` `=` `"https://crescent.sharepoint.com/sites/marketing"`
Check if you have the right permissions to the site:
Check whether you have sufficient permissions and you are able to open the site in the browser. Make sure to have SharePoint Online Administrator Role.
Check whether the Legacy authentication protocol is enabled:
Make sure to enable Legacy authentication protocol in your tenant, if it is not enabled.
Reference : SharePoint Online: Fix "The remote server returned an error (401) Unauthorized" Error in PowerShell - SharePoint Diary
To resolve the error "The remote server returned an error: (403)
Forbidden.", please try checking the following:
Make sure whether you have provided correct URL and credentials.
Make sure whether you have installed latest version of SharePoint Online Client Component SDK.
Try adding yourself to the site explicitly
Check the lock status of your site and unlock if it is locked.
Please check if any conditional access policies is enabled in your tenant.
If you try to connect to the Tenant Admin site, make sure the Tenant Admin URL like below:
https://YourDomain-admin.sharepoint.com
Reference : SharePoint Online: Fix "The remote server returned an error: (403) Forbidden." Error in PowerShell - SharePoint Diary.
I've found a solution.
I basically iterate through all cookies whenever a browser navigates through a new page and parse all the cookies until I get the fedAuth cookie:
I created a web browser from System.Windows.Forms.WebBrowser
In the WebBrowserNavigatedEventHandler for Navigated I do the following:
if (webBrowser1.Url.AbsoluteUri == "about:blank")
{
return;
}
var cookieData = GetWebBrowserCookie.GetCookieInternal(webBrowser1.Url, false);
if (string.IsNullOrEmpty(cookieData) == false)
{
var dict = ParseCookieData(cookieData);
if (dict.ContainsKey("FedAuth") && !string.IsNullOrEmpty(dict["FedAuth"]))
{
m_mediator.FedAuthCookie = dict["FedAuth"];
if (dict.ContainsKey("rtFa") && !string.IsNullOrEmpty(dict["rtFa"]))
{
m_mediator.RtFaCookie = dict["rtFa"];
}
m_mediator.UpdateConfiguration();
this.Close();
}
}
The ParseCookieData method looks like this:
private IDictionary<string, string> ParseCookieData(string cookieData)
{
var cookieDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
if (string.IsNullOrEmpty(cookieData))
{
return cookieDictionary;
}
var values = cookieData.TrimEnd(';').Split(';');
foreach (var parts in values.Select(c => c.Split(new[] { '=' }, 2)))
{
var cookieName = parts[0].Trim();
var cookieValue = parts.Length == 1 ? string.Empty : parts[1];
cookieDictionary[cookieName] = cookieValue;
}
return cookieDictionary;
}
and GetWebBrowserCookie class looks like this:
[SecurityCritical]
public static string GetCookieInternal(Uri uri, bool throwIfNoCookie)
{
uint pchCookieData = 0;
string url = UriToString(uri);
uint flag = (uint)NativeMethods.InternetFlags.INTERNET_COOKIE_HTTPONLY;
//Gets the size of the string builder
if (NativeMethods.InternetGetCookieEx(url, null, null, ref pchCookieData, flag, IntPtr.Zero))
{
pchCookieData++;
StringBuilder cookieData = new StringBuilder((int)pchCookieData);
//Read the cookie
if (NativeMethods.InternetGetCookieEx(url, null, cookieData, ref pchCookieData, flag, IntPtr.Zero))
{
DemandWebPermission(uri);
return cookieData.ToString();
}
}
int lastErrorCode = Marshal.GetLastWin32Error();
if (throwIfNoCookie || (lastErrorCode != (int)NativeMethods.ErrorFlags.ERROR_NO_MORE_ITEMS))
{
throw new Win32Exception(lastErrorCode);
}
return null;
}
private static void DemandWebPermission(Uri uri)
{
string uriString = UriToString(uri);
if (uri.IsFile)
{
string localPath = uri.LocalPath;
new FileIOPermission(FileIOPermissionAccess.Read, localPath).Demand();
}
else
{
new WebPermission(NetworkAccess.Connect, uriString).Demand();
}
}
private static string UriToString(Uri uri)
{
if (uri == null)
{
return string.Empty;
}
UriComponents components = (uri.IsAbsoluteUri ? UriComponents.AbsoluteUri : UriComponents.SerializationInfoString);
return new StringBuilder(uri.GetComponents(components, UriFormat.SafeUnescaped), 2083).ToString();
}
This way we open up a pop-up C# web browser, authenticate the user through the web using MFA and then close the browser when we acquire an authentication cookie so we can continue working with HTTP requests towards the Sharepoint server.
Source: https://github.com/OceanAirdrop/SharePointOnlineGetFedAuthAndRtfaCookie

How to Authenticate and Authorize Asp.Net Web application through QuickBooks?

how to Authenticate and Authorize Asp.Net Web application through QuickBooks.
I want to integrate QuickBooks Accounts System in ASP.NET web Application I have successfully make developer account on quickbooks and make an app and got consumer key, consumer Secret and App Token and all URL's
Know I need some asp.net web api code snipped to successfully authenticate and authorize my web user's and than show there accounting detail
Please help me i Google alot but have no success.
I'm Strange this form is 0% active related to quickbooks API's or etc, after alot of struggling i found an answer of above mention question,
Download Quickbooks IPP.NET SDK it will provide you different classes for CURD.
var appToken = "";
var consumerKey = "";
var consumerSecret = "";
// the above 3 fields you can get when create your app on quickbook go to My app----> select youre app--->goto KEYS
var accessToken = "";
var accessTokenSecret = "";
// this two tookens you will get from URL on the same above page
var realmId = "1400728630"; //1400728630
// this is youre company ID which can be used when you create youre //company on freshbook
var serviceType = IntuitServicesType.QBO;
var validator = new OAuthRequestValidator(accessToken, accessTokenSecret, consumerKey, consumerSecret);
var context = new ServiceContext(appToken,realmId, serviceType, validator);
var service = new DataService(context);
try
{
Customer customer = new Customer();
//Mandatory Fields
customer.GivenName = "Mary";
customer.Title = "Ms.";
customer.MiddleName = "Jayne";
customer.FamilyName = "Cooper";
service.AddAsync(customer);
//service.Add(entity);
}catch(Exception ex)
{
System.Console.WriteLine(ex);
}

How do I pass user credentials from the console to SharePoint Online?

I am trying to connect SharePoint 2013 Online website using a Context Token from a console executable. However, it is giving me error The remote server returned an error: (403) Forbidden.
Here is the code snippet:
string spurl = ConfigurationManager.AppSettings["Sharepoint_URL"].ToString();
using (ClientContext context = new ClientContext(spurl))
{
context.Credentials = new NetworkCredential("username", "password", "domain");
context.ExecuteQuery();
Web web = context.Web;
context.Load(web);
context.ExecuteQuery();
Console.WriteLine(context.Web.Title);
}
Console.ReadKey();
How can I make a connection with SharePoint Online? Does it only support claims-based authentication?
I think the method with which you are trying to authenticate is outdated. The SharePoint 2013 Client Object Model now has a class called SharePointOnlineCredentials which abstracts away all the tedious cookie container stuff. E.g.:
using (ClientContext clientContext = new ClientContext("https://yoursite.sharepoint.com/"))
{
SecureString passWord = new SecureString();
clientContext.Credentials = new SharePointOnlineCredentials("loginname#yoursite.onmicrosoft.com", passWord);
Web web = clientContext.Web;
clientContext.Load(web);
clientContext.ExecuteQuery();
Console.WriteLine(web.Title);
Console.ReadLine();
}
Please refer to this link for more information: https://sharepoint.stackexchange.com/questions/83985/access-the-sharepoint-online-webservice-from-a-console-application

Download file with url as http://<site collection>/_layouts/DocIdRedir.aspx?ID=<doc id> using web request

I have a site collection in which Document Id feature is activated.
Documents are archived to this site collection from another site (in which Document Id is activated as well) and the only information I have about the moved file is the document id which is same between the source and the destination.
I need to download the file using web request, but my code gives '401 Unauthorised Exception'.
My code is as below:
string url = "http://<site collection>/_layouts/DocIdRedir.aspx?ID=<doc id>";
HttpWebRequest request = HttpWebRequest.Create(url) as HttpWebRequest;
request.Method = "Get";
request.PreAuthenticate = true;
var credential= new NetworkCredential(username, password, domainname);
request.Credentials = credential;
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
I need to give some sort of authentication, but could not figure it out.
Any help would be greatly appreciated.
Thanks and Regards
Arjabh
Try running your code inside of a
SPSecurity.RunWithElevatedPrivileges(delegate()
{
//code goes here
});
block

SharePoint 2010 Client Object Model - Kerberos/Claims Authentication

I'm trying to read a value from a list in a remote SharePoint site (different SP Web App). The web apps are set up with Claims Auth, and the client web app SP Managed account is configured with an SPN. I believe Kerberos and claims are set up correctly, but I am unable to reach the remote server, and the request causes an exception: "The remote server returned an error: (401) Unauthorized."
The exception occurs in the line ctx.ExecuteQuery(); but it does not catch the exception in the if (scope.HasException) instead, the exception is caught by the calling code (outside of the using{} block).
When I look at the traffic at the remote server using Wireshark, it doesn't look like the request is even getting to the server; it's almost as if the 401 occurs before the Kerberos ticket is exchanged for the claim.
Here's my code:
using (ClientContext ctx = new ClientContext(contextUrl))
{
CredentialCache cc = new CredentialCache();
cc.Add(new Uri(contextUrl), "Kerberos", CredentialCache.DefaultNetworkCredentials);
ctx.Credentials = cc;
ctx.AuthenticationMode = ClientAuthenticationMode.Default;
ExceptionHandlingScope scope = new ExceptionHandlingScope(ctx);
Web ctxWeb = ctx.Web;
List ctxList;
Microsoft.SharePoint.Client.ListItemCollection listItems;
using (scope.StartScope())
{
using (scope.StartTry())
{
ctxList = ctxWeb.Lists.GetByTitle("Reusable Content");
CamlQuery qry = new CamlQuery();
qry.ViewXml = string.Format(ViewQueryByField, "Title", "Text", SharedContentTitle);
listItems = ctxList.GetItems(qry);
ctx.Load(listItems, items => items.Include(
item => item["Title"],
item => item["ReusableHtml"],
item => item["ReusableText"]));
}
using (scope.StartCatch()) { }
using (scope.StartFinally()) { }
}
ctx.ExecuteQuery();
if (scope.HasException)
{
result = string.Format("Error retrieving content<!-- Error Message: {0} | {1} -->", scope.ErrorMessage, contextUrl);
}
if (listItems.Count == 1)
{
Microsoft.SharePoint.Client.ListItem contentItem = listItems[0];
if (SelectedType == SharedContentType.Html)
{
result = contentItem["ReusableHtml"].ToString();
}
else if (SelectedType == SharedContentType.Text)
{
result = contentItem["ReusableText"].ToString();
}
}
}
I realize the part with the CredentialCache shouldn't be necessary in claims, but every single example I can find is either running in a console app, or in a client side application of some kind; this code is running in the codebehind of a regular ASP.NET UserControl.
Edit: I should probably mention, the code above doesn't even work when the remote URL is the root site collection on the same web app as the calling code (which is in a site collection under /sites/)--in other words, even when the hostname is the same as the calling code.
Any suggestions of what to try next are greatly appreciated!
Mike
Is there a reason why you are not using the standard OM?
You already said this is running in a web part, which means it is in the context of application pool account. Unless you elevate permissions by switching users, it won't authenticate correctly. Maybe try that. But I would not use the client OM when you do have access to the API already.

Resources