Programming

Installing Trac on CentOS 5

I’m using Slicehost, but these instructions should work for any hosting provider running CentOS 5. I am not using Subversion (because it sucks and has been slain by Git). If you need SVN support, check out the posts by Nick or Daniel Skinner.

  1. Install python and mod_python (for Apache)
    1. yum install python mod_python
  2. Install MySQL-python
    1. Download the tarball from http://sourceforge.net/projects/mysql-python
    2. Compile the package:
      python setup.py build && python setup.py install
  3. Install Clearsilver, a templating package needed by Trac
    1. Download Clearsilver from http://www.clearsilver.net/downloads/
    2. Compile Clearsilver:
      ./configure –with-python=/path/to/python && make && make install
    3. Note: My path to python is /usr/lib/python2.4
  4. Install Trac
    1. Download Trac from http://trac.edgewall.org/wiki/TracDownload
    2. Setup Trac:
      python ./setup.py install
  5. Create a Trac project
    1. I’m going to keep all of my Trac projects in /var/www/apps/trac, and for this example, I’ll call my project MyTracProject
    2. trac-admin /var/www/apps/trac/MyTracProject initenv
    3. Give your project a name of your choosing, but accept the default for all other settings.
  6. Install TracWebAdmin
    1. Note: This is an optional step, if you would like to administer Trac from within Trac itself. Also, installation of this plugin is only necessary if you’re running Trac version 0.10 or earlier as 0.11 has integrated this plugin into the core Trac package.
    2. In a temporaty directory, grab the TracWebAdmin package:
      svn co http://svn.edgewall.com/repos/trac/sandbox/webadmin/
    3. cd webadmin
    4. python setup.py egg_info
    5. cp dist/TracWebAdmin-0.1.2dev_r5753-py2.4.egg /var/www/apps/trac/MyTracProject/plugins (Note: the actual filename may be different, depending on the build)
    6. Enable the plugin by adding the following to your trac.ini found at /var/www/apps/trac/MyTracProject/conf/trac.in
      [components]
      webadmin.* = enabled
      
  7. Define some Trac users
    1. Create a file to store your authorized users:
      touch /var/www/apps/trac/auth-file
    2. Add a user to the file:
      htpasswd -m /var/www/apps/trac/auth-file <username>
  8. Give admin permissions to the Trac user
    1. trac-admin /var/www/apps/trac/MyTracProject permission add <username> TRAC_ADMIN
  9. Configure Apache
    1. Load mod_python by editing your httpd.conf (for me this is /etc/httpd/conf/httpd.conf) and add “LoadModule python_module modules/mod_python.so”
    2. I want to access Trac via http://trac.mytrackproject.com
    3. You’ll need a CNAME record in your DNS to support the trac.mytrackproject.com subdomain.
    4. You’ll also need to create a VirtualHost section in Apache’s httpd.conf file. For example:
          <virtualHost *:80>
      
            ServerName trac.mytrackproject.com
      
            <location />
              SetHandler mod_python
              PythonHandler trac.web.modpython_frontend
              PythonOption TracEnv /var/www/apps/trac/mytrackproject
              PythonOption TracUriRoot /
            </location>
            <location "/login">
              AuthType Basic
              AuthName "trac"
              AuthUserFile /var/www/apps/trac/auth-file
              Require valid-user
            </location>
      
          </virtualHost>
      
  10. Restart Apache: service httpd restart
  11. Go to http://trac.mytrackproject.com and start using Trac

Tags: ,

Friday, May 16th, 2008 Programming 5 Comments

How to Change or Reset your Password with RESTful_authentication

I have used the acts_as_authenticated plugin for quite some time. It works well, and there’s lots of documentation. I’ve been happy with it. Mostly. I say mostly because it has always bothered me that acts_as_authenticated generates unRESTful code, which is tainting my perfectly RESTful application.

So, I recently evaluated the restful_authentication plugin. The plugin works great, but it is lacking the same breadth of documentation. I needed to add the ability handle a lost password and to change a password. Here’s what I did:

1. Create a new Passwords controller.

The new/create actions equate to a lost password (user wants to get a new password). The edit/update actions equate to changing a password (user wants to update their password).

When a user forgets their password and requests a new one, both their login and email will be required. If this login and email pair exists, then a new, random password will be generated and emailed.

When a user desires a new password, they are required to enter their old password in addition to typing and confirming a new password. The old password is required for security sake.

