Wednesday, December 17, 2008

Reducing authorization Redundancy in Web.config

We are developing a website that includes several pages, where user access is by page. The users are assigned to groups, which correspond to user roles, in Active Directory. Access to the various pages is based upon a member's being associated with any one of a group of roles.

Here is an example that illustrates the situation:

A user is granted access to the pages, "Bananas.aspx", "MonkeyMatch.aspx", and "Swingers.aspx" if (s)he is in any of the roles: "monkey a", "monkey b", "monkey c".

A user is granted access to the pages, "JavaJabber.aspx", "RailsRules.aspx", and "CodeGuru.aspx" if (s)he is in either of the roles: "geek 0" or "geek 1".

A user in the admin role is granted access to all pages.

Only a user in the admin role is granted access to the page, "SpyOnGeeksAndMonkeys.aspx".


So, Web.config might look like this:

<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<!-- blah, blah ... -->
<system.web>
<authentication mode="Forms">
<forms name=".ADAuthCookie" timeout="10" loginUrl="login.aspx" defaultUrl="default.axpx />
</authentication>
<authorization>
<deny users="?" />
</authorization>
<!-- blah, blah, blah -->
</system.web>
<location path="Bananas.aspx">
<system.web>
<allow roles="monkey a,monkey b,monkey c,admin" />
<deny users="*" />
</system.web>
</location>
<location path="MonkeyMatch.aspx">
<system.web>
<allow roles="monkey a,monkey b,monkey c,admin" />
<deny users="*" />
</system.web>
</location>
<location path="JavaJabber.aspx">
<system.web>
<allow roles="geek 0,geek 1,admin" />
<deny users="*" />
</system.web>
</location>
<location path="RailsRules.aspx">
<system.web>
<allow roles="geek 0,geek 1,admin" />
<deny users="*" />
</system.web>
</location>
<location path="CodeGuru.aspx">
<system.web>
<allow roles="geek 0,geek 1,admin" />
<deny users="*" />
</system.web>
</location>
<location path="SpyOnGeeksAndMonkeys.aspx">
<system.web>
<allow roles="admin" />
<deny users="*" />
</system.web>
</location>
<location path="images">
<system.web>
<allow users="*" />
</system.web>
</location>
<location path="javascript">
<system.web>
<allow users="*" />
</system.web>
</location>
<location path="css">
<system.web>
<allow users="*" />
</system.web>
</location>
<!-- blah, blah, blah -->
</configuration>


You can see the problem! Having the list of roles duplicated in the various location elements is definitely asking for trouble. What are the chances that someone will mess up the roles on a new page -- or even in the original configuration. As the number of roles and the number of pages increase, it gets even worse.

It would be very nice if the path attribute of the location element could take multiple paths. Unfortunately, it doesn't.

There are options. We could organize the structure of the site around authorization. In that case each location element would only need to reference the containing folder. Sometimes that makes sense.

Another option is to use the configSource attribute of the authorization element. We can then write separate files that have the configuration that we need. For example, we can write these files:

AuthMonkey.config

<authorization>
<allow roles="monkey a,monkey b,admin" />
<deny users="*" />
</authorization>


AuthGeek.config
<authorization>
<allow roles="geek 0,geek 1,admin" />
<deny users="*" />
</authorization>

AuthAdmin.config

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


AuthAllowAllUsers.config
<authorization>
<allow users="*" />
</authorization>

The web.config location elements can now be replaced with:




<location path="Bananas.aspx">
<system.web>
<authorization configSource="AuthMonkey.config" />
</system.web>
</location>
<location path="MonkeyMatch.aspx">
<system.web>
<authorization configSource="AuthMonkey.config" />
</system.web>
</location>
<
location path="JavaJabber.aspx">
<system.web>
<authorization configSource="AuthGeek.config" />
</system.web>
</location>
<
location path="RailsRules.aspx">
<system.web>
<authorization configSource="AuthGeek.config" />
</system.web>
</location>
<
location path="CodeGuru.aspx">
<system.web>
<authorization configSource="AuthGeek.config" />
</system.web>
</location>
<location path="SpyOnGeeksAndMonkeys.aspx">
<system.web>
<authorization configSource="AuthAdmin.config" />
</system.web>
</location>
<location path="images">
<system.web>
<authorization configSource="AuthAllowAllUsers.config" />
</system.web>
</location>
<
location path="css">
<system.web>
<authorization configSource="AuthAllowAllUsers.config" />
</system.web>
</location>
<
location path="javascript">
<system.web>
<authorization configSource="AuthAllowAllUsers.config" />
</system.web>
</location>


As a result, the groups of roles are kept in one place. The Web.config file now references the appropriate authorization rules in the location elements. This is a great improvement over redundant values in the allow and deny elements.

No comments: