Connecting Tech Pros Worldwide Forums | Help | Site Map

Custom authentication in a web application

Jon Skeet [C# MVP]
Guest
 
Posts: n/a
#1: Nov 21 '05
I've run against a problem which I'm *sure* must be easy to solve - but
I'm blowed if I can find the answer :(

I have a web service which I want to require authentication. I need to
authenticate using a database lookup, so Windows, Passport and Forms
authentication are (as far as I can tell) no good to me.

I don't need impersonation.

I would like to use HTTP basic or preferrably digest authentication -
and this is from a Pocket PC Compact Framework client, if that makes
any odds. If necessary, I can write my own custom authentication module
for the client to use non-standard headers if that helps, but obviously
I'd rather not. (I *think* I know how to do that, admittedly.)

My problem is working out what to do on the server side. I basically
need to intercept the request at the point of authentication, and
insert my own authentication module at that point. I *suspect* I need
to implement IHttpModule, but I'm not sure. If I do, I've no idea where
to put anything to use it.

This must be simple, as it's no doubt a very common requirement. Anyone
care to put me out of my misery?

--
Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

Tom Porterfield
Guest
 
Posts: n/a
#2: Nov 21 '05

re: Custom authentication in a web application


Jon Skeet [C# MVP] wrote:[color=blue]
> I've run against a problem which I'm *sure* must be easy to solve - but
> I'm blowed if I can find the answer :(
>
> I have a web service which I want to require authentication. I need to
> authenticate using a database lookup, so Windows, Passport and Forms
> authentication are (as far as I can tell) no good to me.
>
> I don't need impersonation.
>
> I would like to use HTTP basic or preferrably digest authentication -
> and this is from a Pocket PC Compact Framework client, if that makes
> any odds. If necessary, I can write my own custom authentication module
> for the client to use non-standard headers if that helps, but obviously
> I'd rather not. (I *think* I know how to do that, admittedly.)
>
> My problem is working out what to do on the server side. I basically
> need to intercept the request at the point of authentication, and
> insert my own authentication module at that point. I *suspect* I need
> to implement IHttpModule, but I'm not sure. If I do, I've no idea where
> to put anything to use it.
>
> This must be simple, as it's no doubt a very common requirement. Anyone
> care to put me out of my misery?
>[/color]

We do this using Windows Authentication with our security data stored in
a SQL server database. On the server we create our own principal object
that inherits from WindowsPrincipal. In Global.asax in the
AuthenticateRequest handler we replace the HttpContext.Current.User with
our principal object, passing HttpContext.Current.User.Identity as
WindowsIdentity to the constructor. Our principal object overrides the
two overloads of IsInRole to use our own security check. We have also
added a HasPermission method to our principal so we can demand a
permission whenever we need to. So our AuthenticateRequest handler
looks as follows:

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
// this will throw an exception if windows auth not turned on
// Also note we have to set the context here since ASP.NET will take
// what's in the context and place it on the Thread.CurrentUser property
CustomServerPrincipal princ = new CustomServerPrincipal as
WindowsIdentity);
HttpContext.Current.User = princ;

// verify that this user is authorized to get into Polaris
if (!princ.HasPermission(authUserPerm))
{
throw new
CustomSecurityException(String.Format(securityExce ptionMessage,
princ.Identity.Name));
}
}

In any server side objects where we need to demand a permission, we now
simply take the current principal from the thread as our custom
principal and demand the permission. Ex:

