Microsoft.Graph.ServiceException when trying to download user image - c#

I have a really frustrating issue, where all I want to do is get user images from O365 and simply display them on my web page, which is hosted on Azure azpp service.
As you can see from this SO and this SharePoint.StackExchange question, The images fail to load when simply trying to display the link taken from SharePoint in an <img> tag.
However, after navigating to the image in a a new tab, and refreshing my page, the iamges load fine. can anyone explain this behaviour? it makes no sense to me at all
Anyways since that just dont work for whatever reason (logged in user clearly has the right permissions, as the images do disaply after navigating to them),
I thought I would try downloading the images using graph API.
SO I downloaded the quick start project and trying to download the iamges with
public async Task<Stream> TestAsync(GraphServiceClient graphClient)
{
var users = graphClient.Users;
var jk = users["user.name#domain.com"];
return await jk.Photo.Content.Request().GetAsync();
}
But I just get
Exception of type 'Microsoft.Graph.ServiceException' was thrown.
Yet when I try to view the same image in the API graph explorer, I can download the image. Please can someone just help me to display SharePoint user images in my web page without the user having to first navigate to the image directly.. Why must it be so difficult?

Once you have a valid token, make sure your permission scopes include User.Read.All, for example:
The query:
var user = graphClient.Users["<userPrincipalName>"];
corresponds to the following endpoint
Url: /users/{userPrincipalName}
Method: GET
which requires User.Read.All scope, see permission section for a more details.
In addition, in case of access without a user token requires Administrative Consent before it can be used.
Example
var users = graphClient.Users;
var user = users[accountName];
var photo = await user.Photo.Content.Request().GetAsync() as MemoryStream;
using (var file = new FileStream("./user.jpg", FileMode.Create, FileAccess.Write))
{
if (photo != null) photo.WriteTo(file);
}

Related

Authenticate GET requests to files in a folder C# MVC

