URL Authorzation Problem

N

nicemonitor

I have created a web application that is utilizing Forms Authentication
and URL Authorzation for application security.

The problem arises when an authenticated user (the authentication
ticket cookie has been set) attempts to access a sub directory or file
where I have explicitely denied them access. For example the code in
the root web.config is as follows:

<authentication mode="Forms">
<forms loginUrl="authAgent.aspx"
name="csgOperationsAuthTicket"
protection="All"
timeout="60"
path="/"
/>
</authentication>

<authorization>
<deny users="?" />
</authorization>

A web.config created in a protected directory called "protected" has
the following authorization tags:

<authorization>
<allow users="admin" />
<deny users="*" />
</authorization>

Now if i attempt to visit a page within the "protected" sub directory
the forms authentication ticket is created for the user however if i
attempt to access the directory as any other user but "admin" I do not
get an access denied page or message. Instead it stays at the loginUrl
page (seems to reload over and over). If I do access the directory as
"admin" everything works fine.

Is there a way to display an access denied page to the user?

Note that when I use Windows authentication a nice access denied page
is displayed. If you try to use forms authentication the user is left
hanging. This cannot be by Microsoft's design can it? Is it a bug?

Any insight is *GREATLY* appreciated.

Thanks
 
D

Dominick Baier [DevelopMentor]

Hello (e-mail address removed),

Thats IMHO a flaw in FormsAuth - it would be nice to have two redirect URLs
in FormsAuth config - one for login, one for access denied.

What you can do (and that's what the built in module should do) is, check
on your login page if the a valid context.user is associated with the request.


In you login.aspx
If the user is unauthenticated, display login UI - if the user is authenticated
- display access denied.
 
J

jfer

Hi Dominick thanks for the reply.

The problem is not that I need two redirect URL's the problem is that
when a user who is authenticated tries to access a resource they are
not authorized to access an access denied page is not provided from IIS
(instead it seems to try over and over to reauthenticate and redirect
which results in the endless loop). I notice IIS has an error page
associated with error code 401.7 which is for access denied because of
URL authorization. Why isn't this page shown? Maybe I have to trap
the event when a response of 401.7 goes out and redirect the user to an
appropriate page? This is ridiculous. I can't believe no one has
complained about URL authorization via forms authentication before.
I invite anyone to setup an application with forms auth and restrict
access to a particular folder or resource. Then try to surf to that
url. You will not get an access denied page, instead forms auth will
continually try to reauthenticate you in hopes of gaining new
credentials which will allow you access (this HAS to be a bug)!
Note that when you set all this up and use Integrated Windows
Authentication with URL Authorization, unauthorized users will see a
nice access denied page from IIS.

Again any insight appreciated!
 
J

Joe Kaplan \(MVP - ADSI\)

One thing you might consider doing to work around this behavior is
implementing your own HttpModule that handles the EndRequest event, checks
for a 401 status code instead redirects to a custom "Access Denied" page of
your choosing (you would need to exclude this page from authorization via a
location tag or simply have your module set the SkipAuthorization flag for
requests to that page in the BeginRequest event).

That should give you a viable solution with hopefully only about 20 lines of
code.

Joe K.
 
J

jfer

Interesting advice Joe thank you very much. Do you have any articles
on this subject to help me begin an implementation?
Also are you SURE you can trap a 401* error? I could of swore I read
others trying to trap 401 errors in the forums in the past and saying
it would not work although they could successfully trap a 404 error.
Any thoughts?
 
J

Joe Kaplan \(MVP - ADSI\)

You can handle the 401 in EndRequest if the 401 was generated by the
UrlAuthorizationModule. You can't if it was handled by IIS as the request
will never get to ASP.NET.

All the UrlAuthorizationModule does is checks the access of the user and if
it fails, sets status to 401 and calls CompleteRequest which short circuits
the event pipeline to the EndRequest method. This is nice because if it had
called Response.End, the response would have been aborted right there.
However, the UrlAuthorizationModule does its work politely and gives you one
last chance at the request.

Here is some VB.NET code that I modified from an actual thing we wrote that
does something similar. I didn't test this version, but you get the idea.
This would basically be the gut of an IHttpModule, although you could do
something similar in Global.asax:

Public Sub Init(ByVal context As System.Web.HttpApplication) _
Implements System.Web.IHttpModule.Init

AddHandler context.EndRequest, AddressOf HandleComplete
End Sub

Private Sub HandleComplete(ByVal sender As Object, ByVal e As EventArgs)
Dim application As HttpApplication
application = DirectCast(sender, HttpApplication)

If application.Context.Response.StatusCode = 401 Then
application.Context.Response.StatusCode = 200
application.Context.Response.Clear()
application.Context.Response.Write("Access Denied")
application.Context.Response.Flush()
End If
End Sub

In your code you might wish to redirect or at least render some valid HTML
:), but you get the idea.

HTH,

Joe K.
 
J

jfer

Wow thank you so much for the help Joe!! I am going to try and
implement this tonight.

I notice in your code above you are trapping ALL 401 errors. Is there
any way I can get at that sub status code? What I mean is I noticed
there are two sub status codes of the 401 errors that IIS can throw in
relation to access denied becase of a URL Authorization denial. I
believe one of the subcodes is 401.7. Again your insight is
appreciated.

Thanks again!!
 
J

Joe Kaplan \(MVP - ADSI\)

If you look at the source for the UrlAuthorizationModule (using .NET
Reflector to reverse compile it is especially helpful here), you'll notice
that it just sets the status to 401. I'm guessing that IIS sets the
substatus on the way back out of the IIS pipeline but ASP.NET does not, so
it won't be set by the time your code gets to it.