CustomServerPrincipal principal =
System.Threading.Thread.CurrentPrincipal as CustomServerPrincipal;
if (!principal.HasPermission(deletePermission))
{
throw new CustomSecurityException(principal, deletePermission);
}
--
Tom Porterfield
Jon Skeet [C# MVP]
Guest
 
Posts: n/a
#3: Nov 21 '05

re: Custom authentication in a web application


(Thanks ever so much for the reply, btw. It's a good start for me :)

Tom Porterfield <tpporter@mvps.org> wrote:[color=blue]
> We do this using Windows Authentication with our security data stored in
> a SQL server database. On the server we create our own principal object
> that inherits from WindowsPrincipal.[/color]

Any reason for using Windows Authentication here rather than any of the
other types?
[color=blue]
> In Global.asax in the
> AuthenticateRequest handler we replace the HttpContext.Current.User with
> our principal object, passing HttpContext.Current.User.Identity as
> WindowsIdentity to the constructor. Our principal object overrides the
> two overloads of IsInRole to use our own security check. We have also
> added a HasPermission method to our principal so we can demand a
> permission whenever we need to. So our AuthenticateRequest handler
> looks as follows:
>
> protected void Application_AuthenticateRequest(Object sender, EventArgs e)
> {
> // this will throw an exception if windows auth not turned on[/color]

How does the behaviour differ between the situation where the user
actually *is* a valid Windows user for the system, and where they're
not? Isn't ASP.NET or IIS going to have tried to use whatever the
client provides as Windows authentication by now?
[color=blue]
> // Also note we have to set the context here since ASP.NET will take
> // what's in the context and place it on the Thread.CurrentUser property
> CustomServerPrincipal princ = new CustomServerPrincipal as
> WindowsIdentity);
> HttpContext.Current.User = princ;[/color]

Any reason for doing it as WindowsIdentity rather than just setting it
as a CustomServerPrincipal?

Presumably before setting the value you check whether the user/password
combination is valid?
[color=blue]
> // verify that this user is authorized to get into Polaris
> if (!princ.HasPermission(authUserPerm))
> {
> throw new
> CustomSecurityException(String.Format(securityExce ptionMessage,
> princ.Identity.Name));
> }
> }[/color]

Does the type of exception matter here, out of interest?
[color=blue]
> In any server side objects where we need to demand a permission, we now
> simply take the current principal from the thread as our custom
> principal and demand the permission. Ex:
>
> CustomServerPrincipal principal =
> System.Threading.Thread.CurrentPrincipal as CustomServerPrincipal;
> if (!principal.HasPermission(deletePermission))
> {
> throw new CustomSecurityException(principal, deletePermission);
> }[/color]

Right - that bit I think I'm reasonably happy with.

--
Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Sami Vaaraniemi
Guest
 
Posts: n/a
#4: Nov 21 '05

re: Custom authentication in a web application


Hi Jon,

Take a look at Greg Reinacker's digest authentication sample, I believe it
shows how to do what you want:

http://www.rassoc.com/gregr/weblog/s...Directory.html

The sample authenticates against user account information in a simple XML
file, but it should be easy to modify it to authenticate against custom user
account information in a database.

Regards,
Sami

"Jon Skeet [C# MVP]" <skeet@pobox.com> wrote in message
news:MPG.1bd73ed6a16ebdb98b6af@msnews.microsoft.co m...[color=blue]
> I've run against a problem which I'm *sure* must be easy to solve - but
> I'm blowed if I can find the answer :(
>
> I have a web service which I want to require authentication. I need to
> authenticate using a database lookup, so Windows, Passport and Forms
> authentication are (as far as I can tell) no good to me.
>
> I don't need impersonation.
>
> I would like to use HTTP basic or preferrably digest authentication -
> and this is from a Pocket PC Compact Framework client, if that makes
> any odds. If necessary, I can write my own custom authentication module
> for the client to use non-standard headers if that helps, but obviously
> I'd rather not. (I *think* I know how to do that, admittedly.)
>
> My problem is working out what to do on the server side. I basically
> need to intercept the request at the point of authentication, and
> insert my own authentication module at that point. I *suspect* I need
> to implement IHttpModule, but I'm not sure. If I do, I've no idea where
> to put anything to use it.
>
> This must be simple, as it's no doubt a very common requirement. Anyone
> care to put me out of my misery?
>
> --
> Jon Skeet - <skeet@pobox.com>
> http://www.pobox.com/~skeet
> If replying to the group, please do not mail me too[/color]


Jon Skeet [C# MVP]
Guest
 
Posts: n/a
#5: Nov 21 '05

re: Custom authentication in a web application


Sami Vaaraniemi <samivanospam@pleasejippii.fi> wrote:[color=blue]
> Take a look at Greg Reinacker's digest authentication sample, I believe it
> shows how to do what you want:
>
> http://www.rassoc.com/gregr/weblog/s...ebServicesSecu
> rityHttpDigestAuthenticationWithoutActiveDirectory .html
>
> The sample authenticates against user account information in a simple XML
> file, but it should be easy to modify it to authenticate against custom user
> account information in a database.[/color]

Having had a very (very!) quick look at it, that looks ideal - thanks
ever so much.

--
Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Tom Porterfield
Guest
 
Posts: n/a
#6: Nov 21 '05

re: Custom authentication in a web application


Jon Skeet [C# MVP] wrote:[color=blue]
> (Thanks ever so much for the reply, btw. It's a good start for me :)
>[color=green]
>>We do this using Windows Authentication with our security data stored in
>>a SQL server database. On the server we create our own principal object
>>that inherits from WindowsPrincipal.[/color]
>
> Any reason for using Windows Authentication here rather than any of the
> other types?[/color]

This is an internal app where we have complete control of the
workstation configuration where we would be called from. We don't
necessarily know who the client is, or will be in the future.
WindowsAuthentication for web applications is company policy.
[color=blue][color=green]
>>In Global.asax in the
>>AuthenticateRequest handler we replace the HttpContext.Current.User with
>>our principal object, passing HttpContext.Current.User.Identity as
>>WindowsIdentity to the constructor. Our principal object overrides the
>>two overloads of IsInRole to use our own security check. We have also
>>added a HasPermission method to our principal so we can demand a
>>permission whenever we need to. So our AuthenticateRequest handler
>>looks as follows:
>>
>>protected void Application_AuthenticateRequest(Object sender, EventArgs e)
>>{
>> // this will throw an exception if windows auth not turned on[/color]
>
>
> How does the behaviour differ between the situation where the user
> actually *is* a valid Windows user for the system, and where they're
> not? Isn't ASP.NET or IIS going to have tried to use whatever the
> client provides as Windows authentication by now?[/color]

Yes, so effectively there are two levels of security involved here. But
since we may not know who our client is, we don't want to rely on the
fact that they have properly authorized the user. Right now you simply
have to be authenticated to a trusted domain to execute our web
services. Another option would be to create a domain group and only
folks in that domain group have access. By using windows authentication
that is possible, but again the scenario here is we want to use our own
security database. If in the future we wanted to use true windows
authentication, or active directory, our custom principal object would
need to change but nothing else in the application would need to change.
When you know your clients are all at least running Windows, this
seemed like the logical future-protection mechanism.
[color=blue][color=green]
>> // Also note we have to set the context here since ASP.NET will take
>> // what's in the context and place it on the Thread.CurrentUser property
>> CustomServerPrincipal princ = new CustomServerPrincipal as
>>WindowsIdentity);
>> HttpContext.Current.User = princ;[/color]
>
>
> Any reason for doing it as WindowsIdentity rather than just setting it
> as a CustomServerPrincipal?[/color]

The code didn't get in there properly. The constructor of
WindowsPrincipal takes a WindowsIdentity as the parameter. The line
should be:

CustomServerPrincipal princ = new
CustomServerPrincipal(HttpContext.Current.User.Ide ntity as WindowsIdentity);
[color=blue]
> Presumably before setting the value you check whether the user/password
> combination is valid?[/color]

Since all of our users are internal, the fact that they have
successfully logged on to our domain means they are validated. And
again, maybe that is a difference here that would require a different
approach for you. So no need to check that they are valid. Rather we
only need to check to see if their ID has authority to our service.
[color=blue][color=green]
>> // verify that this user is authorized to get into Polaris
>> if (!princ.HasPermission(authUserPerm))
>> {
>> throw new
>>CustomSecurityException(String.Format(securityEx ceptionMessage,
>>princ.Identity.Name));
>> }
>>}[/color]
>
>
> Does the type of exception matter here, out of interest?[/color]

We have encapsulated the exceptions so as to capture and present the
exception information in a way that is consistent for our services. So
from a generic standpoint, no it doesn't matter.
[color=blue][color=green]
>>In any server side objects where we need to demand a permission, we now
>>simply take the current principal from the thread as our custom
>>principal and demand the permission. Ex:
>>
>>CustomServerPrincipal principal =
>>System.Threading.Thread.CurrentPrincipal as CustomServerPrincipal;
>>if (!principal.HasPermission(deletePermission))
>>{
>> throw new CustomSecurityException(principal, deletePermission);
>>}[/color]
>
>
> Right - that bit I think I'm reasonably happy with.
>[/color]

--
Tom Porterfield
Closed Thread