0

I have a ASP.NET 4.0 website which contains a sub-folder with multimedia files like JPG, PNG, MP4, MP3, etc.

Currently, any user with the full link to the files is able to access the multimedia files without any restriction. I want to find the currently logged in user who is making the request and after checking their permissions from DB allow/disallow them to access the file requested.

I have tried implementing a Custom HttpModule for this purpose but I am not able to find the current user making the request. Below is my code:

public class CustomHttpModule : IHttpModule
{
    private const string URL_TO_LOOK_FOR = "/MultiMediaFiles/";

    public CustomHttpModule()
    { }

    public void Init(HttpApplication app)
    {
        app.AuthenticateRequest += CustomAuthenticateRequest;
        //app.EndRequest += CustomAuthenticateRequest;
    }

    void CustomAuthenticateRequest(object source, EventArgs e)
    {
        HttpApplication app = (HttpApplication)source;
        HttpContext context = app.Context;
        Uri url = context.Request.Url;
        if (url.AbsolutePath.StartsWith(URL_TO_LOOK_FOR, StringComparison.OrdinalIgnoreCase))
        {
            var response = context.Response;
            response.Clear();
            response.Write("app.Context.User :");
            if (context.User == null || context.User.Identity == null || context.User.Identity.Name == null)
            {
                response.Write("No user");
            }
            else
            {
                response.Write(context.User.Identity.Name);
            }

            response.End();
            response.Flush();
            response.Close();
        }
    }

    public void Dispose()
    { }
}

I tried attaching to events: BeginRequest, AuthenticateRequest, PostAuthenticateRequest and even EndRequest, but in each case context.User is always null even after I have logged in to my website.

EDIT: I am using the FormsAuthentication and my web.config contains:

<system.web>
    <authentication mode="Forms">
        <forms name="MyWebFORMAUTH" timeout="60" 
               loginUrl="~/web/logon/default.aspx" cookieless="UseCookies" 
               defaultUrl="~/web/logon/default.aspx" 
               slidingExpiration="true" />
    </authentication>
</system.web>
<system.webServer>
    <modules>
      <add name="CustomHttpModule" type="CustomHttpModule"/>
    </modules>
<system.webServer>

NOTE: I cannot modify the links to multimedia files.

Please HELP.

Khurram Hassan
  • 1,494
  • 1
  • 13
  • 21
  • You are not authenticating the request. You are authorizing it. You can't authorize until you have already authenticated. See [here](http://stackoverflow.com/questions/6556522/authentication-versus-authorization) for the difference. FormsAuthenticationModule authentication processing has to have completed before you can check HttpContext.User. – John Wu Sep 06 '16 at 22:39
  • Do you use FormsAuthentication on your website? If so how do you set it up in web.config and how do you register your module? Can you check if there are authentication cookies available in `context.Request.Cookies` collection at the beginning of `CustomAuthenticateRequest` method? – vers Sep 06 '16 at 23:11
  • @JohnWu ok I get the difference, I want to Authorize . But what do you suggest I do because even when I capture the `EndRequest` event, I don't see the system identify the username. – Khurram Hassan Sep 06 '16 at 23:35
  • Maybe check [this](http://stackoverflow.com/questions/23590706/why-is-httpcontext-user-null-after-authenticaterequest-is-complete) and/or post a separate question? – John Wu Sep 06 '16 at 23:40
  • @AlexeyMitev I updated my question giving you the details you asked. – Khurram Hassan Sep 06 '16 at 23:51
  • Just tried to run your code and it worked without any issues. Let's debug it further. Try to add the following code to the `CustomAuthenticateRequest` method and to one of your website pages: `List cookieKeys = context.Request.Cookies.AllKeys.ToList(); bool authCookieExists = cookieKeys.Contains("MyWebFORMAUTH");` and check the value of the `authCookieExists` variable in both cases. – vers Sep 07 '16 at 00:12
  • @AlexeyMitev I checked and in both the cases `authCookieExists = true`. – Khurram Hassan Sep 07 '16 at 00:42

1 Answers1

1

UPDATE:

You would also need to tell ASP.NET that you don't want to execute static content handler for certain file types in certain directory.

Here is the updated version of web.config file:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.web>
        <compilation debug="true" targetFramework="4.0" />
        <httpRuntime />
        <authentication mode="Forms">
            <forms name="MyWebFORMAUTH" timeout="60"
                   loginUrl="~/web/logon/default.aspx" cookieless="UseCookies"
                   defaultUrl="~/web/logon/default.aspx"
                   slidingExpiration="true" />
        </authentication>
    </system.web>
    <system.webServer>
        <modules>
            <add name="CustomHttpModule" type="CustomHttpModule" />
        </modules>
        <defaultDocument>
            <files>
                <clear />
                <add value="Default.aspx" />
            </files>
        </defaultDocument>
    </system.webServer>
    <location path="MultiMediaFiles">
        <system.webServer>
            <handlers>
                <!-- This line tells ASP.NET to skip the processing of PNG files
                     by default static content handler. -->
                <add name="SkipStaticPng" path="*.png" verb="GET"
                     type="System.Web.Handlers.TransferRequestHandler"
                     preCondition="integratedMode,runtimeVersionv4.0" />
            </handlers>
        </system.webServer>
    </location>
</configuration>

Your code should work. Here is the example:

Default.aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebForm" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Test</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:Label ID="CurrentUserLabel" runat="server" />
        <br />
        <asp:Button ID="LoginButton" runat="server" OnClick="LoginButton_Click" Text="Login" />
    </form>
</body>
</html>

Default.aspx.cs:

using System;
using System.Security.Principal;
using System.Web.Security;

public partial class WebForm : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
            PopulateCurrentUserName();
    }

    protected void LoginButton_Click(object sender, EventArgs e)
    {
        FormsAuthentication.SetAuthCookie("test_user", false);
        Response.Redirect(Request.Url.AbsoluteUri);
    }

    private void PopulateCurrentUserName()
    {
        IPrincipal user = Request.RequestContext.HttpContext.User;
        if (user != null && user.Identity != null && !String.IsNullOrEmpty(user.Identity.Name))
            CurrentUserLabel.Text = user.Identity.Name;
        else
            CurrentUserLabel.Text = "(null)";
    }
}

