gem "devise", "1.1.2"
gem "devise_ldap_authenticatable", :git => "git://github.com/cschiewek/devise_ldap_authenticatable.git"
Save your gem file and run a bundle install command.
Now that our bundle is complete, we can run some of the install generators.
=> rails generate devise:install
You'll see that it installed devise.rb into initializers and also added a localization file. Let's generate our devise user model.
=> rails generate devise User
This generator created our user.rb model, some test files, a migration file, and altered our routes.rb. Now let's perform a generation for our devise_ldap_authenticatable gem.
=> rails generate devise_ldap_authenticatable:install
This generator created an ldap YAML file, altered the devise.rb file in initializers, modified our user.rb model, and also modified our application_controller.rb controller.
Let's take a look at our initializer, our routes, our user model, and our application controller.
Inside of devise.rb you'll find the following code snippet:
Make sure to uncomment config.ldap_create_user and set to true, config.ldap_config, and config.ldap_use_admin_to_bind and set to true. This will allow new user information to be saved to our user model when a user properly authenticates from AD. In addition, we're binding an admin user which will allow us to set the proper credentials for the admin account that will be used to connect through LDAP. This will be done in our YAML file in a moment.
If you scroll down a little further in this initializer file, you'll find this next snippet of code:
This bit of code helps us configure our ORM (Object Relationship Manager) to work with Active Record. It's already set by default. Great. Let's move on to our User model.
As you can see from our user model below, the new gem has altered the file and placed ldap_authenticatable as a default devise module.
Our application_controller.rb also has some interesting code inside:
The ldap generator we ran earlier added a rescue to our Authenticatable class so that exceptions are rendered via text and provide us a status code of 500. So, if we encounter any exception errors with LDAP, we'll receive a text message along with a numerical status that will let us know we encountered some type of failure.
Our routes.rb file just contains a very simple route called devise_for :users. This will redirect all routes to the gem specific paths unless overridden. This is fine for now.
And, last but not least, we have our YAML file - config/ldap.yml.
We're only concerned with the Environments here. So, scroll down to development: and have a look at it. Notice that we have all of the connection entries here to connect to active directory. However, these will need to be changed. The best question you may want to ask yourself is how can you find all of the information for Active Directory containers and organizational units? This is quite easy with a simple application called "LDP.exe". Go to you run box on the windows server and search for LDP and run it.
- Click connection --> connect.
- Type in the name of your server: corp.ruby.com
- Leave the port the same and click OK.
You'll find that you are connected to the server.
Once connected, you'll need to bind your connection and use an administrative test account to connect. In my example, I created two AD test users from part 5. The admin user was called fred in active directory, but the user account was flintstonef. So, I'm going to use this account to test the bind with.
- Click connection --> bind.
- In the user field type "flintstonef". (this is the admin user I created in part 5)
- In the password type "Bedrock0". (this is the password I set for this user)
- In the domain type "corp.ruby.com" (this is the domain I'm using for AD)
- Once done click OK.
It should look like this.
And once connected you will see this:
And, we're connected to Active Directory. This is a promising start. Let's look over our Active Directory tree and determine our base container and user container paths.
- Start by clicking View --> Tree.
- Click the dropdown and select "DC=corp,DC=ruby,DC=com".
- Click OK.
Once the tree is open, we can then browse down to Users and find our path to our admin user. Look at the picture below:
And this shows us exactly what information we'll need to fill in our development section for ldap.yml in our application. After placing this in, here's what my ldap.yml file looks like now:
Notice that I changed our base to point to the Users container. I also changed the admin_user information to point to our admin user. I commented out everything else. LDP.exe is very helpful and should prove useful later on as we can use it to browse Active Directory and find out pertinent information we may need for our application. Make sure to remember this when working with your app. At this point, we should be able to run a quick test to see if it all works.
First, let's create a generic scaffold to test things with. How about a post model. That seems simple enough.
=> rails g scaffold post title:string body:text
Then, we'll run a migration to migrate everything up to the current schema.
=> rake db:migrate
And, we can see that our devise users table and our posts table successfully migrated. So far, so good.
Let's run our stop/start .bat file (the new service) we created in part 5 as an elevated "administrator" by right-clicking it to start the server. And, after doing so, I'm going to open up a page and go check out the posts route.
And, our server is responding and I'm able to create a post. Great. But, there's no authentication being performed on this view. Let's correct that. We're going to edit our application_controller.rb file and add a before_filter for authentication through devise. It should now look like this:
We added before_filter :authenticated_user! to our class above. Let's save it and refresh our app.
Now, when I tried to login, the first thing I noticed is it's asking me for an email address. This poses two problems that I can see right now. First, I didn't specify an email address for my user account in AD. Let me do that for fred now:
Also, because we're looking for an email address instead of a username, we need to correct one part of our ldap.yml configuration file and change the following:
This will allow our authentication system to search for the correct attribute and this should fix this issue. If we go back to my application and type in:
firstname.lastname@example.org with password Bedrock0
Successful authentication! Let's check the logs:
If you click on the image above, you'll see that it found the user in AD, and also found that the user didn't exist in our User table. It successfully added our user to the table and authenticated us. I was able to post.
If you made it this far without any hiccups, pat yourself on the back! We are now using Active Directory to authenticate and login to our application. We did this with Thin and Apache and did not use fastcgi or IIS. In our next part, we'll do some cleanup, add some user based checking, and also add some test unit code to ensure everything is working fine.
See you in part 7!