Chapter 9. Authentication

Nearly all web applications need to authenticate their users, but how they authenticate them varies. The Merb stack, however, includes a highly modular authentication plugin that gives us a miniature stack of minimally constraining tools that together offer us out-of-the-box authentication within our applications. Created by Daniel Neighman, the Merb auth plugin went through several intense iterations. Before long, however, its design came to exemplify the principle of Merb itself and without hesitation was included within the stack, ultimately because its modularity countered the contentions of custom authentication so strongly.

This also makes it one of the absolute best plugins from which to learn, so we’re going to explore it nearly in its entirety. We recommend that you take your time and keep several goals in mind while we do so. First, as a Merb application developer, remember the methods that you’ll need to use. These will also be listed among other documentation, however, so another goal should be obtaining a deeper understanding of how they work. From the perspective of a Merb plugin developer, you should also pick up on the structural considerations apparent throughout the plugin. Various techniques will indubitably come in handy during the construction of your own plugins. Last, as a student of Merb’s design itself, look to this chapter to impart a deeper understanding of the envisioned extensibility of Merb.

9.1 Auth core

The core part of merb-auth is divided into several sections. We can find the code breakdown spelled out in the file lib/merb-auth-core.rb:

image

We’ll go through the significance and use of each of the files within this section. Note the use of before_app_loads for the inclusion of the authenticated helper. These lines exemplify the common need for methods defined in a plugin to be loaded before application code is loaded, lest the application code blow up. This is because the authenticated helper adds a method, ensure_authenticated, which the application developer may use to ensure the authentication of users. We can also spot the use above of Plugins.add_rakefiles to include various rakefile tasks. This appends rakefiles to the array Merb.rakefiles, which are all iteratively required within the standardly generated Merb application rakefile.

Finally, the use of Merb.push_path is a method that adds files for inclusion within our Merb application. For the authentication plugin, and many other plugins, this is critical because it allows for particular code to be contained within the application itself, overriden by the developer as necessary. In the case of the authentication plugin, there are two such files of importance: setup.rb and strategies.rb. Let’s look at the first of these two:

image

The first thing this does, and that you may need to change, is select which model class will be used for authentication. The standard class is User, as we can see above, but if your application demands that it be something else, such as Person, changing the value within setup.rb allows you to use the authentication plugin without issue. The next few lines add in the salted user mixin. We’ll see the code for this later on, but for now know that this adds properties and methods to the user model for authentication. The last section of the code opens up the Authentication class, adding in two methods. The first wraps the manner of retreiving a user by ID, and the second defines how a user should be stored within a session. Don’t let the tertiary operator confuse you, however. All that’s being said is that a user’s ID alone should be stored within the session store.

Now let’s take a look at the second file, strategies.rb:

image

We see that the default strategies are cleared out and then two of them are reactivated. We’ll find out more about this soon, but from this alone we get a feel for how the application developer can interact with cascading authentication strategies.

9.1.1 Authentication

Let’s take a look at parts of the first file required by the authentication core, which defines Merb::Authentication:

image

