Skip to content

Commit

Permalink
initial commit of the restful_authentication plugin
Browse files Browse the repository at this point in the history
git-svn-id: http://svn.techno-weenie.net/projects/plugins/restful_authentication@1477 567b1171-46fb-0310-a4c9-b4bef9110e78
  • Loading branch information
technoweenie committed Aug 1, 2006
0 parents commit 2366199
Show file tree
Hide file tree
Showing 22 changed files with 868 additions and 0 deletions.
24 changes: 24 additions & 0 deletions README
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Restful Authentication Generator
====

This is a basic restful authentication generator for rails, taken from acts as authenticated. Currently it requires Rails 1.2 (or edge).

To use:

./script/generate authenticated user sessions

The first parameter specifies the model that gets created in signup (typically a user or account model). A model with migration is created,
as well as a basic controller with the create method.

The second parameter specifies the sessions controller name. This is the controller that handles the actual login/logout function on the site.

You can pass --skip_migration to skip the user migration.

From here, you will need to add the resource routes in config/routes.rb.

map.resources :users, :sessions

Generate your mailer:

./script/generate authenticated_mailer user

22 changes: 22 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'

desc 'Default: run unit tests.'
task :default => :test

desc 'Test the restful_authentication plugin.'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end

desc 'Generate documentation for the restful_authentication plugin.'
Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'RestfulAuthentication'
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.rdoc_files.include('README')
rdoc.rdoc_files.include('lib/**/*.rb')
end
1 change: 1 addition & 0 deletions generators/authenticated/USAGE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
./script/generate authenticated USERMODEL CONTROLLERNAME
157 changes: 157 additions & 0 deletions generators/authenticated/authenticated_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
class AuthenticatedGenerator < Rails::Generator::NamedBase
attr_reader :controller_name,
:controller_class_path,
:controller_file_path,
:controller_class_nesting,
:controller_class_nesting_depth,
:controller_class_name,
:controller_singular_name,
:controller_plural_name
alias_method :controller_file_name, :controller_singular_name
alias_method :controller_table_name, :controller_plural_name
attr_reader :model_controller_name,
:model_controller_class_path,
:model_controller_file_path,
:model_controller_class_nesting,
:model_controller_class_nesting_depth,
:model_controller_class_name,
:model_controller_singular_name,
:model_controller_plural_name
alias_method :model_controller_file_name, :model_controller_singular_name
alias_method :model_controller_table_name, :model_controller_plural_name

def initialize(runtime_args, runtime_options = {})
super

@controller_name = args.shift
@model_controller_name = @name.pluralize

# sessions controller
base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@controller_name)
@controller_class_name_without_nesting, @controller_singular_name, @controller_plural_name = inflect_names(base_name)

if @controller_class_nesting.empty?
@controller_class_name = @controller_class_name_without_nesting
else
@controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}"
end

# model controller
base_name, @model_controller_class_path, @model_controller_file_path, @model_controller_class_nesting, @model_controller_class_nesting_depth = extract_modules(@model_controller_name)
@model_controller_class_name_without_nesting, @model_controller_singular_name, @model_controller_plural_name = inflect_names(base_name)

if @model_controller_class_nesting.empty?
@model_controller_class_name = @model_controller_class_name_without_nesting
else
@model_controller_class_name = "#{@model_controller_class_nesting}::#{@model_controller_class_name_without_nesting}"
end
end

def manifest
recorded_session = record do |m|
# Check for class naming collisions.
m.class_collisions controller_class_path, "#{controller_class_name}Controller", # Sessions Controller
"#{controller_class_name}Helper"
m.class_collisions model_controller_class_path, "#{model_controller_class_name}Controller", # Model Controller
"#{model_controller_class_name}Helper"
m.class_collisions class_path, "#{class_name}"
m.class_collisions [], 'AuthenticatedSystem', 'AuthenticatedTestHelper'

# Controller, helper, views, and test directories.
m.directory File.join('app/models', class_path)
m.directory File.join('app/controllers', controller_class_path)
m.directory File.join('app/controllers', model_controller_class_path)
m.directory File.join('app/helpers', controller_class_path)
m.directory File.join('app/views', controller_class_path, controller_file_name)
m.directory File.join('test/functional', controller_class_path)
m.directory File.join('app/controllers', model_controller_class_path)
m.directory File.join('app/helpers', model_controller_class_path)
m.directory File.join('app/views', model_controller_class_path, model_controller_file_name)
m.directory File.join('test/functional', model_controller_class_path)
m.directory File.join('test/unit', class_path)

m.template 'model.rb',
File.join('app/models',
class_path,
"#{file_name}.rb")

m.template 'controller.rb',
File.join('app/controllers',
controller_class_path,
"#{controller_file_name}_controller.rb")

m.template 'model_controller.rb',
File.join('app/controllers',
model_controller_class_path,
"#{model_controller_file_name}_controller.rb")

m.template 'authenticated_system.rb',
File.join('lib', 'authenticated_system.rb')

m.template 'authenticated_test_helper.rb',
File.join('lib', 'authenticated_test_helper.rb')

m.template 'functional_test.rb',
File.join('test/functional',
controller_class_path,
"#{controller_file_name}_controller_test.rb")

m.template 'model_functional_test.rb',
File.join('test/functional',
model_controller_class_path,
"#{model_controller_file_name}_controller_test.rb")

m.template 'helper.rb',
File.join('app/helpers',
controller_class_path,
"#{controller_file_name}_helper.rb")

m.template 'model_helper.rb',
File.join('app/helpers',
model_controller_class_path,
"#{model_controller_file_name}_helper.rb")

