EWS GetUserPhoto switch from Basic Auth to OAuth - c#

I have been using Basic Auth to get user photo as below.
string email = "SomeEmail#email.com";
HttpWebRequest request = WebRequest.Create(string.Format("https://outlook.office365.com/EWS/Exchange.asmx/s/GetUserPhoto?email={0}&size=HR648x648", email)) as HttpWebRequest;
request.Credentials = new NetworkCredential("SomeID", "SomePwd");
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
Stream stream = response.GetResponseStream();
using (MemoryStream ms = new MemoryStream())
{
string encodedPhoto = Convert.ToBase64String((ms.ToArray()));
}
}
But since Basic Authentication for EWS will be decommissioned, I'm trying to use OAuth 2.0 for the same request. This is what I've tried so far.
var pcaOptions = new PublicClientApplicationOptions
{
ClientId = ConfigurationManager.AppSettings["appId"],
TenantId = ConfigurationManager.AppSettings["tenantId"]
};
var pca = PublicClientApplicationBuilder.CreateWithApplicationOptions(pcaOptions).Build();
var ewsScopes = new string[] { "https://outlook.office365.com/EWS.AccessAsUser.All" };
var authResult = await pca.AcquireTokenInteractive(ewsScopes).ExecuteAsync();
var ewsClient = new ExchangeService();
string email = "SomeEmail#Email.com";
ewsClient.Url = new Uri(string.Format("https://outlook.office365.com/EWS/Exchange.asmx/s/GetUserPhoto?email={0}&size=HR648x648", email));
ewsClient.Credentials = new OAuthCredentials(authResult.AccessToken);
How can I proceed to get user photo from here? Any help or information will be very much appreciated.

You don't need to use the EWS Managed API you can just modify you existing code to include the Access token eg
string email = "SomeEmail#email.com";
HttpWebRequest request = WebRequest.Create(string.Format("https://outlook.office365.com/EWS/Exchange.asmx/s/GetUserPhoto?email={0}&size=HR648x648", email)) as HttpWebRequest;
request.Headers.Add("Authorization", "Bearer " + authResult.AccessToken);
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
Stream stream = response.GetResponseStream();
using (MemoryStream ms = new MemoryStream())
{
string encodedPhoto = Convert.ToBase64String((ms.ToArray()));
}
}
or if you do want to use the EWS managed API you can use something like
String ETag = "";
GetUserPhotoResults grPhoto = service.GetUserPhoto("user#domain.com", "HR240x240", ETag);
if (grPhoto.Status == GetUserPhotoStatus.PhotoReturned)
{
ETag = grPhoto.EntityTag;
}
grPhoto = service.GetUserPhoto("user#domain.com", "HR240x240", ETag);
switch (grPhoto.Status)
{
case GetUserPhotoStatus.PhotoReturned: ETag = grPhoto.EntityTag;
break;
case GetUserPhotoStatus.PhotoUnchanged:
Console.WriteLine("Photo Unchanged");
break;
}

I would recommend you to use Microsoft Graph API to get User Photo. Refer, https://learn.microsoft.com/en-us/graph/api/profilephoto-get?view=graph-rest-1.0
Try it out using Graph Explorer
https://developer.microsoft.com/en-us/graph/graph-explorer?request=me%2Fphoto%2F%24value&method=GET&version=v1.0&GraphUrl=https://graph.microsoft.com
Get started with Graph .Net SDK
https://learn.microsoft.com/en-us/graph/sdks/sdks-overview
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
var stream = await graphClient.Me.Photo.Content
.Request()
.GetAsync();

Related

OneDrive upload files with REST API via resumable session

Hi there currently I am trying to make files uploading to one drive trough REST API. But every time I am getting Exception with 401 code for non authorized
The remote server returned an error: (401) Unauthorized.
My code snippet
public async Task<string> UploadFileAsync(Account account, StorageFile file)
{
var publicClientApplication = PublicClientApplicationBuilder.Create(MicrosoftConstants.ClientId)
.WithRedirectUri(MicrosoftConstants.RedirectUri)
.Build();
var scopes = new string[]
{
"files.readwrite.all"
};
AuthenticationResult authToken = null;
try
{
authToken = await publicClientApplication.AcquireTokenInteractive(scopes).ExecuteAsync();
}
catch (Exception)
{
}
if (authToken != null)
{
var postData = new
{
item = new
{
name = file.Name
}
};
var json = JsonConvert.SerializeObject(postData);
var request = (HttpWebRequest)WebRequest.Create($"https://graph.microsoft.com/v1.0/me/drive/items/root:/{file.Name}:/createUploadSession");
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength= json.Length;
request.Headers["Authorization"] = "bearer" + authToken.AccessToken;
using (var requestStream = await request.GetRequestStreamAsync())
using (var streamWriter = new StreamWriter(requestStream))
{
streamWriter.Write(json);
}
var response = (HttpWebResponse)await request.GetResponseAsync();
}
return string.Empty;
}
Do anybody know what am I doing wrong?
To make it work I had to change header with authorization to
request.Headers["Authorization"] = "Bearer " + authToken.AccessToken;