Note that the contained module Strategies is stubbed and will be used later on to contain various means of authentication. The inclusion of Extlib::Hook is also noteworthy; it allows the authentication plugin to make particular methods hookable for the application developer. Moving on to the methods, we can see that an authentication is tightly coupled with a session store. It also specifically stores user data within the session store under the key :user. This means that application developers should stay away from using this key for other purposes. The double bang within the authenticated? method assures that either true or false is returned even if session[:user is nil. The method user returns nil whenever the session user key isn’t holding a user. Otherwise, it fetches the user or, if that has already been done, returns a memoized user. The corresponding writer method delegates to the method store_user, which we previously saw in setup.rb. Going further into the file, we can see stubs for a number of methods, all labeled API overwritable:

image

Some of these are the same methods we saw in setup.rb. The overwritable therefore specifies that they can be defined within that file by the application developer.

The crown jewel of the Authentication class, however, is the method authenticate!. Here it is in full:

image

image

The method takes three arguments: a request, parameters, and an optional array of strategies that may also end with a hash of options. After a sorting out which strategies are to be employed through authentication, the method iterates through these using the Ruby enumerable method detect. This returns the succeeding strategy name as soon as its block evaluates to true. The block itself pulls up a strategy using the lookup_strategy method and then calls the run! method as a means of strategic delegation. If successful, a user is authenticated, but a halted strategy can also induce immediate overall failure. Finally, an application developer should be aware of the use of run_after_authentication_callbacks to serially make callbacks after authentication. Let’s finish off the code for this class by looking at some of the methods used within authenticate!:

image

The first two of these deal with strategy lookup, the first being a memoization that defaults to the second, which effectively stores all authentication strategies into a mash. The final and private method handles authentication callbacks. In a later subsection we’ll see how application developers can make use of these.

9.1.2 Strategy

The Strategy class is important in that it defines a common structure with which the auth plugin can interface during user authentication. In the source file for this class, we see that the first step is the extension of the Authentication class:

image

The class variables, which have been made redundantly read-accessible through cattr_reader, are used to store a list of strategies. The reason the class method register is labeled as an API plugin is that it is meant to be used by merb-auth-more and possibly other auth strategy plugins.

Moving on to the Strategy class, we can comprehend the manner by which strategies are to be designed. Let’s start by looking only at class methods:

image

First notice the use of the inherited method to assure that the class is appended to the list of strategies. Consequently, the default strategy order is determined by the order in which the strategies are defined. This isn’t permanently necessary, however, as the two class methods before and after allow us to reinsert a strategy before or after some particular strategy. Finally, the methods abstract! and abstract? will be used later on to determine if a strategy is treated concretely or not.

Let’s now take a look at the instance methods. Insofar as the Strategy class is an abstraction of the strategy interface, these form a basis upon which strategies must be developed.

image

image

The initialize method takes two parameters, request and request parameters. A strategy object should therefore be understood to be tightly coupled with particular requests. Here a number of these methods are simply designed to proxy to an underlying method. The redirect method is particularly interesting in that it allows strategies to halt authentication and have Merb pursue immediate redirect. The methods halt! and halted? are the ones that set and get whether a strategy object has been halted or not.

image

Finally, we again see the method user_class, which is used here to give access to the user model class to strategy objects. We also see an abstract method run!, which is used by all concrete classes to define the precise manner of authentication.

9.1.3 Sessions

The ubiquitousness of the auth plugin is made clear by how many other classes and modules it opens up. Here we see what additions it makes to the Session module:

image

Since these methods are the ones application developers will find themselves using the most, be sure to remember them. They are all accessible through the session object and can be collectively used to set, check, initialize, or abandon authentication.

9.1.4 Errors

Authentication errors are a means of storing error messages when authentication fails. Let’s take a quick look at the file that does this:

image

image

You’ll see that, for the most part, it is a reimplementation of what we find in the DataMapper validation plugin. Consequently, we’ll be able to use the method error_messages_for on the authentication object as if it were a validatable model.

9.1.5 Responses

Authentication strategies can push out responses for use by Merb directly. In order to facilitate this, the file responses.rb layers in various methods (which we actually saw being referenced previously) within the class Authentication:

image

Notice how the default status level is 200, and "Location" is the header key used for redirects. It’s clear from this that Merb auth, like Merb itself, is designed to work in an HTTP world.

9.1.6 Helpers

The single controller helper method that comes along with the auth plugin is ensure_authenticated. We saw its containing module previously included before the Merb application code loads. Nonetheless, here is the source to the actual method:

image

The method itself is protected so that it won’t appear as a controller action. It also accepts strategies as an optional list; when absent, the method authenticate! uses the default strategy list instead. In an application controller, this method may be used with a before filter:

image

Here we have locked out all unauthenticated requests.

9.1.7 Router helper

The router helper extends the Merb router with a method authenticate. Application developers can use this to alternatively demand authentication from within the router as opposed to within controllers.

image

Interestingly, the method first creates a new Proc that is used by the defer method, which you may recall from our discussion of routers. Within the Proc, the first thing checked is whether authentication has already occurred or not. If so, the request params are immediately passed along. Otherwise, logic that imitates what we found in ensure_authenticated relays to the method authenticate!. As long as no authentication strategy led to a halt, params are passed, but in the case when a halt was encountered, the triplet of status, headers, and body form the immediate Merb response.

9.1.8 Customizations

Merb auth core defines a class method customize_default that can be used to append extra blocks to run by its own boot loader. Below we see both the definition of this method along with the creation of the MerbAuthBootLoader. Both of these will be used later by the Merb auth password slice.

image

9.1.9 Callbacks

At the beginning of this section, we encountered the invoking of callbacks. Now let’s discover how application developers can create these callbacks. Here is the source that enables us to do this:

image

Here we find the class method after_authentication appending to the array after_callbacks. In some cases it appends method names as callbacks. These must be user model instance methods. In other cases, it simply appends an unnamed block if one is given. Looking back to how these callbacks are invoked by the method run_after_authentication_callbacks, we remember that these blocks are provided three parameters: the user (if authenticated), the request, and the request params. It is also important to realize that the return value of our callback will be used to reset the value of user. As application developers, we can therefore make final adjustments through these callbacks, potentially further filtering authentication by returning a non-true value through our callback.

9.2 Auth more

Merb auth more contains the strategies used by a standard Merb application for authentication. Opening the file lib/merb-auth-more.rb, we can see an outline of the strategies provided:

image

The method Authentication.register, which we saw in the auth core, is used to name and establish the path to the strategies to be used. We’ll first go through each of these and then also take a look at more general modifications Merb auth more makes to Merb.

9.2.1 Strategies

All strategies use a base class, aptly named Base. Let’s open up its source to get a feel for what it does and what all strategies have in common:

image

It is easy to overlook the use of the class method abstract!, which as we discovered while looking through the auth core makes the strategy abstract. The effect is that we can programmatically recognize that it should not be used among the strategy cascade.

The most important methods it defines are the class methods password_param and login_param. These two methods allow us to use plugin config values in place of the default symbols :login and :password. These are carried over to instance methods as well.

9.2.1.1 Basic

The basic authentication strategy uses HTTP basic access authentication. To be fair, its code is one of the more complicated among the three strategies, but given its class name, we’ll introduce it first.

image

The most important method of any strategy is run!. This method does the dirty work of authentication. Here we see it first determining whether basic access authorization is possible. If so, it passes a block to basic_authentication, and upon failure, it sets up a request for authentication.

image

Moving forward, the strategy allows the use of access realms, setting the default to Application. In case you’re not familiar with HTTP basic access authorization, realms allow for authentication across certain resources to be done only once. As application developers we can make use of these realms by subclassing this strategy and activating those multiple subclasses. Above, a default failure message is also set.

image

The initialization method shows that the strategy employs Rack’s ability to recognize and interpret basic authentication. Note that the method basic_authentication? ensures that basic authorization can occur and that some credentials were provided.

image

Finally, here we arrive at the two most critical methods that were referenced in run!. The latter of these is used to wrap authentication in order to provide for its use across multiple realms. The former method issues a halt after setting the HTTP response appropriately to instigate basic authentication client-side.

9.2.1.2 Password form

Most web applications rely on web forms for authentication because they tend to be prettier and less obtrusive. The authentication strategy for forms also happens to be far simpler. Here it is in its entirety:

image

Aside from pushing out the strategy error message into a helper method, everything is contained within run!. We can see how it makes use of the model class method authenticate that we saw in the auth core. Upon failure, an authentication error becomes accessible to application developers via the session object.

9.2.1.3 OpenID

OpenID is growing in use, and providing it as an alternative among a cascade of authentication methods is a great way to ease the pain users get from having to log in on a myriad of sites, including yours. However, because of the strong interweaving of the OpenID gem with this strategy, and the need to extensively introduce OpenID concepts alongside the source, we’ll leave its exploration to the reader.

9.2.2 Models

Merb auth more also steps into the user model to define how authentication should occur. Having seen auth more contain the concrete logic for strategies, you should now realize that auth more is intended to provide actual authentication implementations, whereas the auth core is concerned only with underlying mechanisms. As we explore the source related to extending the user model for authentication, we will concern ourselves only with the DataMapper-related code.

image

Above, the SaltedUser module makes good use of the methods included and class_eval to create password accessors as well as extend and include class and instance methods respectively. This is a typical construct found within many such modules, and it helps avoid the deep nesting of numerous methods within the class_eval.

image

The only class method provided is encrypt, and it needs to be this way since we may have to encrypt passwords even when not yet dealing with user objects. Interestingly enough, despite this insight, all the methods that do call this method are just instance methods. A chaining of instance to class method can be observed below.

image

What we also see is a method for the initial encryption of the password. The creation of a class-level salt is required as we saw with the class method encrypt. Note that if you need more powerful or custom encryption, we recommend that you take these methods as templates for your own, placing them within the user model class itself.

There are also modifications made to the user model class dependent upon the ORM. Let’s open up the file related to DataMapper models and see what it does:

image

This time we see a variation from included and class_eval to extended and class_eval. This is because every alteration is essentially class-level but needs the DataMapper::Resource module to be included first for the methods property, validates_*, and before. More precisely, we see above the addition of two properties, validations for those properties, and a before hook that will ensure the encryption of passwords. There’s one more method, though, and it’s not in the class_eval:

image

The method authenticate is a class method that allows us to locate a user object matching credentials. If no such user exists, we’ll get nil, which we know can be evaluated to false in Ruby.

9.2.3 Controller

Merb auth more adds only one method to Merb controllers. This is the method redirect_back_or, which is used to return users to the page they intially requested before being redirected to a login:

image

Above we see that the method checks for a URL within the session store, but that we can pass it a default URL as well as an optional hash to prevent the redirection to particular pages. As an application developer, you may need to use this method from inside a custom sessions controller.

9.3 Auth password slices

The final stretch for the Merb auth plugin is to provide a slice that already sets up basic controllers and views to handle web form logins. Since we’ve already explored the composition of slices, it’s a great time to see one in action. Let’s open up the all-important lib file first and then move on to the application files the slice provides.

9.3.1 Lib file

The lib file of any slice is where a number of essential steps occur. For the Merb auth password slice, this means requiring its dependencies along with setting up routes. With regard to the form, we discover the following:

image

Note the required gems at the top, the setting of metadata, and then the use of init to turn on the password form strategy. Moving on, we find the routes:

image

We see three matches, one of them pointing to the Exceptions controller for login and the other two involving the Sessions controller. It may seem odd at first to use an Exceptions controller for anything the user sees on a regular basis, but once you realize that you can throw Unauthenticated exceptions to get the user to a login page, the decision to do so makes perfect sense. Finally, remember that scope is used to limit the reach of our routes within the main application. Thus, within our application router we’ll probably spot code like that below to get the routes matching at the root level.

image

9.3.2 Controller

The password slice makes modifications to two controllers, Sessions and Exceptions. Let’s take a look at the Sessions controller first since its construction is the most direct:

image

What we notice first is the use of underscored filters. The underscores are there to prevent conflict with your own. More important, though, we can conclude that there are two actions in this controller, update and destroy. In either case, a session will be abandoned, but in the case of update, ensure_authenticated will come into play by authenticating our session, as was previously seen. Additionally, the two after filters do not have underscores and are meant to be overwritten if desired.

image

If not, they behave as above, using the method redirect_back_or to direct the user appropriately after login or logout. Finally, we see that _abandon_session simply relays to a method we saw in Chapter 8, abandon!.

Moving on to the code for the Exceptions controller, we’ll warn you that it has been structured as a mixin:

image

Simply enough, though, the method authenticated looks like an action and either renders an HTML template or attempts basic authentication otherwise using the Merb core method basic_authentication.request!. Encountering the use of the authentication boot loader method customize_default, we find the reason for the mixin above:

image

As we can see, the Exceptions controller needs a bit of added work to get the slice templates working with it. It also needs unauthenticated to be manually added as an action because of its being mixed. Is this all a bit undesirable? Perhaps. But altogether this isn’t much work for an edge use case of a custom exception action in a slice.

9.3.3 Views

The one view necessary for the slice to function is the login. A common point of bewilderment among first-time Merb application developers is where this view is. Thinking back to the routes we’ve seen in the password slice, it’s apparent that it should be in app/views/exceptions/unauthenticated.html.erb. Below we present the default login view, but if your application is like most and needs to customize this, it should be as easy as providing a replacement within your application code.

image

Of course, if you make this form for yourself, there’s no reason not to use the Merb helper, which out of courtesy has not been used above. Also, you probably want to refer to login and password by indirect references. The most interesting line is the one with the method error_messages_for. Remember the errors included within Authentication? It’s nice to finally put them to use as if they were model validation errors.

9.4 Conclusion

Nearly all web applications need to authenticate their users. With merb-auth, Adam French, Daniel Neighman, and other contributors have isolated the core mechanism of authentication, providing a fully modular approach to its additional features. Our tour of the code behind merb-auth, probably the pinnacle of beautiful Merb plugins, has given us examples of both low-level plugins as well as a high-level slice. We recommend that all students of the Merb framework grok the code as a supplement to this chapter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.37.10