m.template 'unit_test.rb',
File.join('test/unit',
class_path,
"#{file_name}_test.rb")

m.template 'fixtures.yml',
File.join('test/fixtures',
"#{table_name}.yml")

# Controller templates
m.template 'login.rhtml', File.join('app/views', controller_class_path, controller_file_name, "new.rhtml")
m.template 'signup.rhtml', File.join('app/views', model_controller_class_path, model_controller_file_name, "new.rhtml")

unless options[:skip_migration]
m.migration_template 'migration.rb', 'db/migrate', :assigns => {
:migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}"
}, :migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}"
end
end

puts
puts ("-" * 70)
puts "Don't forget the restful routes in config.routes.rb"
puts
puts " map.resources :#{model_controller_file_name}, :#{controller_file_name}"
puts
puts "Try these for some familiar login URLs if you like:"
puts
puts " map.signup '/signup', :controller => '#{model_controller_file_name}', :action => 'new'"
puts " map.login '/login', :controller => '#{controller_file_name}', :action => 'new'"
puts " map.logout '/logout', :controller => '#{controller_file_name}', :action => 'destroy'"
puts
puts ("-" * 70)
puts

recorded_session
end

protected
# Override with your own usage banner.
def banner
"Usage: #{$0} authenticated ModelName ControllerName"
end
end
131 changes: 131 additions & 0 deletions generators/authenticated/templates/authenticated_system.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
module AuthenticatedSystem
protected
# Returns true or false if the user is logged in.
# Preloads @current_<%= file_name %> with the user model if they're logged in.
def logged_in?
(@current_<%= file_name %> ||= session[:<%= file_name %>] ? <%= class_name %>.find_by_id(session[:<%= file_name %>]) : :false).is_a?(<%= class_name %>)
end
# Accesses the current <%= file_name %> from the session.
def current_<%= file_name %>
@current_<%= file_name %> if logged_in?
end

# Store the given <%= file_name %> in the session.
def current_<%= file_name %>=(new_<%= file_name %>)
session[:<%= file_name %>] = new_<%= file_name %>.nil? ? nil : new_<%= file_name %>.id
@current_<%= file_name %> = new_<%= file_name %>
end

# Check if the <%= file_name %> is authorized.
#
# Override this method in your controllers if you want to restrict access
# to only a few actions or if you want to check if the <%= file_name %>
# has the correct rights.
#
# Example:
#
# # only allow nonbobs
# def authorize?
# current_<%= file_name %>.login != "bob"
# end
def authorized?
true
end

# Filter method to enforce a login requirement.
#
# To require logins for all actions, use this in your controllers:
#
# before_filter :login_required
#
# To require logins for specific actions, use this in your controllers:
#
# before_filter :login_required, :only => [ :edit, :update ]
#
# To skip this in a subclassed controller:
#
# skip_before_filter :login_required
#
def login_required
username, passwd = get_auth_data
self.current_<%= file_name %> ||= <%= class_name %>.authenticate(username, passwd) || :false if username && passwd
logged_in? && authorized? ? true : access_denied
end

# Redirect as appropriate when an access request fails.
#
# The default action is to redirect to the login screen.
#
# Override this method in your controllers if you want to have special
# behavior in case the <%= file_name %> is not authorized
# to access the requested action. For example, a popup window might
# simply close itself.
def access_denied
respond_to do |accepts|
accepts.html do
store_location
redirect_to :controller => '<%= controller_file_name %>', :action => 'login'
end
accepts.xml do
headers["Status"] = "Unauthorized"
headers["WWW-Authenticate"] = %(Basic realm="Web Password")
render :text => "Could't authenticate you", :status => '401 Unauthorized'
end
end
false
end

# Store the URI of the current request in the session.
#
# We can return to this location by calling #redirect_back_or_default.
def store_location
session[:return_to] = request.request_uri
end

# Redirect to the URI stored by the most recent store_location call or
# to the passed default.
def redirect_back_or_default(default)
session[:return_to] ? redirect_to_url(session[:return_to]) : redirect_to(default)
session[:return_to] = nil
end

# Inclusion hook to make #current_<%= file_name %> and #logged_in?
# available as ActionView helper methods.
def self.included(base)
base.send :helper_method, :current_<%= file_name %>, :logged_in?
end

# When called with before_filter :login_from_cookie will check for an :auth_token
# cookie and log the user back in if apropriate
def login_from_cookie
return unless cookies[:auth_token] && !logged_in?
user = <%= class_name %>.find_by_remember_token(cookies[:auth_token])
if user && user.remember_token?
user.remember_me
self.current_<%= file_name %> = user
cookies[:auth_token] = { :value => self.current_<%= file_name %>.remember_token , :expires => self.current_<%= file_name %>.remember_token_expires_at }
flash[:notice] = "Logged in successfully"
end
end

private
# gets BASIC auth info
def get_auth_data
user, pass = nil, nil
# extract authorisation credentials
if request.env.has_key? 'X-HTTP_AUTHORIZATION'
# try to get it where mod_rewrite might have put it
authdata = request.env['X-HTTP_AUTHORIZATION'].to_s.split
elsif request.env.has_key? 'HTTP_AUTHORIZATION'
# this is the regular location
authdata = request.env['HTTP_AUTHORIZATION'].to_s.split
end

# at the moment we only support basic authentication
if authdata && authdata[0] == 'Basic'
user, pass = Base64.decode64(authdata[1]).split(':')[0..1]
end
return [user, pass]
end
end
Loading

0 comments on commit 2366199

Please sign in to comment.