Also, remember that this will only catch 401 errors generated by .NET code
in the ASP.NET pipeline. If IIS rejects the request for some reason, none
of this code will likely even get executed. Therefore, as long as you are
reasonably certain that only the UrlAuthorizationModule will be setting 401
status codes from .NET, you can be relatively sure that is a fair indicator.

However, in examining this a little further, I noticed that there is one
hitch. The FormsAuthenticationModule ALSO handles the EndRequest event and
checks for the 401 response code too. Since it is probably loaded in the
list of modules before you code, it will likely execute first and beat your
code to the punch.

As such, you may need to "reorder" the list of modules and place yours first
by removing the forms auth module, adding yours and then re-adding forms
auth. I'd also suggest taking a look via Reflector at exactly what
FormsAuth is doing in EndRequest so you can understand what it is up to
better.

HTH,

Joe K.
 
J

jfer

This ordering is done in machine.config correct? Can I reorder inside
web.config so as to only change the ordering for the application where
I need this functionality?

Just out of curiousity why is it that that UrlAuthorization module
doesn't automatically send the user to an appropriate page or deliver
an access denied message? Seems odd that by design microsoft set this
up so that when an authenticated user tries to access a resource they
are not authorized to access that it redirects them back to the
loginURL page specified in the web.config for forms authentication.
This results in an endless loop of redirection until the redirectURL
becomes larger than some browser setting where it finally "dies" for
lack of a better term. I'm glad you offered your insight on this as
most people attribute my problem to something misconfigured in my forms
authentication. Due to the lack of internet discussion out there with
my problem it makes me wonder how many people out there are actually
utilizing URL Authorization with Forms Authentication. You would think
after several years of this being available someone would of stumbled
upon this problem. I had to search mercilessly over the net for
similar discussion, and even then was very minimal discussion.

Your help will assist those in the future I'm sure.

Thanks!
 
J

Joe Kaplan \(MVP - ADSI\)

You can reorder in web.config although the original list is set in
machine.config. Just use the remove element in conjunction with the add
element. The documentation for the syntax is in the MSDN documentation
somewhere under config file schema for ASP.NET.

I have no idea what the motivation for the original MS design was.
Additionally, I make no warranty that my solution will not break some other
scenario that we are not considering. Please test carefully. :)

Best of luck,

Joe K.
 
J

jfer

I had one last comment before I sit down and do this.

Isn't it just as feasible to create a solution that uses the LoginURL
page defined in the <authentication> section of the web.config for
forms authentication. What I mean is that it seems when a user who is
already authenticated attempts to access a resource they are not
authorized to access IIS transfers the user to the loginUrl page which
attempts to re-authenticate them. If thats the case could we not
include at the top of the Page_Load event something along the lines of

Page_Load (...)
{
// user has already been authenticated and thus must be sent here if
they failed an
// authorization check
if (User.IsAuthenticated) { Response.Redirect("accessDenied.aspx");
}
else {
// check authentication and issue ticket if user is ok
}
}

Any thoughts?

Thanks

Thoughts?
 
J

Joe Kaplan \(MVP - ADSI\)

Sure, you could also do that. Essentially, you would not be using the
UrlAuthorizationModule (<authorization> tags) and would be doing your own
thing there. I'd probably put that code in an HttpModule or global.asax
event handler so I didn't have to put it in every single page, but that is
an implementation detail.

Basically, you use the UrlAuthorizationModule because you like the
config-driven approach for providing authorization information about your
application. However, it is not the only way to go by a long shot. In many
cases, you may wish to do programmatic authorization checks such as the case
when you need to dynamically render controls based on who the current user
is.

Let us know how you make out if you try my suggestion.

Joe K.
 
J

jfer

Sorry let me clarify. The code above I provided would not go into the
Page_Load event of every page it would go into the Page_Load event of
the loginUrl page specified in the forms authentication portion of the
web.config file. It seems to me that the user is sent to the loginUrl
page when they are
a) not authenticated
b) authenticated but are accessing a resource they are not authorized
to access

If that is the case then when they are already authenticated but are
accessing the loginURL page again then it must be because they failed
authorization somewhere in the web application. (Albeit a user COULD
load the page via a url if they were so inclined after already being
authenticated).

Anyways your approach is a more robust solution I just thought I would
also throw in my 2 cents!

Thanks
 
J

Joe Kaplan \(MVP - ADSI\)

Ah, gotcha. Yes, you should be able to branch on in the login page and use
that to do something different. That is also a very good idea and is
probably a much more straightforward solution to what you are trying to
solve.

Good thinking,

Joe K.
 
J

jfer

Hey Joe I just wanted to ask you if my part b) event from my post above
was correct? Does a user get redirected to the LoginURL page when they
are authenticated but try to access a section they are not authorized
to? I wasn't sure how to verify this was hoping you might know off
hand.

Thanks
 
J

Joe Kaplan \(MVP - ADSI\)

The user will get redirected if they were denied access to the resource for
whatever reason. They might not be authenticated or they might be
authenticated or not authorized.

What I'm not totally sure about is whether the forms auth module will
actually set the current user to an authenticated user when it is redirected
to the login page. I'm sure you'll find out pretty quickly if you try it
though.

I'm not really that much of a forms authentication expert as it is. I've
used the UrlAuthorizationModule a bunch, but mostly in the context of the
Windows auth stuff, so some of the finer points on Forms auth elude me.

Hopefully you've got enough options here to try a couple of different
solutions though.

Joe K.
 
D

Dominick Baier [DevelopMentor]

Hello Joe,

cool. this was exactly what i was suggesting 15 posts before :)
 
J

Joe Kaplan \(MVP - ADSI\)

lol!

I wasn't actually paying attention to the whole thread and kind of jumped in
the middle. Serves me right...

:)

Joe K.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,521
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top