class PasswordsController < ApplicationController
  before_filter :login_from_cookie
  before_filter :login_required, :except => [:create]

  # Don't write passwords as plain text to the log files
  filter_parameter_logging :old_password, :password, :password_confirmation

  # GETs should be safe
  verify :method => :post, :only => [:create], :redirect_to => { :controller => :site }
  verify :method => :put, :only => [:update], :redirect_to => { :controller => :site }

  # POST /passwords
  # Forgot password
  def create
    respond_to do |format|

      if user = User.find_by_email_and_login(params[:email], params[:login])
        @new_password = random_password
        user.password = user.password_confirmation = @new_password
        user.save_without_validation
        UserNotifier.deliver_new_password(user, @new_password)

        format.html {
          flash[:notice] = "We sent a new password to #{params[:email]}"
          redirect_to signin_path
        }
      else
        flash[:notice] =  "We can't find that account.  Try again."
        format.html { render :action => "new" }
      end
    end
  end

  # GET /users/1/password/edit
  # Changing password
  def edit
    @user = current_user
  end

  # PUT /users/1/password
  # Changing password
  def update
    @user = current_user

    old_password = params[:old_password]

    @user.attributes = params[:user]

    respond_to do |format|
      if @user.authenticated?(old_password) && @user.save
        format.html { redirect_to user_path(@user) }
      else
        format.html { render :action => 'edit' }
      end
    end
  end

  protected

  def random_password( len = 20 )
    chars = (("a".."z").to_a + ("1".."9").to_a )- %w(i o 0 1 l 0)
    newpass = Array.new(len, '').collect{chars[rand(chars.size)]}.join
  end

end

2. Here is the change password view (edit.html.erb):

<div class="form_container">
    <%= error_messages_for :user %>

    <% form_for(:user, :url => user_password_path(@user), :html => { :method => :put }) do |f| %>
      <fieldset>
<div class="form_row">
          <label for="password">Old password</label>
<%= password_field_tag :old_password %></div>
<div class="form_row">
          <label for="password">New password</label>
          <%= f.password_field :password %></div>
<div class="form_row">
          <label for="password_confirmation">Retype the new password</label>
          <%= f.password_field :password_confirmation %></div>
<div class="submit_row">
          <%= f.submit "Update", :class => "submit" %> or <%= link_to 'Cancel', home_path %></div>
</fieldset>
    <% end %></div>

3. Here is the new password view (new.html.erb):

<div class="form_container">
    <% form_for(:password, :url => passwords_path) do |f| %>
      <fieldset>
<div class="form_row">
          <label for="login">Username</label>
          <%= text_field_tag 'login' %></div>
<div class="form_row">
          <label for="email">Email</label>
          <%= text_field_tag 'email' %></div>
<div class="submit_row">
          <%= submit_tag 'Send Password', :class => "button-to" %></div>
</fieldset>
    <% end %></div>

4. Here’s the user notifier (emailer) code:

You’ll need a user_notifier.rb file and a view template (app/views/user_notifier/new_password.html.erb) which will just contain the text of the email you want to send.

app/models/user_notifier.rb:

class UserNotifier < ActionMailer::Base
  def new_password(user, new_password)
    setup_email(user)
    @subject    += 'Your new password'
    @body[:new_password]  = new_password
  end

  protected

  def setup_email(user)
    @recipients  = "#{user.email}"
    @from        = "Support" "<support@yoursite.com>"
    @subject     = ""
    @sent_on     = Time.now
    @body[:user] = user
  end
end

app/views/user_notifier/new_password.html.erb:

We’re sorry to hear your lost your password. But, there’s no need to worry, because we’ve created a new, temporary password for you.

Your new password is: <%=h @new_password %>

You can change this password to something more memorable once you log into your account.

5. Here’s the modified routes.rb file:

  map.resources :passwords
  map.resources :users, :has_one => [:password]

Tags:

Monday, March 24th, 2008 Programming 21 Comments

Justin has been obsessing over writing simple Web software using Ruby on Rails since 2007. He's also an entrepreneur and Lean Startup expert. Learn more

View Justin Britten's profile on LinkedIn

Subscribe to Justin Britten's blog Follow Justin Britten on Twitter Network with Justin Britten on LinkedIn
 
Prefinery: Simple, online beta management software'

Launch a private beta for your Web application in minutes. Prefinery takes care of collecting e-mail addresses, generating invitation codes, and sending invitations for your private beta. Your customers never leave your site, and e-mail invitations are sent from your address.

Justin is Founder and CEO of Prefinery.