I'm looking for to generate access token using azure credentials in c#

I'm looking for to generate access token using azure credentials in c#. This is my code but its not working.With this i'm facing Unexpected character '<' error.
var uri = $"https://login.microsoftonline.com/common/oauth2/token";
var parameters = new Dictionary<string, dynamic>()
{
["grant_type"] = "password",
["client_id"] ="Azure client id"
["username"] = "CRM User name",
["password"] = "CRM Passowrd",
["client_secret"] ="Azure Client app scret"
["resource"] = "Your CRM Url",
};
var request = WebRequest.CreateHttp(uri);
request.Method = "POST";
var body = Encoding.ASCII.GetBytes(parameters.UrlEncode());
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = body.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(body, 0, body.Length);
}
using (var response = request.GetResponse())
using (var stream = response.GetResponseStream())
{
var serializer = new DataContractJsonSerializer(typeof(Token));
return serializer.ReadObject(stream) as Token;
}
Here is an example of how a crm token is retreived using postman < you can applythis in your c# code. but get this right first:
also make sure that Azure Active directory > application has the above reply url and dynamics security assigned (api permissions).

Upload video on Twitter without 3rd library

I use Hammock in the project and I want to upload videos to Twitter. I also get the "media type unrecognized" error when I try with the following code. Where part am I doing wrong?
var restClient = new Hammock.RestClient
{
Authority = "https://upload.twitter.com",
Encoding = Encoding.UTF8,
};
var restRequest = new Hammock.RestRequest
{
Credentials = credentials,
Path = "/1.1/media/upload.json",
Method = Hammock.Web.WebMethod.Post,
Encoding = Encoding.UTF8,
};
Stream stream = new MemoryStream(images);
restRequest.AddFile("media", "test", stream);
var asyncResult = restClient.BeginRequest(restRequest);
var response = restClient.EndRequest(asyncResult);
var jsonData = JsonConvert.DeserializeObject<Image>(response.Content);

Bot work in local but not in azure

I'm working on a chat bot that help users of a SharePoint on premise network to upload a file. The bot works on local but returns code 500 when tested in Azure.
I'm using Csom library to navigate in the site tree and the SharePoint _api to get all site collections. I have done some test and I don't think that is the Csom that causes this bug, but rather it is the NetworkCredential that doesn't work in Azure.
So can I use credential in Azure ?
I know that the problem comes from this function
public void GetAllSiteCollections(string url)
{
HttpWebRequest endpointRequest = (HttpWebRequest)HttpWebRequest.Create(url + "/_api/search/query?querytext='contentclass:sts_site'&trimduplicates=false&rowlimit=100");
endpointRequest.Method = "GET";
endpointRequest.Accept = "application/json;odata=verbose";
NetworkCredential cred = new NetworkCredential(Login, Mdp, DomaineUser);
endpointRequest.Credentials = cred;
HttpWebResponse endpointResponse = (HttpWebResponse)endpointRequest.GetResponse();
WebResponse webResponse = endpointRequest.GetResponse();
Stream webStream = webResponse.GetResponseStream();
StreamReader responseReader = new StreamReader(webStream);
string response = responseReader.ReadToEnd();
JObject jobj = JObject.Parse(response);
for (int ind = 0; ind < jobj["d"]["query"]["PrimaryQueryResult"]["RelevantResults"]["Table"]["Rows"]["results"].Count(); ind++)
{
string urlCollection = jobj["d"]["query"]["PrimaryQueryResult"]["RelevantResults"]["Table"]["Rows"]["results"][ind]["Cells"]["results"][6]["Value"].ToString();
string nomCollection = jobj["d"]["query"]["PrimaryQueryResult"]["RelevantResults"]["Table"]["Rows"]["results"][ind]["Cells"]["results"][3]["Value"].ToString();
if (urlCollection.Contains("myLocalDomain/sites/") == true)
{
string[] split = urlCollection.Split('/');
ClientCtx = new ClientContext(Domaine + "/sites/" + split[4]);
using (ClientCtx = new ClientContext(ClientCtx.Url))
{
ClientCtx.Credentials = new NetworkCredential(Login, Mdp, DomaineUser);
Web rootWeb = ClientCtx.Site.RootWeb;
ClientCtx.Load(rootWeb);
BasePermissions bp = new BasePermissions();
bp.Set(PermissionKind.AddListItems);
ClientResult<bool> viewListItems = rootWeb.DoesUserHavePermissions(bp);
ClientCtx.ExecuteQuery();
if (viewListItems.Value)
{
ListDesSiteCollections.Add(nomCollection, split[4]);
}
}
}
}
responseReader.Close();
}
When I check the logs at http://botName.azurewebsites.net/api/messages I get the response "The requested resource does not support http method 'GET'"

