Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 50 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
50
Dung lượng
515,6 KB
Nội dung
Building a Custom Authentication Module
Authentication is the process of identifying users. Authentication modules use evidence in each
request made to the application to identify which user is making the request. The authentica-
tion modules that ship with ASP.NET use as their evidence encrypted cookies in the request
(forms authentication and Passport authentication) and evidence provided by IIS (Windows
authentication).
What Is an Authentication Module?
In code terms, an authentication module is an HTTP module that handles the
AuthenticateRequest
event of the
HttpApplication
object. When the event fires, the authentication module checks the
evidence associated with the request and populates the
Context.User
intrinsic object with an
appropriate
IPrincipal
object (that is, an object of a class that implements the
IPrincipal
inter-
face). The authorization module then uses
Context.User
as the basis for deciding whether the
request should be authorized. The rest of the application code is then able to access whatever
data is stored in the
IPrincipal
object.
It is actually pretty rare that you need to replace the standard authentication modules with a
custom solution. Usually you can solve your problems by customizing one of the existing
modules. Forms authentication, as you saw in Chapter 13, is particularly suitable for such
manipulation.
One situation in which a custom authentication module is useful is when you want to identify
access to an application according to which machine is trying to access the application rather
than according to which specific user is making the request. For example, if you have an
intranet application running on a closed network in a shopping mall, you might want to iden-
tify which client machines are used to make requests in order for the application to behave
differently. (For example, the application might show special offers appropriate to stores near
the client machine that is being used, or the map might be able to show a “you are here” label.)
There are all sorts of ways you can solve this problem. One clean way is to implement a custom
authentication module that uses the IP address of the client machine as the evidence for
authentication. The following sections show how to build a simple HTTP module that provides
this functionality.
Building a Custom Identity Class
Before you build the HTTP module itself, you need to think about the
IPrincipal
object that it
will use to populate
Context.User
. The principal represents the security context of the user. The
interface has the following members:
Member Return Type
Identity IIdentity
IsInRole (String) Boolean
14
Customizing Security
538
19 0672326744 CH14 5/4/04 12:27 PM Page 538
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
539
Building a Custom Authentication Module
Every
IPrincipal
object will store an
IIdentity
object that represents the identity of the authen-
ticated user and will allow you to check whether the user is in a particular role.
You can build a custom class that implements
IPrincipal
, but there is rarely any need to do so;
System.Security.Principal.GenericPrincipal
does the job in the vast majority of cases.
GenericPrincipal
provides a constructor that takes an
IIdentity
object and an array of strings for
the roles. It simply stores the roles internally and checks against them when
IsInRole
is called.
Most authentication approaches can use
GenericPrincipal
. The exception is Windows authenti-
cation, which needs to check roles against the user’s Windows roles rather than against a set of
roles stored by the principal object. It therefore defines a different
IPrincipal
implementation,
WindowsPrincipal
. In the IP authentication example,
GenericPrincipal
will do just fine. However,
you should create a custom identity class that implements
IIdentity
. The reason becomes clear
when you look at the members required by the
IIdentity
interface:
Member Return Type
AuthenticationType String
IsAuthenticated Boolean
Name String
The identity needs to return the type of authentication used to create it, so a new identity class
is needed for each authentication module.
The following is the code for an identity class for the IP authentication module:
Public Class IPIdentity
Implements System.Security.Principal.IIdentity
Private _IP As String = Nothing
Public Sub New(ByVal ip As String)
_IP = ip
End Sub
‘do not allow an IPIdentity to be created without an IP address
Private Sub New()
End Sub
Public ReadOnly Property AuthenticationType() As String _
Implements System.Security.Principal.IIdentity.AuthenticationType
Get
Return “IP”
End Get
End Property
Public ReadOnly Property IsAuthenticated() As Boolean _
Implements System.Security.Principal.IIdentity.IsAuthenticated
19 0672326744 CH14 5/4/04 12:27 PM Page 539
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Get
‘An IP Identity will only be used when authentication is successful
Return True
End Get
End Property
Public ReadOnly Property Name() As String _
Implements System.Security.Principal.IIdentity.Name
Get
Return _IP
End Get
End Property
End Class
You store the IP address of the machine that is making the request in a private field. A construc-
tor is provided to allow a new
IPIdentity
object to be created from an IP address, but you mark
the default constructor as private so it cannot be used.
The members required by
IIdentity
are each provided.
AuthenticationType
returns
“IP”
.
IsAuthenticated
returns true; you will be using
IPIdenity
only with authenticated requests.
Name
returns the IP address string.
This is a pretty minimal
IIdenity
implementation. You can add other data to the identity class.
For example,
FormsIdentity
provides access to the forms authentication ticket.
Building the HTTP Module
Now that you know what the IP authentication module is going to populate
Context.User
with,
you can press on and build the HTTP module that will implement it (see Listing 14.1).
LISTING 14.1 An HTTP Module Implementation for IP-Based Authentication
Imports System.Security.Principal
Public Class IPAuthenticationModule
Implements IHttpModule
Public Sub Dispose() Implements System.Web.IHttpModule.Dispose
‘we have no resources to dispose of
End Sub
Public Sub Init(ByVal context As System.Web.HttpApplication) _
Implements System.Web.IHttpModule.Init
‘handle the AuthenticateRequest of the application
AddHandler context.AuthenticateRequest, AddressOf Me.Authenticate
End Sub
14
Customizing Security
540
19 0672326744 CH14 5/4/04 12:27 PM Page 540
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
541
Building a Custom Authentication Module
Public Sub Authenticate(ByVal sender As Object, ByVal e As EventArgs)
Dim application As HttpApplication = CType(sender, HttpApplication)
‘create identity and principal objects
Dim identity As New IPIdentity(application.Request.UserHostAddress)
Dim principal As New GenericPrincipal(identity, New String() {})
‘attach the principal to the application context
application.Context.User = principal
End Sub
End Class
You don’t need to do anything in the
Dispose
method because you use no resources that require
disposal. You have to include it, though, because it is required by the
IHttpModule
interface.
In the
Init
method, you bind the
Authenticate
method of this class to the
AuthenticateRequest
event of the application. In the
Authenticate
method, you simply use the IP address of the
request (
Request.UserHostAddress
) to create an
IPIdentity
object, which is then used to construct
a
GenericPrincipal
instance that is stored in
Context.User
.
Before the module can be used, you need to ensure that no other authentication modules are
active by setting the
<Authentication>
element of the
web.config
file appropriately:
<authentication mode=”None” />
You also need to add an
<httpModules>
section to the
web.config
file to add the module to the
application:
<?xml version=”1.0” encoding=”utf-8” ?>
<configuration>
<system.web>
<httpModules>
<add type=”CustomAuthentication.IPAuthenticationModule,
➥CustomAuthentication” name=”IPAuthentication” />
</httpModules>
After you have done this, you can access the IP address of the client through
Context.User.
Identity.Name
. (This is not very impressive, admittedly, because you can access it through
Request.UserHostAddress
anyway.) More interestingly, you can use URL authorization by specify-
ing the IP addresses as the usernames:
<authorization>
<allow users=”127.0.0.1” />
LISTING 14.1 Continued
19 0672326744 CH14 5/4/04 12:27 PM Page 541
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
<allow users=”56.43.43.1” />
<allow users=”56.43.43.2” />
<allow users=”56.43.43.3” />
<deny users=”*” />
</authorization>
You could also have the
IPAuthenticationModule
implementation create the
GenericPrincipal
object with roles that reflect what sort of information should be displayed to that client. You
would then be able to use
Context.User.IsInRole
or any of the other programmatic authorization
techniques to access this information.
Running Authentication Modules in Tandem
The built-in authentication modules in ASP.NET can only be used one at a time, but there is no
reason you cannot have additional custom authentication modules running on top of the built-
in modules.
For example, you might want to use forms authentication to allow administrators to sign in to
the system but use the
IPAuthenticationModule
implementation that you built in the previous
section to identify the client machine for users who are not authenticated by the forms authen-
tication module.
The important thing to do if you want to use more than one module together is to ensure that
they do not clash with each other. You can change the
IPAuthenticationModule
implementation
so that it will populate the
Context.User
object only if it has not already been populated by
another authentication module (see Listing 14.2).
LISTING 14.2 Adapting IPAuthenticationModule to Allow It to Work with Other Modules
Public Sub Authenticate(ByVal sender As Object, ByVal e As EventArgs)
Dim application As HttpApplication = CType(sender, HttpApplication)
‘check that the user has not been created or is not authenticated
If application.Context.User Is Nothing _
OrElse Not application.Context.User.Identity.IsAuthenticated Then
‘create identity and principal objects
Dim identity As New IPIdentity(application.Request.UserHostAddress)
Dim principal As New GenericPrincipal(identity, New String() {})
‘attach the principal to the application context
application.Context.User = principal
End If
End Sub
14
Customizing Security
542
19 0672326744 CH14 5/4/04 12:27 PM Page 542
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
543
Building a Custom Authorization Module
The
IPAuthenticationModule
implementation will then happily coexist with the forms
authentication module. When forms authentication does not authenticate the user, the
IPAuthenticationModule
implementation will populate the
Context.User
object. When forms
authentication does pick up a ticket and authenticate the user, the
IPAuthenticationModule
imple-
mentation will do nothing.
This system will work best when forms authentication is set up to support role-based authoriza-
tion, so that the administrators or other privileged users can be placed in a role.
The example shown here is very simple, but it shows all the features that are required from an
authentication module. If you have some authentication requirements that are not served by
the default modules, you should be able to build a custom module to do the job.
Building a Custom Authorization Module
Authorization is the process of deciding whether the current user has permission to access the
resource that he or she requested. The authorization modules that ship with ASP.NET decide
whether the resource can be accessed by either checking Windows access control lists (file
authorization) or checking the
<authorization>
element of the configuration file (URL authoriza-
tion).
There are lots of other possibilities for authorizing the requests of users. For example, you might
allow access only at certain times, you might require users to have been registered with the
application for a certain amount of time before accessing some content, or you might assign
each user credits that he or she can use to access pay-per-view content. Or you might use a
single-page application architecture and want to authorize based on the URL parameters of the
request.
The best way to implement custom authorization behavior is by creating an authorization
module. Like authentication modules, authorization modules are HTTP modules (although they
hook into the
AuthorizeRequest
event rather than the
AuthenticateRequest
event).
Listing 14.3 shows a simple authorization module that checks the expiration date in a custom
identity against the current date.
LISTING 14.3 A Custom Authorization Module
Public Class ExpirationAuthorizationModule
Implements System.Web.IHttpModule
Public Sub Dispose() Implements System.Web.IHttpModule.Dispose
‘nothing to dispose of
End Sub
Public Sub Init(ByVal context As System.Web.HttpApplication)
➥Implements System.Web.IHttpModule.Init
AddHandler context.AuthorizeRequest, AddressOf Me.Authorize
19 0672326744 CH14 5/4/04 12:27 PM Page 543
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
End Sub
Private Sub Authorize(ByVal sender As Object, ByVal e As EventArgs)
Dim application As HttpApplication = CType(sender, HttpApplication)
If application.Context.Request.IsAuthenticated Then
If Not application.Context.User.IsInRole(“NonExpiring”) Then
Dim identity As ExpiringIdentity = _
CType(application.Context.User.Identity, ExpiringIdentity)
If identity.Expires < DateTime.Now Then
‘the users registration has expired
application.Context.Response.Redirect(“RegistrationExpired.aspx”)
End If
End If
End If
End Sub
End Class
The infrastructure of this authorization module is very similar to that of the custom authentica-
tion module discussed earlier in this chapter in the section, “What Is an Authentication
Module?”
In the
Authorize
event handler, you check whether the user is authenticated. (This module is
designed to only check for expired membership; it does not deny authorization to anonymous
users. It is assumed that URL authorization would be used to do that.)
Next, you check that the user is not in the
NonExpiring
role. If he or she is, you do nothing
more, and the user is allowed to view the resource he or she requested. If the user is not in the
NonExpiring
role, you check the current date and time against the user’s expiration date and time
from the
ExpiringIdentity
object in
Context.User.Identitiy
. If the user has expired, you redirect
the response to the “registration expired” page.
You may be wondering what the
ExpiringIdentity
class looks like. It is shown in Listing 14.4.
LISTING 14.4 The ExpiringIdentity Class
Public Class ExpiringIdentity
Implements System.Security.Principal.IIdentity
Private _Username As String
Private _MembershipExpires As DateTime
Public Sub New(ByVal username As String, ByVal expires As DateTime)
14
Customizing Security
544
LISTING 14.3 Continued
19 0672326744 CH14 5/4/04 12:27 PM Page 544
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
545
Building a Custom Authorization Module
_Username = username
_MembershipExpires = expires
End Sub
Private Sub New()
End Sub
Public ReadOnly Property AuthenticationType() As String _
Implements System.Security.Principal.IIdentity.AuthenticationType
Get
Return “Custom”
End Get
End Property
Public ReadOnly Property IsAuthenticated() As Boolean _
Implements System.Security.Principal.IIdentity.IsAuthenticated
Get
Return True
End Get
End Property
Public ReadOnly Property Name() As String _
Implements System.Security.Principal.IIdentity.Name
Get
Return _Username
End Get
End Property
Public ReadOnly Property Expires() As DateTime
Get
Return _MemberShipExpires
End Get
End Property
End Class
Running Authorization Modules in Tandem
As with authentication modules, you can run multiple authorization modules at the same time.
You do not have to worry about clashing authorization modules as you do with authentication
modules. If any of the authorization modules in the chain results in failed authorization, it will
take action ahead of any other modules. This is as it should be; when it comes to security, you
should always pay attention to the test that fails rather than to the test that passes.
LISTING 14.4 Continued
19 0672326744 CH14 5/4/04 12:27 PM Page 545
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
The example shown in Listing 14.4 is designed to work in tandem with URL authorization. URL
authorization would be used to keep anonymous users from using the application, whereas
ExpirationAuthorizationModule
implementation would be used to deal with users whose registra-
tions have expired.
Trust Levels
By default, ASP.NET applications run at full trust. This means that the .NET Framework places
no limitations on what they can do, aside from the limitations imposed by the operating system
on the account that ASP.NET runs under. This is not a huge problem if you trust all the develop-
ers who write code for all the ASP.NET applications that run on your server, but what if you
do not?
Also, running all applications at full trust breaks the principle of least privilege—the idea that
for the best possible security, code should be allowed only the permissions that it absolutely
needs.
The solution is to force applications to run at less than full trust. ASP.NET ships with four differ-
ent levels of trust and allows you to configure your own trust levels if you need to specify a
particular set of permissions.
Using One of the Preconfigured Trust Levels
In addition to the full-trust mode that places no restrictions, four trust levels are provided with
ASP.NET (see Table 14.1).
TABLE 14.1
The Four Trust Levels Provided with ASP.NET
Trust Level Main Permissions
Minimal Only the bare minimum that are required for ASP.NET to function
Low Very limited access to the file system
Medium Limited read/write access to the file system; some other permissions
High Full access to the file system; most other permissions
Remember that the permissions granted by these trust levels do not allow the ASP.NET user
account to access anything that it does not have operating system permissions for. Trust levels
can only impose additional restrictions; they can never remove existing operating system restric-
tions.
Let’s look at each trust level in more detail to see what permissions the levels provide.
The Minimal Preconfigured Trust Level
The minimal trust level only grants the permissions that are absolutely required for an ASP.NET
application to run.
14
Customizing Security
546
19 0672326744 CH14 5/4/04 12:27 PM Page 546
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
547
Trust Levels
An ASP.NET application running at this trust level will not be able to do a lot. It can’t do any
file system input/output work, can’t do any data access, can’t access isolated storage, can’t access
the registry, and can’t execute any code that requires reflection. In fact, applications at this trust
level can’t really do anything apart from read the HTTP request and write to the HTTP response.
Another restriction when running at this trust level (and low trust) is that it does not allow
debugging. Attempting to run an application that is configured for debugging at this trust level
will result in an error message. For this reason, you have to appropriately set the
<compilation>
element in the
web.config
file for applications that will run at minimal or low trust:
<compilation defaultLanguage=”vb” debug=”false” />
The Low Preconfigured Trust Level
The low trust level does not allow very many more permissions than minimal trust. At this
level, the application can read (but not write) files that are within its application directory, and
it can read and write isolated storage with a quota of 1MB.
Note that the low trust level has the same limitation on debugging that the minimal trust level
has: If you configure an application with low trust for debugging, you will get an error.
The Medium Preconfigured Trust Level
Compared to the minimal and low trust levels, quite a few additional permissions are added at
the medium trust level. Debugging is now allowed. You can read and write files within the
application directory. You also have access to isolated storage with an effectively unlimited
quota. An application can access a SQL Server database through the
SqlClient
classes and can
even print to the default printer.
At this level, an application also gets read access to the following environment variables:
n
TEMP
n
TMP
n
USERNAME
n
OS
n
COMPUTERNAME
Finally, at medium trust, an application gets more control over threads, the principal object, and
remoting.
The medium trust level contains the permissions that most ASP.NET applications need to run.
The High Preconfigured Trust Level
At high trust, an application gets unrestricted access to most resources, including the file system,
isolated storage, environment variables, the registry, and sockets. An application also gains the
ability to generate dynamic assemblies by using
Reflection.Emit
.
19 0672326744 CH14 5/4/04 12:27 PM Page 547
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
[...]... all applications in the InsiderSolutions folder as follows: Creating Custom Trust Levels The trust levels that ship with ASP.NET provide a pretty... of the Web server (usually wwwroot), specify that the application called UntrustedApp that is in the InsiderSolutions folder should be run at low trust: ...548 14 Customizing Security Remember, though, that ASP.NET is still limited by the permissions that the account under which it runs has been given Forcing an Application to Use a Trust Level As mentioned earlier in this chapter, the default trust level for ASP.NET applications is full trust You can see this by finding the appropriate section of the machine.config... to the permission set that it should run with For the purposes of changing the permissions that ASP.NET applications run with, you do not need to change the elements; you just need to add or remove permissions from the element that holds the permissions that are granted to the ASP.NET application The Web_MediumTrust.config file contains three permission sets: a full access... Trust Levels Listing 14.5 shows the element from Web_MediumTrust.config that is granted to the code of the ASP.NET application itself LISTING 14.5 Permissions from the Medium Trust Level Configuration File The permission set named ASP.NET is assigned to the code of the application in all the trust level files It is quite easy to read the various permissions from the file, to see what the application will be allowed to do Removing... PublicKeyToken=b77a5c561934e089”/> Trust Levels Fortunately, there is a way to generate the elements you need—by using the NET Framework Configuration tool The tool does not allow you to edit the ASP.Net trust level policy files directly, but you can add permissions to a permission set in one of the files that the tool can edit and then copy them across to the trust level file To use the NET Framework... this permission set for anything) It would be best to give it a name and description that make it clear that this is a temporary set that you are using to create permissions and classes to copy across to ASP.NET configuration Then you can click Next, and you will see the window where you can add permissions to the set (see Figure 14.2) FIGURE 14.2 Adding permissions to a permission set 553 554 14 Customizing... runtime You can also use the following substitutions: $OriginHost$ - the address of the client that made a request to the application $AppDirUrl$ - the URL of the application $CodeGen$ - The folder where ASP.NET stores dynamically generated assemblies $Gac$ - the Global Assembly Cache folder Note that the last three substitutions are usually used in code groups rather than in permissions 555 556 14 Customizing . usernames:
<authorization>
<allow users= 12 7.0.0 .1 />
LISTING 14 .1 Continued
19 0672326744 CH14 5/4/04 12 :27 PM Page 5 41
Please purchase PDF Split-Merge on. restrictions, four trust levels are provided with
ASP. NET (see Table 14 .1) .
TABLE 14 .1
The Four Trust Levels Provided with ASP. NET
Trust Level Main Permissions
Minimal