1

Consider this scenario: I have a REST API built with Web API 2.x and authentication is managed by ASP.NET Identity. Users can upload attachments as part of their records, which are all stored on disk in the root folder, under a directory named Attachments.

Now at some point users can generate PDFs from their records. The PDF includes links to attachment files, and when you click them the static file is happily served. For example: attachments/2018/01/somefile.jpeg.

What I need to do, is serve these media files ONLY to authorized users. And basic authentication isn't enough, I can't just say serve media files for all logged-in users. I need to query the database, check user assignments and/or other security measures and decide if the file should be served or not.

I've been looking for a viable solution. How can I handle such routing through Web API and serve static content only to authorized users? It's worth mentioning that I don't use ASP.NET MVC in my project. It is just Web API 2.x with an Angular 1.6 app written in TypeScript.

halfer
  • 19,824
  • 17
  • 99
  • 186
Nexus
  • 968
  • 1
  • 12
  • 31
  • For clarity: Are you using this [Authentication and Authorization](https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api) ? With attributes from [AuthorizeAttribute Class](https://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute(v=vs.118).aspx) ? – JQuale Feb 18 '18 at 05:53
  • Yes I'm using Bearer tokens for authentication, the default implementation in Identity. And controllers and actions are protected with the Authorize attribute and roles. – Nexus Feb 18 '18 at 13:58
  • Here is an answer to a similar question [How do I protect static files...](https://stackoverflow.com/questions/2903292/how-do-i-protect-static-files-with-asp-net-form-authentication-on-iis-7-5) Does this solve your problem? If not what are the differences between your question and the linked question? – JQuale Feb 18 '18 at 15:51
  • Thanks @JQuale. I'll look into it, I've been able to catch requests by introducing a new controller with a route prefix (i.e. "attachments"). But seems like the request is different than other OWIN requests. There's no current user or identity to check upon. They're simply null. This is taking forever .. – Nexus Feb 18 '18 at 16:02
  • In this case of no current user would it make sense to set the security settings on the Attachments folder to not allow anonymous users? Like by right clicking on Attachments folder and setting permissions on the Security tab. That way it would require an authenticated user to read, write etc. or force user authentication with a popup for UserName and Password – JQuale Feb 18 '18 at 17:37
  • Also I found this relating to anonymous access, IIS, and Windows Authentication [Using Windows Authentication with Minimal Permissions Granted to Disk](https://weblogs.asp.net/owscott/iis-using-windows-authentication-with-minimal-permissions-granted-to-disk) – JQuale Feb 18 '18 at 17:44
  • If you are getting null for current user try getting user with HttpContext.Current.Request.LogonUserIdentity.Name this seems to work when using Angular with Web API 2 according to [Get Current User within an APIController...](https://stackoverflow.com/a/41561590/9229961) – JQuale Feb 18 '18 at 18:00
  • Thanks a lot pal! Useful links, much obliged. But still not a solution. I can't use in web.config because that only works on FormsAuthentication module. I'm using Owin + Identity + EF. I have been able to work with Owin StaticFiles, you can register a OnPrepareResponse() handler and check for authentication. But that didn't help at all. The thing is, when a request is made like "example.com/attachments/photo.jpeg" I can intercept it in a controller action, but there's no user context. Using only the [Authorize] attribute also fails, because there's no User/Owin context. – Nexus Feb 18 '18 at 20:58

1 Answers1

0

Following approach should work for you.

Step 1- Deny the direct access permission on your attachment folder in your web.config to all users like following.

<location path="attachments"> 
<system.web>
<authorization> 
</authorization>
</system.web>
</location>

Step 2: Create a common file download API, this should be your single point for downloading any file from server.

All your secured link should look like /Download/somefilename

You implement your data level security in your Download API, by checking the request file against the logged in user.

PSK
  • 17,547
  • 5
  • 32
  • 43
  • Yes I'm aware of the **location** config, but how do I handle that end-point through Web API? My understanding is IIS serves static files, so the routing request doesn't even reach my Web API pipeline. Care to include a sample code or something? – Nexus Feb 18 '18 at 14:02
  • Basically in a website there are static content which is not secured like website images, and there will be some content like “attachments” in your case which needs to be secured. For content which don’t required an security, let the URL of those data remain same, but for the content which need to be secured you should not give direct relative URL for your folder, you need to change the URL like /Document/FileName where ever it is being used. This way the secured content loading responsibility will always with the Controller. – PSK Feb 19 '18 at 06:43
  • I think you're right. That's the way to go for now, relative URLs that point to files on disk will be removed, in favor of an action controller. This isn't desirable at all but I don't think there's any other way. Whether you serve static content via IIS, or via Owin StaticFiles you're not gonna have a user context when a file on disk is requested. It's just a different context, and the current user is always a Windows user (your apppool for instance). So perhaps all media files should be requested from a controller, to enable authentication. I'll give it a try and update this post. – Nexus Feb 19 '18 at 08:50