C# Add item to Sharepoint list using REST API

I would like to add an item to a list in sharepoint using below code:
protected string httpGetPost(string getPostMode, string url, string dataToPost = "")
{
HttpWebRequest endpointRequest = (HttpWebRequest)WebRequest.Create(url);
endpointRequest.Method = getPostMode;
var credentialCache = new CredentialCache();
credentialCache.Add(
new Uri(endpointRequest.RequestUri.GetLeftPart(UriPartial.Authority)), // request url's host
"Digest", // authentication type
new NetworkCredential(userName, password) // credentials
);
endpointRequest.Credentials = credentialCache;
endpointRequest.Accept = "application/json;odata=verbose";
endpointRequest.ContentType = "application/json;odata=verbose";
if (!string.IsNullOrEmpty(dataToPost))
{
using (Stream dataStream = endpointRequest.GetRequestStream())
{
byte[] bs = Encoding.ASCII.GetBytes(dataToPost);
dataStream.Write(bs, 0, bs.Length);
}
}
using (var resp = endpointRequest.GetResponse())
{
var html = new StreamReader(resp.GetResponseStream()).ReadToEnd();
return html;
}
}
And call the above method using below code:
httpGetPost("POST", url, "{\"__metadata\": { \"type\": \"SP.Data.Test_x0020_ListListItem\" }, \"Title\": \"Test\", \"Column B\", \"BBB\"}");
Here's the data I'm posting:
{"__metadata": { "type": "SP.Data.Test_x0020_ListListItem" }, "Title":
"Test", "Column B", "BBB"}
I've took a look at this website https://msdn.microsoft.com/en-us/library/office/dn292552.aspx, but the authorization is different, it's using an accesstoken, but here's the problem:
In this website: http://sharepoint.stackexchange.com/questions/69617/sharepoint-2013-oauth-url-to-get-token, it saids I can't get the accesstoken, so I used username and password to login the sharepoint, but here comes another problem:
A System.Net.WebException is thrown in var resp = endpointRequest.GetResponse(), the error is saying The remote server returned an error: (403) Forbidden.
The account is a domain admin as well as a sharepoint admin.
Why I'm still getting the 403 error?
For some reasons, I can only use the REST API to communicate with sharepoint.
Here is a slightly different method to achieve your goals. Some of the objects are specific to Store Apps in this example, but they can all easily be replaced with other values in a standard app.
public string digest()
{
String retVal = "";
try
{
string url = "https://YourSite.com/";
HttpClient client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true });
client.BaseAddress = new System.Uri(url);
string cmd = "_api/contextinfo";
client.DefaultRequestHeaders.Add("Accept", "application/json;odata=verbose");
client.DefaultRequestHeaders.Add("ContentType", "application/json");
client.DefaultRequestHeaders.Add("ContentLength", "0");
StringContent httpContent = new StringContent("");
var response = client.PostAsync(cmd, httpContent).Result;
if (response.IsSuccessStatusCode)
{
string content = response.Content.ReadAsStringAsync().Result;
JsonObject val = JsonValue.Parse(content).GetObject();
JsonObject d = val.GetNamedObject("d");
JsonObject wi = d.GetNamedObject("GetContextWebInformation");
retVal = wi.GetNamedString("FormDigestValue");
}
}
catch
{ }
return retVal;
}
FileOpenPicker picker = new FileOpenPicker();
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
picker.ViewMode = PickerViewMode.Thumbnail;
// Filter to include a sample subset of file types.
picker.FileTypeFilter.Clear();
picker.FileTypeFilter.Add(".bmp");
picker.FileTypeFilter.Add(".png");
picker.FileTypeFilter.Add(".jpeg");
picker.FileTypeFilter.Add(".jpg");
// Open the file picker.
StorageFile path = await picker.PickSingleFileAsync();
if (path != null)
{
string url = "https://YourSite.com/Subsite/";
HttpClient client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true });
client.BaseAddress = new System.Uri(url);
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add("Accept", "application/json;odata=verbose");
client.DefaultRequestHeaders.Add("X-RequestDigest", digest());
client.DefaultRequestHeaders.Add("X-HTTP-Method", "POST");
client.DefaultRequestHeaders.Add("binaryStringRequestBody", "true");
IRandomAccessStream fileStream = await path.OpenAsync(FileAccessMode.Read);
var reader = new DataReader(fileStream.GetInputStreamAt(0));
await reader.LoadAsync((uint)fileStream.Size);
Byte[] content = new byte[fileStream.Size];
reader.ReadBytes(content);
ByteArrayContent file = new ByteArrayContent(content);
HttpResponseMessage response = await client.PostAsync("_api/web/lists/getByTitle(#TargetLibrary)/RootFolder/Files/add(url=#TargetFileName,overwrite='true')?#TargetLibrary='Project Photos'&#TargetFileName='TestUpload.jpg'", file);
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
{ }
}

Categories