views:

443

answers:

4

We have an ASP.Net web application running on IIS6 that manages its own database of users.

The site itself just allows anonymous access and all authentication/security is managed using our application itself.

We have a page that contains an HTML table of data that we import into Excel and is then used for Reporting purposes. The page currently has no security implemented.

We need to add security to this page so that should these spreadsheets fall into the wrong hands then the data cannot be "Refreshed" without supplying a username / password.

If I set this page to not allow Anonymouse access then I can use Basic/Windows authentication with Windows Users in order to secure this page. Then when Excel refreshes the data the password dialog box pops up.

The problem is that I need to be able to secure this page based on the Users within our database and they will not be Windows users. I also need to do it in such a way that allows Excel to manage the authentication which excludes any Form based authentication.

Anyone got any ideas? Is it possible to get IIS to look elsewhere for it's Basic Authentication?

+1  A: 

I'm not an expert but I thought that the point of Basic was that it was Windows Authentication. Can you run a script to synchronise your DB users with your Active Directory?

If it's a corporate AD, you could consider having a second AD just for your app and synchronising users from both your corporate AD and your DB. If you don't need to synchronise passwords (e.g. build a pwd-mgmt page in your site) you could just use scripts or C# or something. If you want something more sophisticated with built-in password synchronisation, you could look at ILM 2007 (soon to be FIM 2010).

serialhobbyist
The problem with this is that I have no way of knowing what any of the existing users passwords are. They are all salted and hashed etc.
Robin Day
How if you put your synchronisation method in place (in the background) and then expire all passwords so that users have to set up new ones?
serialhobbyist
+1  A: 

Is the page an .html file or an .aspx file? If it's an .aspx, you should keep this page under anonymous access and check for authentication in the page logic itself

SergeyKazachenko
It is an ASPX page so I can write any .net/c# code required for it. However, is it possible to go through IIS as anonymous and then still perform a custom HTTP Auth style authentication? Do you have any examples of this?
Robin Day
I'm not sure I understand your question. You said "all authentication/security is managed using our application itself." So I assume once the user logs in there's a Session variable started, right?At the top of the page check that variable, if it's not set, redirect to "login.aspx"
SergeyKazachenko
The page is accessed by Excel... Excel has no idea what to do with a page that redirects to Login.aspx.
Robin Day
OK, then instead of redirecting, simply return a string "Please log in before accessing this page". I hope Excel can display that...
SergeyKazachenko
+2  A: 

As you've got a custom database of users, I'd recommend looking at building a quick membership provider that talks to your database schema.

MSDN has a good example on "How to: Sample Membership Provider".

You can then use the standard access control mechanisms of ASP.NET to lock down the page, require authentication, etc, along with controls like Login, LoginStatus and others to provide much of the UI you need.


Edit to add

A quick search found the following, which might help:

Web Service Security - Basic HTTP Authentication without Active Directory

Where Greg Reinacker presents "a fully working sample in 100% managed code demonstrating the use of HTTP Basic authentication, using a separate credential store (in this case, a XML file, although this would be easy to change to a database or LDAP store)."

Zhaph - Ben Duguid
I may be wrong here, but doesn't this then rely on a Forms style of authentication, eg, requesting a page takes the user to a login page first before returning to the original page. The problem is, this is not possible from Excel which is why I need it to use HTTP Auth, eg, Basic Authentication.
Robin Day
Ah, I see you point, but then you're stuck without windows users - which is as serialhobbyist points out, what Basic Auth uses.
Zhaph - Ben Duguid
I've seen some possible uses of an HttpModule to implement Basic Authentication outside of IIS. I'll post here if I have any success.
Robin Day
Yes, that seems to be what I found too.
Zhaph - Ben Duguid
+1  A: 

Ok, so I've found two solutions to this problem. One thanks to Zhaph - Ben Duguid's answer which is an HttpModule that allows ASP.Net to fully manage the authentication.

The second solution, and the one that I am going with, is thanks to this question/answer.

HTTP Authentication (Basic or Digest) in ASP Classic via IIS

I've stripped this down and have a simple test harness that seems to be working well. In this example, instead of a database call, it merely checks that the username and password match and considers that authenticated.

using System;
using System.Text;

namespace AuthenticationTests
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            string authorisationHeader = Request.ServerVariables["HTTP_AUTHORIZATION"];

            if (authorisationHeader != null && authorisationHeader.StartsWith("Basic ", StringComparison.InvariantCultureIgnoreCase))
            {
                string authorizationParameters = Encoding.Default.GetString(Convert.FromBase64String(authorisationHeader.Substring("Basic ".Length)));
                string userName = authorizationParameters.Split(':')[0];
                string password = authorizationParameters.Split(':')[1];

                if (userName == password) //Perform your actual "login" check here.
                {
                    //Authorised!
                    //Page loads as normal.
                }
                else
                {
                    Unauthorised();
                }
            }
            else
            {
                Unauthorised();
            }
        }

        private void Unauthorised()
        {
            Response.AddHeader("WWW-Authenticate", "Basic");
            Response.Status = "401 Unauthorized";
        }
    }
}
Robin Day