I am developing a Provider-hosted application for SharePoint 2013.
I debug this application on a Development Collection with both Windows Authentication and FBA (Form Based Authentication) activated. I can successfully access to this collection with my Windows account or a user stored in SQL Server. Both accounts are administrators of the collection with full control on it.
When I run the application, I get the usual window asking for the authentication mode I want. After being successfully connected with a user (both are working), I get : "The remote server returned an error: (403) Forbidden" on clientContext.ExecuteQuery().
var contextToken = TokenHelper.GetContextTokenFromRequest(Page.Request);
var hostWeb = Page.Request["SPHostUrl"];
using (var clientContext = new ClientContext(hostWeb))
{
clientContext.Load(clientContext.Web, web => web.Title);
clientContext.ExecuteQuery();
Response.Write(clientContext.Web.Title);
}
I should precise that, if I disable the FBA on the collection and only let the Windows authentication, it works like a charm.
What am I doing wrong ? Any idea ?
thanks for helping
public void Whatevermethod()
{
using (SP.ClientContext clientContext = new SP.ClientContext("http://server/collection"))
{
//Configure the handler to set FBA mode
clientContext.ExecutingWebRequest += new EventHandler<SP.WebRequestEventArgs>(ctx_MixedAuthRequest);
//Use the default mode to execute under the credentials of this process
clientContext.AuthenticationMode = SP.ClientAuthenticationMode.Default;
clientContext.Credentials = System.Net.CredentialCache.DefaultCredentials;
clientContext.ExecuteQuery();
}
}
private void ctx_MixedAuthRequest(object sender, SP.WebRequestEventArgs e)
{
try
{
//Add the header that tells SharePoint to use FBA
e.WebRequestExecutor.RequestHeaders.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
}
catch (Exception ex)
{
string error = ex.Message;
}
}
var hostWeb = Page.Request["SPHostUrl"];
using (var clientContext = new ClientContext(hostWeb))
{
clientContext.ExecutingWebRequest += new EventHandler<WebRequestEventArgs>(clientContext_ExecutingWebRequest);
clientContext.Load(clientContext.Web, web => web.Title);
clientContext.ExecuteQuery();
Response.Write(clientContext.Web.Title);
}
static void clientContext_ExecutingWebRequest(object sender, WebRequestEventArgs e)
{
e.WebRequestExecutor.WebRequest.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
}
Related
I have a console application that I published as webjob. The purpose of this webjob is to read the data from sharepoint site. It is working fine in local machine and I am able to read data.
However, after deploying it to Azure App service, it is not working.
Getting below error
[10/12/2017 04:00:43 > 60bc6a: INFO] Cannot contact site at the specified URL http://flic.farahleisure.com/Sites/FLFIN.
[10/12/2017 04:00:43 > 60bc6a: INFO] at Microsoft.SharePoint.Client.ClientContext.GetFormDigestInfoPrivate()
[10/12/2017 04:00:43 > 60bc6a: INFO] at Microsoft.SharePoint.Client.ClientContext.EnsureFormDigest()
[10/12/2017 04:00:43 > 60bc6a: INFO] at Microsoft.SharePoint.Client.ClientContext.ExecuteQuery()
Here is the code
using System;
using System.Configuration;
using System.Security;
using Microsoft.SharePoint.Client;
using System.Net;
using SP = Microsoft.SharePoint.Client;
namespace SampleApp
{
class Program
{
static void Main(string[] args)
{
try
{
using (ClientContext context = new ClientContext("http://flic.farahleisure.com/Sites/FLFIN"))
{
// Use default authentication mode
context.AuthenticationMode = ClientAuthenticationMode.Default;
context.Credentials = CredentialCache.DefaultNetworkCredentials;
// Specify the credentials for the account that will execute the request
context.Credentials = new NetworkCredential(GetSPOAccountName(), GetSPOSecureStringPassword(), GetSPODomainName());
ListCollection collList = context.Web.Lists;
context.Load(collList);
context.ExecuteQuery();
foreach (SP.List oList in collList)
{
Console.WriteLine("Title: {0}", oList.Title);
}
Console.WriteLine("Azure Web Job: Successfully completed.");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
Console.ReadKey();
}
}
}
Here is a good explanation:
You're most probably facing what is known as a "double-hop" issue:
Your client user connects and authenticate as himself against the Web app (through Windows NTLM protocol, that requires the client to know her/his password).
The Web app uses impersonation. It means the code runs under the user's identity.
With your context.Credentials = CredentialCache.DefaultNetworkCredentials, the call to SharePoint tries to authenticate with the user's identity, with NTLM. However, this requires the Web app to know the user's password: as it does not, the authentication fails (unless the client browses the Web app from the Web app server, in witch case it works fine).
Simplest solution here is to avoid impersonation at the Web app level (in the web.config); all requests to SharePoint will then be made Under the application pool's identity (that will require permissions under SharePoint, of course).
Another option I described here: Saving file from SharePoint Server to shared folder - Which user account?.
Please have a try to use SharePointOnlineCredentials, we also could get the demo code from the Use Microsoft Azure WebJobs with Office 365.
// Use default authentication mode.
context.AuthenticationMode = ClientAuthenticationMode.Default;
//context.Credentials = CredentialCache.DefaultNetworkCredentials;
context.Credentials = new SharePointOnlineCredentials(GetSPOAccountName(), GetSPOSecureStringPassword());
Update:
Please have a try to use username#domain, I test it on local or published on the Azure, both are working correctly on my side.
using (ClientContext context = new ClientContext("sharepoint url"))
{
// Use default authentication mode
context.AuthenticationMode = ClientAuthenticationMode.Default;
// Specify the credentials for the account that will execute the request
var secureString = new SecureString();
foreach (char c in "password")
{
secureString.AppendChar(c);
}
context.Credentials = new SharePointOnlineCredentials("username#domain", secureString); //example username :tom#tomtest.com
ListCollection collList = context.Web.Lists;
context.Load(collList);
context.ExecuteQuery();
foreach (var oList in collList)
{
Console.WriteLine("Title: {0}", oList.Title);
}
Console.WriteLine("Azure Web Job: Successfully completed.");
}
I am trying to authenticate using active directory and C#. The code is working on IIS Express under Visual Studio 15 but when I deploy my project to an IIS server, the LDAP connection returns the following error :
"The Supplied Credential is invalid"
Here is the code I am using:
public static dynamic AuthenticationUser(string username, string password)
{
bool validation;
try
{
var credentials = new NetworkCredential(username, password, "somedomain");
var serverId = new LdapDirectoryIdentifier("someserver");
LdapConnection conn = new LdapConnection(new LdapDirectoryIdentifier((string)null, false, false));
conn.Credential = credentials;
conn.AuthType = AuthType.Negotiate;
conn.Bind(credentials);
validation = true;
}
catch (LdapException ex)
{
validation = false;
return ex.Message;
}
Everything is OK when I debug with Visual Studio, I can verify and validate that the user exists on the AD server, but with IIS server the error occurs.
Update
I fixed this issue by disabling the domain controller on the IIS server.
I fixed this issue by disabling the domain controller on the IIS server.
We have a 3rd party web service that we consume from our web application. I've created a windows service that call this web service for all our customer, each of them with their own credentials.
The web service is using basic authentication.
When cycling through the credentials, it always uses the first authenticated credential.
Example code below:
private void testConnection(string username, string password)
{
_url = "https://somewebservice.com.au/transport/SomeService";
using (var someWebService = new someWebService {Url = _url})
{
var netCredential = new NetworkCredential(username, password);
var credential = new CredentialCache
{
{new Uri(someWebService.Url), "Basic", new NetworkCredential(username, password)}
};
someWebService.Credentials = credential;
someWebService.PreAuthenticate = true;
someWebService.Timeout = 1200000;
try
{
var result = someWebService.testConnection();
textBoxMsg.Invoke(new UpdateTextBoxDelegate(UpdateTextBox), result);
}
catch (SoapException soapex)
{
textBoxMsg.Invoke(new UpdateTextBoxDelegate(UpdateTextBox), "SOAP Error: " + soapex.Message + "\r\n");
}
catch (WebException webex)
{
textBoxMsg.Invoke(new UpdateTextBoxDelegate(UpdateTextBox), "Web Error: " + webex.Message + "\r\n");
}
catch (Exception ex)
{
textBoxMsg.Invoke(new UpdateTextBoxDelegate(UpdateTextBox), "Error: " + ex.Message + "\r\n");
}
finally
{
credential.Remove(new Uri(someWebService.Url), "Basic");
}
}
}
private void buttonTest2_Click(object sender, EventArgs e)
{
ThreadStart start = () => testConnection("user1", "123");
new Thread(start).Start();
}
private void buttonTest3_Click(object sender, EventArgs e)
{
ThreadStart start = () => testConnection("user2", "1234");
new Thread(start).Start();
}
if "user1" is authenticated first, second call to testConnection will always use "user1" credentials.
I've tried setting HttpWebRequest KeepAlive to false so connection is not re-used. TCP monitoring show the connection getting killed after setting it to false. This did not solve the issue.
If I close down the application and restart, and run testConnection for "user2", it gives the correct result.
Seems like the credentials are cached in the process. The only way to get rid of it is to exit the process.
This present some challenges when I have to cycle through about 1000 credentials.
Is there a way to clear the credential cache in process? If that is what's happening. See this link How to stop credential caching on Windows.Web.Http.HttpClient?
Options that I've explored and protoyped
Self hosted WCF accessing the web service. Another process that start and stop the WCF service for every credential
WCF service hosted in Windows Services - Another process that start and stop the windows service for every credential
Wait more than 10 mins for server side credential to expire. Not viable too slow.
My problem with the aboves are they have to be sequential, so to cycle through 1000 of them will take a while. Each credential will be around 20-30 secs.
Try using CredentialCache.Remove() method after your last catch block.
https://msdn.microsoft.com/en-us/library/4zaz5c95(v=vs.110).aspx
This will remove it from cache.
Maybe this is a bit old question, but you PreAuthenticate should be false for HttpClient not to cache the credentials.
I am trying to implement user authentication in my universal app (without using Mobile Services) as given in this article. However I am getting following error:
Cannot work with a MobileServiceClient that does not specify a gateway URI.
As I am not using mobile service for auth and doing it in client universal app, I am not sure what url goes here. Currently, "http://MyApp.azurewebsites.net" is the url for the backend app which I have in Azure Portal(Browse All > MyApp > Settings > url).
In my shared App.xaml.cs:
//Problem may be here as per my understanding
public static MobileServiceClient MobileService =
new MobileServiceClient("http://MyApp.azurewebsites.net");
In my shared MainPage.cs:
private async System.Threading.Tasks.Task AuthenticateAsync()
{
string message;
// This sample uses the Microsoft provider.
var provider = "MicrosoftAccount";
// Use the PasswordVault to securely store and access credentials.
PasswordVault vault = new PasswordVault();
PasswordCredential credential = null;
while (credential == null)
{
try
{
// Try to get an existing credential from the vault.
credential = vault.FindAllByResource(provider).FirstOrDefault();
}
catch (Exception)
{
// When there is no matching resource an error occurs,
// which we ignore.
}
if (credential != null)
{
// Create a user from the stored credentials.
user = new MobileServiceUser(credential.UserName);
credential.RetrievePassword();
user.MobileServiceAuthenticationToken = credential.Password;
// Set the user from the stored credentials.
App.MobileService.CurrentUser = user;
try
{
// Try to return an item now to determine
// if the cached credential has expired.
await App.MobileService
.GetTable<TodoItem>().Take(1).ToListAsync();
}
catch (MobileServiceInvalidOperationException ex)
{
if (ex.Response.StatusCode ==
System.Net.HttpStatusCode.Unauthorized)
{
// Remove the credential with the expired token.
vault.Remove(credential);
credential = null;
continue;
}
}
}
else
{
try
{
// Login with the identity provider.
// Here I am getting the exception.
user = await App.MobileService.LoginAsync(provider);
// Create and store the user credentials.
credential = new PasswordCredential(provider,
user.UserId, user.MobileServiceAuthenticationToken);
vault.Add(credential);
}
catch (MobileServiceInvalidOperationException ex)
{
message = "You must log in. Login Required";
}
}
message = string.Format("You are now logged in - {0}", user.UserId);
var dialog = new MessageDialog(message);
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();
}
}
So what is Gateway Uri, what I am doing wrong and how to implement authentication in app only without Azure Mobile Service (MVC project hosted on azure).
The App needs to have an associated gateway. For further reading, checkout this article on the Azure website. You will want to have code like this:
public static MobileServiceClient MobileService = new MobileServiceClient(
mobileAppUri: "https://mvp2015mobileapp.azurewebsites.net",
gatewayUri: "https://mvp2015b14929cfc35019b24a7daaf694.azurewebsites.net",
applicationKey: string.Empty);
Find an existing App Service gateway
From portal.azure.com, open your Mobile App, and click on its resource group link. Once the resource group blade opens, click on its summary panel. If you already have a Gateway, it will be in the list.
Create a new App Service gateway
From portal.azure.com, open your Mobile App, choose Settings, and then Mobile User Authentication. You will be able to create a new gateway from there. Here is a screen shot that shows where to create the Gateway (and also shows the Resource Group link.)
Retreive the gateway URL
Once you have found the gateway, you can grab its URL.
I am confused about publishing a post on facebook using C# sdk
I want to publish Name ,Description and photo on my page:
Do i need "publish_actions " in "items in review"(permissions)? because it is my own page .
When i try to add publish_actions ,facebook asks for privacy policy url ,How am i supposed to make it using C# Desktop Application, I didn't Found useful help on google.
Settings:
I have added http: //localhost:80/ to my site URL and:
http://abbasnaqvi512.tumblr.com/ to Valid OAuth redirect URIs.
Native or desktop app?=Yes
Is your App Secret embedded?=No
Client OAuth Login=yes
Embedded browser OAuth Login=NO
App Secret Proof for Server API calls=No
Require 2-factor reauthorization=No
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
try
{
if (e.Url.OriginalString.Contains("assets") && e.Url.OriginalString.Contains("code"))
{
code = Regex.Matches(e.Url.OriginalString, "assets.tumblr.com.*?code%3D(?<data>.*?)&")[0].Groups["data"].Value;
richTextBox1.Text += "\n\n" + code + "\n\n";
if (String.IsNullOrEmpty(code) == false)
{
webBrowser1.Stop();
webBrowser1.Dispose();
ShareOnFB();
}
}
}
catch (Exception)
{
}
}
private void ShareOnFB()
{
string pageId = "ABC";
FacebookClient client = new FacebookClient(code);
dynamic messagePost = new ExpandoObject();
messagePost.access_token = code;
messagePost.picture = "http://fc02.ostadreza-d6pkzrd.jpg";
// messagePost.link = "http://www.examplearticle.com";
messagePost.name = "NAME";
messagePost.description = "DESCRIPTION";
var result = client.Post(string.Format("/{0}/feed", pageId), messagePost);
richTextBox1.Text += "\n\n"+result+"\n\n";
}
Rightnow it is giving me Error
"Malformed access token AQA44CIJCyoV7_Xlz3mtvdPErPBrmtF6ykz6teCc9QINrfePHxEOiQKIyl8wgxH1mvQxEtLE-xnVfdyfiE38eA2M1YU7RS22MNIKNUh5wMmd2zwPCLj30PiEaq6CKIfcq9yIvq_slblOWmE4LYcynyH_pJuZcPc3EqLCQoCUBtSO58X1WtiohRoRvq70QWHpZec-7jhzUQnW75nlk4wpEwcJ9yOcBlPbne72sV6yX_hqndI5RKVDjqRJzdOscOblbLCkC1xtI0rMD1bCJufvpAa-tMsIyG6ATqrk6TNqXXASlcvialbzh0WttS2x-j_J59LF7cBh22T18P8qOly5cOwF"
Thanks for reading my question ,Kindly help me,
Update: I have added publish_actions in review by adding tumblr privacy policy url ,Notes and screen shots of my application ,It is on review