I have a web site (IIS, C#.Net, MVC4) where users are (forms-)authenticated and they upload media files (mostly .mp4) and authorize set of users to play back on demand. I store these files on local storage.
I play these files using jwplayer back to the authorized users on demand.
jwplayer expects I pass the url directly for it to play, but I didn't want to expose a direct url.
I really have to restrict unauthorized access to these files as they are private files.
I tried implementing a controller method to handle https://mysite/Video/Watch?VideoId=xyz, and return FileStream of the actual file. It works on a browser directly. (Though not sure how efficient it is for large files.)
But the problem is, jwplayer looks for urls of pattern http(s)://domain/path/file.mp4[?parameter1=value1&parameter2=value2 and so on.]
When I give a url like https://mysite/Video/Watch?VideoId=xyz, it says 'No playable sources found' without even sending a HEAD request.
If I expose the urls directly, the files are available for anybody to download, which will break the privacy.
Worst case, I would at least want to avoid hot links which will live for ever.
I have also looked at www.jwplayer.com/blog/securing-your-content/ but did not find the solutions suitable.
My questions are,
Is there a way I can retain the pattern of the url http(s)://domain/path/file.mp4 and still control the access to the file?
If (1.) is not possible, how do I leverage the parameters that could be passed on the url. With the parameters, I can think of signed urls. What should I do on the server if I have to provide and handle/validate signed urls.
Just not to hinder the performance, after any validation, can I somehow get the iis to handle the filestream rather my code?
I implemented an HTTPModule to allow/block access to the file. This addresses my questions 1 & 3.
Code snippet below.
void context_PreRequestHandlerExecute(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
//Get the file extension
string fileExt= Path.GetExtension(app.Request.Url.AbsolutePath);
//Check if the extension is mp4
bool requestForMP4 = fileExt.Equals(".mp4", StringComparison.InvariantCultureIgnoreCase);
//If the request is not for an mp4 file, we have nothing to do here
if (!requestForMP4)
return;
//Initially assume no access to media
bool allowAccessToMedia = false;
//....
// Logic to determine access
// If allowed set allowAccessToMedia = true
// otherwise, just return
//....
if(!allowAccessToMedia)
{
//Terminate the request with HTTP StatusCode 403.2 Forbidden: Read Access Forbidden
app.Response.StatusCode = (int)HttpStatusCode.Forbidden;
app.Response.SubStatusCode = 2;
app.CompleteRequest();
}
}

Using Facebook API to access public group event data

I'm developing a public website and what I want to do is pretty straightforward, but I'm pulling my hair out trying to get everything working right.
I administer an open Facebook group and I want to display the public facebook events of this group on my website.
I can't seem to figure out how to setup my authentication so that I can access the event data. Here is my code for using my application to get an auth token:
var fb = new FacebookClientWrapper();
dynamic result = fb.Get("oauth/access_token", new
{
client_id = AppSettings.AppID,
client_secret = AppSettings.AppSecret,
grant_type = "client_credentials"
});
fb.AccessToken = result.access_token;
I know this works fine because I can access some information - for example, if I access a specific event by its ID, I can retrieve that information.
The problem occurs when I try to retrieve a list of events with fields within a date range:
[HttpGet]
public object GetEventDetails(string unixStartDateTime, string unixEndDateTime)
{
var parms = new Dictionary<string, object>();
parms.Add("fields", new[] { "id","name","description","start_time","venue" });
if (!String.IsNullOrEmpty(unixStartDateTime)) { parms.Add("since", unixStartDateTime); }
if (!String.IsNullOrEmpty(unixEndDateTime)) { parms.Add("until", unixEndDateTime); }
var eventsLink = String.Format(#"/{0}/events", AppSettings.GroupID);
return ObjectFactory.GetInstance<IFacebookClient>().Get(eventsLink,parms);
}
(I'm aware that even if this did succeed, the return value wouldn't be serializable - I'm not concerned about that quite yet).
This GET request returns the following message:
(OAuthException - #102) A user access token is required to request this resource.
So the message is quite clear: I need a user access token to get the data I've requested. The question is - what is the best way to do this? Can I give my application a certain permission to read this data? I've looked over all the permissions available to apps, but I don't see one that would do the trick.
I don't want to require people to log onto Facebook to look at public event data, and I love the idea of allowing people with no technical experience to essentially update the website content by posting Facebook events to the group. Right now, I have to duplicate anything they do.
I would think this kind of application would be very common, but no matter what I've read or tried, I can't quite find an example of the same thing that works.
From the docs at https://developers.facebook.com/docs/graph-api/reference/v2.0/group/events you need
A user access token for a member of the group with user_groups permission.
To avoid the hassle, you could create such an Access Token via the Graph Explorer and then store it in your application. Remember to exchange that Access Token to a long-lived one (https://developers.facebook.com/docs/facebook-login/access-tokens/#extending), and that you have to renew the Access Token every 60 days afterwards.

Post Media to User/Page Wall in Facebook with C# SDK

I'm using Facebook .Net SDK(http://facebooksdk.net/) in my application. I need post an image to the wall of the user or his page.
I have this piece of code to try do this:
var postUrl = "<fbid>/feed";
var fbParameters = new Dictionary<string,object>();
fbParameters["message"] = postRequest.FacebookPostContent;
if (postRequest.MediaData != null && postRequest.MediaData.Length > 0)
{
var stream = new MemoryStream(postRequest.MediaData);
if (postRequest.ContentType.Equals("image/jpeg"))
{
postUrl = postUrl.Replace("/feed", "/photos");
fbParameters["picture"] = new FacebookMediaStream { ContentType = postRequest.ContentType, FileName = DateTime.UtcNow.ToString("ddmmyyyyhhmmss") + "-photo.jpeg" }.SetValue(stream);
}
}
if (!string.IsNullOrWhiteSpace(postRequest.FacebookPageId))
{
fbUserID = postRequest.FacebookPageId;
}
postUrl = postUrl.Replace("<fbid>", fbUserID);
var result = await facebookClient.PostTaskAsync(postUrl, fbParameters);
Look at my postUrl variable. I update the with the user ID in Facebook or the PageID if it is a page so the post should be properly posted in the right object. If there is some image to upload, so add it to the dictionary.
So, with it in mind, I have the following questions:
When the fbUserID is a user ID, the post happens perfectly, with the image and description but, when the ID is a PageID, only the description text is posted and image is just ignored(the user has the manage_page permissions so I dont think it is a permission issue). What I'm doing wrong that the image is not being posted to the page's wall?
If I want to post a video instead of a image, what should I change in this code?
Already saw many problems with other technologies here in SO but never a conclusive solution.
Thank you very much for the help, I really appreciate.
Regards,
Gutemberg
Got it!
Facebook creates a different section inside the page called Recent Posts by Others on Test Page where people allowed to post images will be there, like an attachment icon. In order to post directly to the page's feed/wall, all I need to do is instead of use the user access_token(even if user granted manage_pages permission) just use the access_token that comes in /me/accounts object for the respective page.
About the video post, I just set the ContentType to "video/mpeg" and at server instead of set picture parameter on dictionary, I've set the video field with the video byte[].
Thanks!
Regards,
As an alternative you could try the Share Content button shown in one of the answers here:
Upload video on Facebook using Graph REST API on Windows Phone 8.1
I found that to be easier than tackling authorization and manually posting.

Display User Picture in Lync 2013

I am working on small application using the lync 2013 sdk. Is there any way provided in sdk where I can implement a functionality to allow user to upload his picture using any API provided in the SDK.
If it is possible then what and where is the best way to store it, if the users are configured in the active directory?
Waiting for a positive response from your side.
Regards
Amit
You can get a stream to the photo via the SDK using
var photoStream = Client.Self.Contact.GetContactInformation(ContactInformationType.Photo) as System.IO.Stream
And whilst you can read the stream you can't write to it as you are at this point looking at contact information from AD.
Kind of feels like you want to write something to change the photo in the photoThumbnails attribute of AD not in Lync.
Update as of 12/11/2013
The latest Lync update (Lync Client CU3 (November Update)) has the option to set a photo added back to the GUI.
Link to the KB Article
Link to the Download
Article with explanations and screenshots can be found here: Lync Client CU3 (November Update) – Show a picture from a website!.
Original Answer
Though this is a different problem, my answer to this question (Displaying a photo for an Application endpoint) is valid here as well:
Basicly, there is an option to set a user's photo to an URL, but it is no longer displayed in the Lync 2013 client interface (it was there in the Lync 2010 client). If you can get your code to publish the image to a web-accessible location, you could publish the URL to it and change your user picture that way.
For reference, the answer to the other question:
Publishing presence information (which includes photo settings) is done on the LocalEndpoint.LocalOwnerPresence. Both UserEndpoint and ApplicationEndpoint derive from LocalEndpoint, so this should be doable really.
The actual publishing gets slightly complex because there are a lot of different combinations of 'levels' to publish on:
First, there are a bunch of InstanceID values that you need to know about, read up on them here: Presence data source and category instance ID
Second, there is a value for who this presence applies to, see Microsoft.Rtc.Collaboration.Presence.PresenceRelationshipLevel. Don't publish on Unknown, you'll get an exception.
public enum PresenceRelationshipLevel
{
Unknown = -1,
Everyone = 0,
External = 100,
Colleagues = 200,
Workgroup = 300,
Personal = 400,
Blocked = 32000,
}
You need to publish a PresenceCategoryWithMetaData for the user photo properties, which is part of container 0x5, "Presentity information".
var photoPresence = new PresenceCategoryWithMetaData(
0x5, // The container id
(int)PresenceRelationshipLevel.Everyone,
new ContactCard(0x5) // Same container ID again
{
IsAllowedToShowPhoto = true,
PhotoUri = "<uri to your photo here"
});
You can set an ExpiryPolicy on this object too, should be self explainatory really. Then publish this presence object on your endpoint:
Endpoint.LocalOwnerPresence.BeginPublishPresence(new[] { photoPresence }, cb => {
Endpoint.LocalOwnerPresence.EndPublishPresence(cb);
}, null);
And that should do it, really. I ended up explicitly publishing to all relationship levels because it didn't cascade the data as logically expected.

C#/ASP.NET Selenium WebDriver - Re-using Cookies

I want to:
Login to a website
Save Cookies
Give user a choice to do A, B or C
A,B and C all require being logged in.
Each will open a FirefoxDriver and do their own thing
What i want to do, is login ONCE, save the cookies from that, and add them to any other FirefoxDriver i want to open.
Right now I'm trying to save the cookies in
public ReadOnlyCollection<Cookie> Cookies { get; set; }
which is the result of
WebDriver.Manage().Cookies.AllCookies;
Assuming login worked and cookies were saving in the above, I have this:
WebDriver = new FirefoxDriver();
WebDriver.Navigate().GoToUrl("http://www.example.com");
if (cookies != null)
{
var s = WebDriver.Manage().Cookies; //Logged out cookies
WebDriver.Manage().Cookies.DeleteAllCookies(); //Delete all of them
var sd = WebDriver.Manage().Cookies; //Make sure theyre deleted
foreach (var cookie in cookies)
{
WebDriver.Manage().Cookies.AddCookie(cookie);
}
var ss = WebDriver.Manage().Cookies;
WebDriver.Navigate().GoToUrl("http://example.com/requiresloginpage");
}
The problem is, howevering over "ss" in this case, gives this exception error
AllCookies = 'ss.AllCookies' threw an exception of type
'OpenQA.Selenium.WebDriverException'
base {System.Exception} = {"Unexpected problem getting cookies"}
InnerException = {"Cookie name cannot be null or empty string\r\nParameter name: name"}
I'm passing 8 cookies (total number when youre logged in) - and all of them seem set and ok. Not sure what I'm doing wrong
In order to save cookies, you should tell selenium to use a specified profile. For some reason I can't get it to use my normal Chrome profile, but this solution will allow you to log in one time, and afterward, selenium will remember cookies.
ChromeOptions options = new ChromeOptions();
options.AddArguments(#"user-data-dir=C:\Users\YOU\AppData\Local\Google\Chrome\User Data\NAMEYOUCHOOSE");
//specify location for profile creation/ access
ChromeDriver driver = new ChromeDriver(options);
Simply put, this code creates a save location for a profile, which does include cookies.
using this code, it is not necessary to write code that saves or loads cookies, Chrome will handle that.
Please note that the location where chrome saves your profiles may be different than mine, and I have only successfully used a directory that leads to the same location as my regular Chrome profile. This profile exists in the form of a folder, not a file.
Generally Selenium do not support cross-session cookies.
Most easy way is to use Serialization.
You need to create wrapper class around selenium's cookie and make it serializable. And create class CookiesManager where will be 2 methods: SaveSession() -- to save and RestoreSession() - to restore from serialized file.
Another way is to save some cookies information into some temp cookies file. Like.... Csv or XML.
Sample of this way you can see here: Keep user logged in - save cookies using web driver
but only for c#.

Categories

Resources