I was recently asked to create a solution for providing
folder access and security on a Web site. The idea was that a user could log in
to the Web site and then be automatically directed to a default folder in which
files were listed on another page as links. When the user clicks on the file
name, the file would be delivered to the user. (This is akin to the process
where a user’s credential information directs them to a particular directory in
FTP. The difference is this is a Web interface to a familiar process.) I’ll
walk you through my steps for creating this solution. (The code in this article
was successfully tested and run on Windows 2000 Server with Internet
Information Services (IIS) 5.0.)
Laying the groundwork
The Web site was located on a Windows 2000 machine. Since
IIS and Windows security are tightly integrated in this environment, I decided
to take advantage of this authentication mechanism. When the user logs in to
the originating page, the LOGON_USER environment variable is used to get detailed information
about the user. Since Windows takes care of authenticating and authorizing the
user, the only thing to worry about is where to grab the file information for
the currently logged in user.
Since there is no database interaction with the solution, my
process uses XML files that provide the ability to persist user information.
The XML data will be persisted in application variables—any changes to the
application XML data will be persisted in the XML files. The only thing that is
persisted is identifiable information about the currently logged in user. This
is the SessionID of the current user session.
In order to provide flexibility with the security on
folders, I wanted to allow users access as individual users or users of a
group. This requires that folders provide access to users and groups, and this
information must be stored in an XML file. So there should be three XML files:
one for users, one for groups, and one for folders.
The user’s XML file contains user information. For instance,
each logged in user has a username. When the user visits the Web site, a
session is created that is identified by a session identifier. Since there is
only one user per session, the user node that identifies the user contains a sessionId attribute to hold the current session identifier.
The sessionId attribute will be used to locate the
user’s ID for access information. You’ll also need the default folder for the user.
Listing A contains an example
of the user’s XML file.
The group’s XML file contains information about groups and
the users of each group. Each group node contains a group of users identified
by their ID number.
Listing B
contains an example of the group’s XML file.
The folder’s XML file contains all the necessary information
for granting access to individual users. Each folder node contains a list of
users who have permission to view the contents of the folder. The folder node
also specifies a friendly name for the folder—to protect the true identity of
the folder—and an absolute path to the physical folder location on the server.
Listing C contains the example for the
folder’s XML file.
When the user logs in to the Web site, he is
“directed” to his default folder. This folder will display all the
available files and folders within that folder that are accessible.
Putting all of the pieces together
First, the user must log in to the system. A generic login
page will provide the means for prompting the user for their credentials. Since
I don’t want to mess with Windows NT authentication, I’m going to request that
the user supplies their credentials through basic authentication. You can do this
by setting the Response status to “401 Unauthorized” and adding the
header “WWW-Authenticate: Basic”. When the browser receives this
status, it should automatically provide a login window for the user to enter
his username and password. When the user enters and submits this information,
IIS will automatically authenticate the user based on the supplied credentials.
It’s important to understand that basic authentication will
send the credential information as plain text back to the server. In order to
avoid any security issues, it is recommended that any solution that implements
this type of authentication mechanism do so through SSL. Also, Basic
Authentication must be enabled for the login page through administration
(usually through Internet Services Manager). (For more information about
authentication using Windows 2000 Server, visit
Microsoft’s page on the subject.) When (and if) the user is authenticated,
the LOGON_USER environment variable is set. This data can be used to query the
user’s XML for a particular user node during login.
If the user is already logged in, the sessionId
attribute should be set. You can verify this by looking for the user node where
the sessionId attribute value is the current session
ID. If you cannot find this node, then you can log in the user by setting the sessionId attribute, persisting
the XML data, and directing the user to their default folder. Listing D contains the code to accomplish this task.
This code assumes the following: that the users.xml file must be located in the root directory of the
site for this code to work; and, the currently logged in user must have read
privileges to this file. This presents a security hazard as long as the file is
located under the root directory of the site. If you move this file to another
location, such as a directory above the root directory, the user will not be
able to view the file through a normal URL. Also, this code will work as long
as the site is not on a Web farm. To handle this type of issue, the users.xml file must be in a shared directory for each
server, and you must choose another mechanism other than SessionID,
such as a generated GUID stored in a cookie. However, this is supposed to be a
simple, one server solution. This code is saved to a file called Security.asp.
Once the user is logged in, he is redirected to GetFiles.asp. This page displays all the files and folders
as links to which the user has access. The GetFiles.asp
page checks to make sure there is a currently logged in user. If there isn’t
one, the browser is redirected back to the Security.asp
page. If there is a currently logged in user, the page checks to see if a
folder specification, the friendly name, was passed in as part of the request.
If it wasn’t, the user is provided with the folders and files of their default
directory. Otherwise, the files and folders of the current directory to which
the user has access are displayed. The user can then click on any file to
retrieve the file or on any folder to navigate to that folder. Listing E contains the code to
accomplish this task.
The IsUserOkay function checks to
see if the user or the user’s group(s) is valid for the friendly name passed in
to the function. Finally, all the files and folders are provided as links in
the outgoing HTML. A subfolder will not be displayed unless the user has
privileges to this folder. Once again, this is all controlled in the folders.xml file.
When the user sees this page, they click on either a folder
or a file. The onclick event handlers for the links
take care of submitting the necessary data to the server. These event handlers
are located in the getfiles.js file, as you can see
in Listing F.
When the user clicks a folder, the page sets the friendlyName hidden input and submits the form. The
destination for this submission is still the GetFiles.asp
page. To wrap things up, another file called GetSecureFile.asp
is responsible for delivering the file when it is clicked. GetSecureFile.asp
once again checks the security of the user, and then delivers the file as an
octet-stream if security is passed.
View Listing G to see the necessary code.
When the user receives the file, he sees a pop-up asking
whether to Save, Open, or Cancel the download. If the user types in the specified URL for getting
information, he would have to be logged in. If the user is logged in, he would
need to have privileges for the file or folder. If not, the user will always be
redirected to the Security.asp page.
Download
the source code for this solution. Try out the code on your own development
platform using an administrator account. Once you get this to work on your
platform, try tightening down security by moving the XML files outside of the
site root. Also, use credentials for test users and provide the directories
you’re exposing with the appropriate permissions for these users.
Keep your developer skills sharp by automatically signing up for TechRepublic’s free Web Development Zone newsletter, delivered each Tuesday.