Sharepoint with MFA not allowing access - c#

We use Multi-factor authentication on our Sharepoint. We are trying to download some documents from sharepoint to manipulate in our application. I have tried to access the sharepoint using both the "traditional" method as well as trying to go thru our Azure AD. Both methods dont allow us to access the sharepoint - we get permission denied
Any help would be greatly appreciated
This is what i have tried already - going thru AD
string clientId = "xxx";
string clientSecret = "yyy";
string tenant = "zzz";
AuthenticationResult result = null;
var data = AzureAdOptions.Settings.Authority;
AuthenticationContext authContext = new
AuthenticationContext(AzureAdOptions.Settings.Authority);
ClientCredential credential = new
ClientCredential(AzureAdOptions.Settings.ClientId,
AzureAdOptions.Settings.ClientSecret);
result = await
authContext.AcquireTokenAsync(AzureAdOptions.Settings.PreceptWebApiResourceId, credential);
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
HttpResponseMessage response = await client.SendAsync(request);
and then the more "traditional way"
WebRequest request = WebRequest.Create("https://my.sharepoint.com:/sites/files/");
string userName = "mylogon";
string password = "#!";
var securePassword = new SecureString();
foreach (char c in password)
{
securePassword.AppendChar(c);
}
request.Credentials = new NetworkCredential(userName, securePassword);
String encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(userName + ":" + password));
request.Headers.Add("Authorization", "Basic " + encoded);
WebResponse response = request.GetResponse();

Replace the line of code below
request.Credentials = new NetworkCredential(userName, securePassword);
with
request.Credentials = new SharePointOnlineCredentials(userName, securePassword);
Or using SharePointPnPCoreOnline.
var authManager = new AuthenticationManager();
var ctx = authManager.GetWebLoginClientContext("https://contoso.sharepoint.com/");
Refer to: CSOM.MFA.cs

Related

MCAS REST API Limit issues(nextQueryFilters)

I am trying to collect Microsoft Defender for Cloud Activity Log using C#.
If you look at the Python example, the value of the nextQueryFilters item should be entered as a filter.
But when I run it in C# and check the test result, the items in nextQueryFilters themselves are not retrieved.
Please check if there is a problem with my code.
string tenantId = "mytenantId";
string appId = "myappId";
string appSecret = "myappSecret";
const string authority = "https://login.microsoftonline.com";
const string MCASResourceId = "myMCASResourceId";
AuthenticationContext auth = new AuthenticationContext($"{authority}/{tenantId}/");
ClientCredential clientCredential = new ClientCredential(appId, appSecret);
AuthenticationResult authenticationResult = auth.AcquireTokenAsync(MCASResourceId, clientCredential).GetAwaiter().GetResult();
string token = authenticationResult.AccessToken;
var httpClient = new HttpClient();
bool hasNextPage = false;
do
{
Url = "https://url.portal.cloudappsecurity.com/api/v1/activities/?filters={\"date\":{ \"gte_ndays\":1}}&isScan:True";
using (var request = new HttpRequestMessage(HttpMethod.Post, Url))
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
using (HttpResponseMessage respose = httpClient.SendAsync(request).GetAwaiter().GetResult())
{
string json = respose.Content.ReadAsStringAsync().Result;
}
}
} while (hasNextPage);

How to read API secured with username and password in ASP.NET Core MVC

I have an API that is secured with username and password. I'm using ASP.NET Core MVC but I'm reading the API using JavaScript. Now my organization secured this API with username and password and I want to know how can I read the API with these username and password using C# because it's more secure than JavaScript. What code I can Add in my Post request in the controller. If you can guide me to a way to achieve this.
I found this way but it's not supported in ASP.NET Core:
WebRequest req = WebRequest.Create(#"https://sub.domain.com/api/operations?param=value&param2=value");
req.Method = "GET";
req.Headers["Authorization"] = "Basic " +
Convert.ToBase64String(Encoding.Default.GetBytes("username:password"));
//req.Credentials = new NetworkCredential("username", "password");
HttpWebResponse resp = req.GetResponse() as HttpWebResponse;
for net core it is better to use http client
using (var client = new HttpClient())
{
var baseAddress = "https://sub.domain.com";
var api = "/api/operations?param=value&param2=value";
client.BaseAddress = new Uri(baseAddress);
var contentType = new MediaTypeWithQualityHeaderValue("application/json");
client.DefaultRequestHeaders.Accept.Add(contentType);
var authenticationString = $"{username}:{password}";
var base64EncodedAuthenticationString = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(authenticationString));
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", base64EncodedAuthenticationString);
var response = await client.GetAsync(api);
var statusCode = response.StatusCode.ToString();
if (response.IsSuccessStatusCode)
{
var stringData = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<object>(stringData);
}
}
UPDATE
If you wont to use http client but use ajax too, just create an action with the code above and call this action from ajax.

sharepoint rest api credentials

I'm triggering an external web page outside of sharepoint which needs to read lists using the sharepoint web api.
HttpWebRequest endpointRequest = (HttpWebRequest)HttpWebRequest.Create(sharepointUrl.ToString() + "/_api/web/lists");
endpointRequest.Method = "GET";
endpointRequest.Accept = "application/json;odata=verbose";
//endpointRequest.Headers.Add("Authorization", "Bearer " + accessToken);
HttpWebResponse endpointResponse = (HttpWebResponse)endpointRequest.GetResponse();
I can access the API using chrome if I'm logged in but I suspect I need the access token line.. but can't seem to find a way to populate it.
Currently it returns:
No connection could be made because the target machine actively refused it...
You need to set credential of HttpWebRequest.
Here you go:
HttpWebRequest endpointRequest = (HttpWebRequest)HttpWebRequest.Create(sharepointUrl.ToString() + "/_api/web/lists");
string password = "XXXXX";
string userName = "XXXX";
SecureString secureString = new SecureString();
foreach (char c in password.ToCharArray())
{
secureString.AppendChar(c);
}
endpointRequest.Credentials = new SharePointOnlineCredentials(userName, secureString);
//.........
If you are using SharePoint online, it can work with my answer above because i have tested.
If you are using SharePoint 2013/2010/2016, the code will be as below.
HttpWebRequest endpointRequest = (HttpWebRequest)HttpWebRequest.Create(sharepointUrl.ToString() + "/_api/web/lists");
string password = "XXXXX";
string userName = "XXXX";
string domain = "XXX"
endpointRequest.Credentials = new NetworkCredential(userName, password, domain);
//.........

Not getting access_token by calling https://login.microsoftonline.com/{tenant}/oauth2/token

I want to get user email from user id (object identifier) from web api, but getting blank response while calling api for token. I am running this code from my Web API. Please help. Below is the code.
Given full permission to APIs
Getting Blank response in below line.
var responseBytes = await webClient.UploadValuesTaskAsync(url, "POST", requestParameters);
Below is code
var tenant = "tenant ID";
var clientID = "app ID";
// I've tried graph.microsoft.com and graph.microsoft.com/.default
var resource = "https://graph.microsoft.com";
var secret = "client secret";
string token;
using (var webClient = new WebClient())
{
var requestParameters = new NameValueCollection();
requestParameters.Add("scope", resource);
requestParameters.Add("client_id", clientID);
requestParameters.Add("grant_type", "client_credentials");
requestParameters.Add("client_secret", secret);
var url = "https://login.microsoftonline.com/{tenant}/oauth2/token";
webClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
var responseBytes = await webClient.UploadValuesTaskAsync(url, "POST", requestParameters);
var responseBody = Encoding.UTF8.GetString(responseBytes);
var jsonObject = Newtonsoft.Json.JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JObject>(responseBody);
token = jsonObject.Value<string>("access_token");
}
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
var response = await client.GetAsync(new Uri("https://graph.microsoft.com/v1.0/user/" + ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier")));
Your error is here:
requestParameters.Add("scope", resource);
It needs to be resource rather than scope:
requestParameters.Add("resource", resource);
Can you help me understand what documentation or tutorial you followed to make this mistake? I have seen it happen before and I am trying to understand the patterns here.
The documentation and authentication flow you should be following is here.

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

Categories

Resources