CustomHttpModule.cs:

using System;
using System.Web;

public class CustomHttpModule : IHttpModule
{
    private const string URL_TO_LOOK_FOR = "/MultiMediaFiles/";

    public CustomHttpModule()
    {
    }

    public void Init(HttpApplication app)
    {
        app.AuthenticateRequest += CustomAuthenticateRequest;
    }

    void CustomAuthenticateRequest(object source, EventArgs e)
    {
        HttpApplication app = (HttpApplication)source;
        HttpContext context = app.Context;
        Uri url = context.Request.Url;
        if (url.AbsolutePath.StartsWith(URL_TO_LOOK_FOR, StringComparison.OrdinalIgnoreCase))
        {
            var response = context.Response;
            response.Clear();
            response.Write("app.Context.User :");
            if (context.User == null || context.User.Identity == null || context.User.Identity.Name == null)
            {
                response.Write("No user");
            }
            else
            {
                response.Write(context.User.Identity.Name);
            }

            response.End();
            response.Flush();
            response.Close();
        }
    }

    public void Dispose()
    {
    }
}

web.config:

<?xml version="1.0"?>
<configuration>
    <system.web>
        <compilation debug="true" targetFramework="4.0"/>
        <httpRuntime/>
        <authentication mode="Forms">
            <forms name="MyWebFORMAUTH" timeout="60"
                   loginUrl="~/web/logon/default.aspx" cookieless="UseCookies"
                   defaultUrl="~/web/logon/default.aspx"
                   slidingExpiration="true" />
        </authentication>
    </system.web>
    <system.webServer>
        <modules>
            <add name="CustomHttpModule" type="CustomHttpModule"/>
        </modules>
        <defaultDocument>
            <files>
                <clear/>
                <add value="Default.aspx"/>
            </files>
        </defaultDocument>
    </system.webServer>
</configuration>

And here is the test scenario:

  1. Clear the cookies in your browser.
  2. Navigate to the start page (let's say it is http://localhost).
  3. You will see that current user is (null).
  4. Open http://localhost/MultiMediaFiles/ in the second tab.
  5. You will see the "app.Context.User :No user" message.
  6. Switch back to the previous tab and click "Login" button.
  7. You will see that current user now is "test_user".
  8. Switch to the second tab and refresh the page.
  9. If everything is correct then the "app.Context.User :test_user" message should be displayed.
vers
  • 622
  • 2
  • 9
  • 21
  • my target framework is 4.0 but in yours it is 4.6.1. Will it be a problem for me? – Khurram Hassan Sep 07 '16 at 01:14
  • 1
    It shouldn't. But just in case I changed the target framework to 4.0 as well and retested it. It works the same way as it was on 4.6.1. By the way I use local IIS Express (default in Visual Studio 2013) to run this example. If you use non-express IIS for testing, IIS settings may affect the result too. – vers Sep 07 '16 at 01:27
  • Oh.. I know why you can't see the problem. You are navigating to: `http://localhost/MultiMediaFiles/` whereas I am navigating to: `http://localhost/MultiMediaFiles/mypic.png`. When the url points to just the folder then I am able to get the user but when the url points to a file in the folder then the user is `null` – Khurram Hassan Sep 07 '16 at 01:42
  • I just tested this example on IIS 7; it works with default settings. However you can break it by changing some of the IIS settings. For example setting classic app pool instead of integrated is one of the obvious cases. – vers Sep 07 '16 at 01:49
  • Thanks for the help but please check my latest comment above. – Khurram Hassan Sep 07 '16 at 01:57
  • Ah, yes, that's the issue with static content handler. Let me update my answer with the solution. – vers Sep 07 '16 at 01:58
  • Thanks so much for your help. One last question though. The folder may contain any file extension not just `PNG`. So, can I use `path="*.*"` instead of `path="*.png"` ? – Khurram Hassan Sep 07 '16 at 02:15
  • 1
    In this case you can use `path="*"`. – vers Sep 07 '16 at 02:28