simple_auth 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown ADDED
@@ -0,0 +1,136 @@
1
+ Simple Auth
2
+ ===========
3
+
4
+ SimpleAuth is an authentication library to be used when Authlogic & Devise are just too complicated.
5
+
6
+ This library only supports in-site authentication and won't implement OpenID, Facebook Connect and like.
7
+
8
+ Installation
9
+ ------------
10
+
11
+ As plugin:
12
+
13
+ script/plugin install git://github.com/fnando/simple_auth.git
14
+
15
+ As gem:
16
+
17
+ sudo gem install simple_auth
18
+
19
+ Then run `script/generate simple_auth` to copy the initializer file.
20
+
21
+ Usage
22
+ -----
23
+
24
+ Your user model should have the attributes `password_hash` and `password_salt`. The credential field can be anything you want, but SimpleAuth uses `[:email, :login]` by default.
25
+
26
+ class CreateUsers < ActiveRecord::Migration
27
+ def self.up
28
+ create_table :users do |t|
29
+ t.string :email
30
+ t.string :login
31
+ t.string :password_hash
32
+ t.string :password_salt
33
+
34
+ t.timestamps
35
+ end
36
+
37
+ add_index :users, :email
38
+ add_index :users, :login
39
+ add_index :users, [:email, :login]
40
+ end
41
+
42
+ def self.down
43
+ drop_table :users
44
+ end
45
+ end
46
+
47
+ If your user model is other than `User`, you have to set it in your `config/initializer/simple_auth.rb` initializer file.
48
+ You can also set up the credentials attributes.
49
+
50
+ SimpleAuth.setup do |config|
51
+ config.model = :account
52
+ config.credentials = [:username]
53
+ end
54
+
55
+ On your model, call the method `has_authentication`.
56
+
57
+ class User < ActiveRecord::Base
58
+ has_authentication
59
+ end
60
+
61
+ This will add some callbacks and password validations.
62
+
63
+ After you set up the model, you can go the controller.
64
+
65
+ class SessionsController < ApplicationController
66
+ def new
67
+ @user_session = SimpleAuth::Session.new
68
+ end
69
+
70
+ def create
71
+ @user_session = SimpleAuth::Session.new(params[:session])
72
+
73
+ if @user_session.save
74
+ redirect_to dashboard_path
75
+ else
76
+ flash[:warning] = "Invalid username or password"
77
+ render :new
78
+ end
79
+ end
80
+
81
+ def destroy
82
+ current_session.destroy if logged_in?
83
+ redirect_to root_path
84
+ end
85
+ end
86
+
87
+ There are some helpers:
88
+
89
+ logged_in? # controller & views
90
+ current_user # controller & views
91
+ current_session # controller & views
92
+ when_logged(&block) # views
93
+
94
+ Troubleshooting
95
+ ---------------
96
+
97
+ You may receive strange errors related to `can't dup NilClass` or `You have a nil object when you didn't expect it!`. This will occur only on development mode and is an ActiveRecord bug that hasn't been fixed. Open the ActiveRecord file `activerecord-2.3.5/lib/active_record/base.rb` and comment the lines 411-412:
98
+
99
+ klass.instance_variables.each { |var| klass.send(:remove_instance_variable, var) }
100
+ klass.instance_methods(false).each { |m| klass.send :undef_method, m }
101
+
102
+ Dirty, but it works. Here's the ticket for this issue: [LINK TO LIGHTHOUSE TICKET]
103
+
104
+ To-Do
105
+ -----
106
+
107
+ * Write README
108
+
109
+ Maintainer
110
+ ----------
111
+
112
+ * Nando Vieira (<http://simplesideias.com.br>)
113
+
114
+ License:
115
+ --------
116
+
117
+ (The MIT License)
118
+
119
+ Permission is hereby granted, free of charge, to any person obtaining
120
+ a copy of this software and associated documentation files (the
121
+ 'Software'), to deal in the Software without restriction, including
122
+ without limitation the rights to use, copy, modify, merge, publish,
123
+ distribute, sublicense, and/or sell copies of the Software, and to
124
+ permit persons to whom the Software is furnished to do so, subject to
125
+ the following conditions:
126
+
127
+ The above copyright notice and this permission notice shall be
128
+ included in all copies or substantial portions of the Software.
129
+
130
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
131
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
132
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
133
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
134
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
135
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
136
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,39 @@
1
+ require 'rake'
2
+ require 'spec/rake/spectask'
3
+
4
+ require 'jeweler'
5
+ require File.dirname(__FILE__) + '/lib/simple_auth/version'
6
+
7
+
8
+ desc 'Default: run specs.'
9
+ task :default => :spec
10
+
11
+ desc 'Run the specs'
12
+ Spec::Rake::SpecTask.new(:spec) do |t|
13
+ t.spec_opts = ['--colour --format specdoc --loadby mtime --reverse']
14
+ t.spec_files = FileList['spec/**/*_spec.rb']
15
+ end
16
+
17
+ JEWEL = Jeweler::Tasks.new do |gem|
18
+ gem.name = "simple_auth"
19
+ gem.version = SimpleAuth::Version::STRING
20
+ gem.summary = "A simple authentication system for Rails apps"
21
+ gem.description = <<-TXT
22
+ When Authlogic & Devise are just too much.
23
+ TXT
24
+
25
+ gem.authors = ["Nando Vieira"]
26
+ gem.email = "fnando.vieira@gmail.com"
27
+ gem.homepage = "http://github.com/fnando/simple_auth"
28
+
29
+ gem.has_rdoc = false
30
+ gem.files = %w(Rakefile simple_auth.gemspec init.rb VERSION README.markdown) + Dir["{generators,lib,spec,app,config}/**/*"]
31
+ end
32
+
33
+ desc "Generate gemspec and build gem"
34
+ task :build_gem do
35
+ File.open("VERSION", "w+") {|f| f << SimpleAuth::Version::STRING }
36
+
37
+ Rake::Task["gemspec"].invoke
38
+ Rake::Task["build"].invoke
39
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,10 @@
1
+ module SimpleAuthHelper
2
+ # Renders the specified block for logged users.
3
+ #
4
+ # <% when_logged do %>
5
+ # <!-- content for logged users -->
6
+ # <% end %>
7
+ def when_logged(&block)
8
+ capture(&block) if logged_in?
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ en:
2
+ simple_auth:
3
+ sessions:
4
+ need_to_be_logged: "You need to be logged"
5
+ invalid_credentials: "Invalid username or password"
@@ -0,0 +1,11 @@
1
+ pt: &pt
2
+ simple_auth:
3
+ sessions:
4
+ need_to_be_logged: "Você precisa estar logado"
5
+ invalid_credentials: "Usuário ou senha inválidos"
6
+
7
+ pt-BR:
8
+ <<: *pt
9
+
10
+ pt-PT:
11
+ <<: *pt
@@ -0,0 +1,5 @@
1
+ Description:
2
+ Create an initializer file for SimpleAuth library.
3
+
4
+ Examples:
5
+ script/generate simple_auth
@@ -0,0 +1,7 @@
1
+ class SimpleAuthGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ m.file "simple_auth.rb", "config/initializers/simple_auth.rb"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ # Use this file to setup SimpleAuth.
2
+ SimpleAuth.setup do |config|
3
+ # Generate the password hash. The specified block should expected
4
+ # the plain password and the password hash as block parameters.
5
+ # config.crypter = proc {|password, salt| Digest::SHA256.hexdigest("#{password}--#{salt}") }
6
+
7
+ # Generate the password salt. The specified block should expect
8
+ # the ActiveRecord instance as block parameter.
9
+ # config.salt = proc {|r| Digest::SHA256.hexdigest("#{Time.now.to_s}--#{r.email}")}
10
+
11
+ # Set which attributes will be used for authentication.
12
+ config.credentials = [:email, :login]
13
+
14
+ # Set the User model that should be used
15
+ config.model = :user
16
+
17
+ # Set the login url
18
+ config.redirect_to = proc { login_path }
19
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require "simple_auth"
@@ -0,0 +1,18 @@
1
+ require "digest/sha2"
2
+ require "simple_auth/config"
3
+ require "simple_auth/active_record"
4
+ require "simple_auth/session"
5
+ require "simple_auth/version"
6
+
7
+ module SimpleAuth
8
+ class NotAuthorized < Exception; end
9
+ end
10
+
11
+ ActiveRecord::Base.send :include, SimpleAuth::ActiveRecord::InstanceMethods
12
+ ActiveRecord::Base.send :extend, SimpleAuth::ActiveRecord::ClassMethods
13
+
14
+ ActionController::Base.send :include, SimpleAuth::ActionController::Implementation
15
+ ActionController::Base.send :include, SimpleAuth::ActionController::InstanceMethods
16
+ ActionController::Base.send :extend, SimpleAuth::ActionController::ClassMethods
17
+
18
+ I18n.load_path += Dir[File.dirname(__FILE__) + "/../config/locales/*.yml"]
@@ -0,0 +1,81 @@
1
+ module SimpleAuth
2
+ module ActionController
3
+ module Implementation
4
+ def self.included(klass)
5
+ klass.prepend_before_filter :activate_simple_auth
6
+ klass.helper_method :current_user, :current_session, :logged_in?
7
+ end
8
+ end
9
+
10
+ module InstanceMethods
11
+ private
12
+ def current_session
13
+ @current_session ||= SimpleAuth::Session.find
14
+ end
15
+
16
+ def current_user
17
+ current_session && current_session.record
18
+ end
19
+
20
+ def authorized?
21
+ true
22
+ end
23
+
24
+ def logged_in?
25
+ current_user != nil
26
+ end
27
+
28
+ def activate_simple_auth
29
+ SimpleAuth::Config.controller = self
30
+ end
31
+
32
+ def simple_auth_path(controller, path)
33
+ path ||= SimpleAuth::Config.redirect_to
34
+ path = controller.instance_eval(&path) if path.kind_of?(Proc)
35
+ path
36
+ end
37
+ end
38
+
39
+ module ClassMethods
40
+ # Redirect unlogged users to the specified :to path
41
+ #
42
+ # require_logged_user :to => proc { login_path }
43
+ # require_logged_user :to => {:controller => "session", :action => "new"}
44
+ # require_logged_user :only => [:index], :to => login_path
45
+ # require_logged_user :except => [:public], :to => login_path
46
+ #
47
+ # You can set :to globally:
48
+ #
49
+ # SimpleAuth::Config.redirect_to = {:controller => "session", :action => "new"}
50
+ # SimpleAuth::Config.redirect_to = proc { login_path }
51
+ def require_logged_user(options = {})
52
+ before_filter(options.except(:to)) do |c|
53
+ c.instance_eval do
54
+ path = simple_auth_path(c, options[:to])
55
+
56
+ unless logged_in? && authorized?
57
+ flash[:warning] = I18n.translate("simple_auth.sessions.need_to_be_logged")
58
+ session[:return_to] = request.request_uri if request.get?
59
+ redirect_to path
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ # Redirect logged users to the specified :to path
66
+ #
67
+ # redirect_logged_user :to => proc { login_path }
68
+ # redirect_logged_user :to => {:controller => "dashboard"}
69
+ # redirect_logged_user :only => [:index], :to => login_path
70
+ # redirect_logged_user :except => [:public], :to => login_path
71
+ def redirect_logged_user(options = {})
72
+ before_filter(options.except(:to)) do |c|
73
+ c.instance_eval do
74
+ path = simple_auth_path(c, options[:to])
75
+ redirect_to path if logged_in?
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,80 @@
1
+ module SimpleAuth
2
+ module ActiveRecord
3
+ module InstanceMethods
4
+ private
5
+ def encrypt_password
6
+ self.password_salt = SimpleAuth::Config.salt.call(self)
7
+ self.password_hash = SimpleAuth::Config.crypter.call(password, password_salt)
8
+ end
9
+
10
+ def erase_password
11
+ self.password = nil
12
+ self.password_confirmation = nil
13
+ end
14
+
15
+ def validate_password?
16
+ new_record? || password.present?
17
+ end
18
+ end
19
+
20
+ module ClassMethods
21
+ # Receive a credential and a password and try to authenticate the specified user.
22
+ # If the credential is valid, then an user is returned; otherwise nil is returned.
23
+ #
24
+ # User.authenticate "johndoe", "test"
25
+ # User.authenticate "john@doe.com", "test"
26
+ def authenticate(credential, password)
27
+ # Build a hash that will be passed to the finder
28
+ options = {:conditions => [[], {}]}
29
+
30
+ # Iterate each attribute that should be used as credential
31
+ # and set it to the finder conditions hash
32
+ SimpleAuth::Config.credentials.each do |attr_name|
33
+ options[:conditions][0] << "#{attr_name} = :#{attr_name}"
34
+ options[:conditions][1][attr_name] = credential
35
+ end
36
+
37
+ # Join the attributes in OR query
38
+ options[:conditions][0] = options[:conditions][0].join(" OR ")
39
+
40
+ # Find the record using the conditions we built
41
+ record = SimpleAuth::Config.model_class.first(options)
42
+
43
+ # If no record has been found
44
+ return nil unless record
45
+
46
+ # Compare password
47
+ return nil unless record.password_hash == SimpleAuth::Config.crypter.call(password, record.password_salt)
48
+
49
+ return record
50
+ end
51
+
52
+ # Set virtual attributes, callbacks and acts as a wrapper for
53
+ # SimpleAuth::Config if a block is provided.
54
+ #
55
+ # class User < ActiveRecord::Base
56
+ # has_authentication
57
+ # end
58
+ #
59
+ # class User < ActiveRecord::Base
60
+ # has_authentication do |config|
61
+ # config.credentials = [:email]
62
+ # end
63
+ # end
64
+ def has_authentication(&block)
65
+ attr_accessor :password
66
+ attr_accessor :password_confirmation
67
+
68
+ SimpleAuth.setup(&block)
69
+
70
+ before_save :encrypt_password, :if => :validate_password?
71
+ after_save :erase_password
72
+
73
+ validates_presence_of :password, :if => :validate_password?
74
+ validates_length_of :password, :if => :validate_password?, :minimum => 4, :allow_blank => true
75
+ validates_presence_of :password_confirmation, :if => :validate_password?
76
+ validates_confirmation_of :password, :if => :validate_password?
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,46 @@
1
+ module SimpleAuth
2
+ # Add a shortcut to Authorization::Config
3
+ def self.setup(&block)
4
+ yield SimpleAuth::Config if block_given?
5
+ end
6
+
7
+ class Config
8
+ # Generate the password hash. The specified block should expected
9
+ # the plain password and the password hash as block parameters.
10
+ cattr_accessor :crypter
11
+ @@crypter = proc do |password, salt|
12
+ Digest::SHA256.hexdigest [password, salt].join("--")
13
+ end
14
+
15
+ # Generate the password salt. The specified block should expect
16
+ # the ActiveRecord instance as block parameter.
17
+ cattr_accessor :salt
18
+ @@salt = proc do |record|
19
+ Digest::SHA256.hexdigest [Time.to_s, ActiveSupport::SecureRandom.hex(32)].join("--")
20
+ end
21
+
22
+ # Set which attributes will be used for authentication.
23
+ cattr_accessor :credentials
24
+ @@credentials = [:email, :login]
25
+
26
+ # Set the user model
27
+ cattr_accessor :model
28
+ @@model = :user
29
+
30
+ # Set the current controller object
31
+ cattr_accessor :controller
32
+ @@controller = nil
33
+
34
+ # Set the login url
35
+ cattr_accessor :redirect_to
36
+ @@redirect_to = proc { login_path }
37
+
38
+ # Reset session before saving the user session
39
+ cattr_accessor :reset_session
40
+ @@reset_session = false
41
+
42
+ def self.model_class
43
+ model.to_s.classify.constantize
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,114 @@
1
+ module SimpleAuth
2
+ class Session
3
+ attr_accessor :credential
4
+ attr_accessor :password
5
+ attr_accessor :model
6
+ attr_accessor :controller
7
+ attr_accessor :record
8
+ attr_accessor :errors
9
+
10
+ class Errors
11
+ attr_accessor :errors
12
+
13
+ def add_to_base(message)
14
+ @errors << message
15
+ end
16
+
17
+ def initialize
18
+ @errors = []
19
+ end
20
+
21
+ def on(attr_name)
22
+ nil
23
+ end
24
+
25
+ def full_messages
26
+ @errors
27
+ end
28
+
29
+ def empty?
30
+ @errors.empty?
31
+ end
32
+ end
33
+
34
+ def self.find
35
+ session = new
36
+ session.record = session.model.find_by_id(session.controller.session[:record_id])
37
+
38
+ if session.record
39
+ session
40
+ else
41
+ nil
42
+ end
43
+ end
44
+
45
+ def self.create(options = {})
46
+ returning new(options) do |session|
47
+ session.save
48
+ end
49
+ end
50
+
51
+ def self.create!(options = {})
52
+ returning new(options) do |session|
53
+ session.save!
54
+ end
55
+ end
56
+
57
+ def self.destroy!
58
+ controller = SimpleAuth::Config.controller
59
+ controller.session[:record_id] = nil
60
+ controller.instance_variable_set("@current_user", nil)
61
+ controller.instance_variable_set("@current_session", nil)
62
+ true
63
+ end
64
+
65
+ def initialize(options = {})
66
+ @credential = options[:credential]
67
+ @password = options[:password]
68
+ @controller = SimpleAuth::Config.controller
69
+ @model = SimpleAuth::Config.model_class
70
+ @errors = Errors.new
71
+ end
72
+
73
+ def new_record?
74
+ record.nil?
75
+ end
76
+
77
+ def valid?
78
+ if record
79
+ true
80
+ else
81
+ errors.add_to_base I18n.translate("simple_auth.sessions.invalid_credentials")
82
+ false
83
+ end
84
+ end
85
+
86
+ def record
87
+ @record ||= model.authenticate(credential, password)
88
+ end
89
+
90
+ def save
91
+ if valid?
92
+ controller.send(:reset_session) if SimpleAuth::Config.reset_session
93
+ controller.session[:record_id] = record.id
94
+ end
95
+
96
+ controller.session[:record_id] != nil
97
+ end
98
+
99
+ def save!
100
+ if valid?
101
+ save
102
+ else
103
+ raise SimpleAuth::NotAuthorized
104
+ end
105
+ end
106
+
107
+ def destroy
108
+ @record = nil
109
+ @credential = nil
110
+ @password = nil
111
+ self.class.destroy!
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,8 @@
1
+ module SimpleAuth
2
+ module Version
3
+ MAJOR = "0"
4
+ MINOR = "1"
5
+ PATCH = "0"
6
+ STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
7
+ end
8
+ end
@@ -0,0 +1,74 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{simple_auth}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Nando Vieira"]
12
+ s.date = %q{2010-01-04}
13
+ s.description = %q{When Authlogic & Devise are just too much.
14
+ }
15
+ s.email = %q{fnando.vieira@gmail.com}
16
+ s.extra_rdoc_files = [
17
+ "README.markdown"
18
+ ]
19
+ s.files = [
20
+ "README.markdown",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "app/helpers/simple_auth_helper.rb",
24
+ "config/locales/en.yml",
25
+ "config/locales/pt.yml",
26
+ "generators/simple_auth/USAGE",
27
+ "generators/simple_auth/simple_auth_generator.rb",
28
+ "generators/simple_auth/templates/simple_auth.rb",
29
+ "init.rb",
30
+ "lib/simple_auth.rb",
31
+ "lib/simple_auth/action_controller.rb",
32
+ "lib/simple_auth/active_record.rb",
33
+ "lib/simple_auth/config.rb",
34
+ "lib/simple_auth/session.rb",
35
+ "lib/simple_auth/version.rb",
36
+ "simple_auth.gemspec",
37
+ "spec/resources/controllers.rb",
38
+ "spec/resources/user.rb",
39
+ "spec/schema.rb",
40
+ "spec/simple_auth/action_controller_spec.rb",
41
+ "spec/simple_auth/active_record_spec.rb",
42
+ "spec/simple_auth/config_spec.rb",
43
+ "spec/simple_auth/session_spec.rb",
44
+ "spec/simple_auth/simple_auth_helper_spec.rb",
45
+ "spec/spec_helper.rb"
46
+ ]
47
+ s.homepage = %q{http://github.com/fnando/simple_auth}
48
+ s.rdoc_options = ["--charset=UTF-8"]
49
+ s.require_paths = ["lib"]
50
+ s.rubygems_version = %q{1.3.5}
51
+ s.summary = %q{A simple authentication system for Rails apps}
52
+ s.test_files = [
53
+ "spec/resources/controllers.rb",
54
+ "spec/resources/user.rb",
55
+ "spec/schema.rb",
56
+ "spec/simple_auth/action_controller_spec.rb",
57
+ "spec/simple_auth/active_record_spec.rb",
58
+ "spec/simple_auth/config_spec.rb",
59
+ "spec/simple_auth/session_spec.rb",
60
+ "spec/simple_auth/simple_auth_helper_spec.rb",
61
+ "spec/spec_helper.rb"
62
+ ]
63
+
64
+ if s.respond_to? :specification_version then
65
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
66
+ s.specification_version = 3
67
+
68
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
69
+ else
70
+ end
71
+ else
72
+ end
73
+ end
74
+
@@ -0,0 +1,31 @@
1
+ # Add routes
2
+ ActionController::Routing::Routes.add_route "/:controller/:action/:id"
3
+ ActionController::Routing::Routes.add_named_route :login, "/login", :controller => "session", :action => "new"
4
+ ActionController::Routing::Routes.add_named_route :dashboard, "/dashboard", :controller => "dashboard", :action => "index"
5
+
6
+ class SampleController < ActionController::Base
7
+ end
8
+
9
+ class SessionController < ActionController::Base
10
+ redirect_logged_user :to => {:controller => "dashboard"}
11
+
12
+ def new
13
+ @user_session = SimpleAuth::Session.new
14
+ end
15
+
16
+ def create
17
+ @user_session = SimpleAuth::Session.new(params[:session])
18
+
19
+ if @user_session.save
20
+ redirect_to session.delete(:return_to) || dashboard_path
21
+ else
22
+ flash[:warning] = "Invalid login/password."
23
+ render :new
24
+ end
25
+ end
26
+ end
27
+
28
+ class DashboardController < ActionController::Base
29
+ def index
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ class User < ActiveRecord::Base
2
+ has_authentication
3
+ end
data/spec/schema.rb ADDED
@@ -0,0 +1,5 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+ create_table :users do |t|
3
+ t.string :email, :login, :password_hash, :password_salt, :username
4
+ end
5
+ end
@@ -0,0 +1,103 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe SimpleAuth::ActionController, :type => :controller do
4
+ before do
5
+ @user = User.create(
6
+ :login => "johndoe",
7
+ :email => "john@doe.com",
8
+ :password => "test",
9
+ :password_confirmation => "test"
10
+ )
11
+ end
12
+
13
+ describe "require_logged_user" do
14
+ controller_name :dashboard
15
+
16
+ context "unlogged user" do
17
+ before do
18
+ DashboardController.filter_chain.pop if DashboardController.filter_chain.count > 1
19
+ end
20
+
21
+ context "return to" do
22
+ before do
23
+ DashboardController.require_logged_user :to => "/login"
24
+ end
25
+
26
+ it "should set return to" do
27
+ get :index
28
+ session[:return_to].should == "/dashboard"
29
+ end
30
+
31
+ it "should set warning message" do
32
+ get :index
33
+ flash[:warning].should == "You need to be logged"
34
+ end
35
+
36
+ it "should redirect when user is not authorized" do
37
+ controller.should_receive(:logged_in?).and_return(true)
38
+ controller.should_receive(:authorized?).and_return(false)
39
+
40
+ get :index
41
+ response.should redirect_to("/login")
42
+ end
43
+ end
44
+
45
+ it "should be redirected [hash]" do
46
+ DashboardController.require_logged_user :to => {:controller => "session", :action => "new"}
47
+
48
+ get :index
49
+ response.should redirect_to("/session/new")
50
+ end
51
+
52
+ it "should be redirected [block]" do
53
+ DashboardController.require_logged_user :to => proc { login_path }
54
+
55
+ get :index
56
+ response.should redirect_to("/login")
57
+ end
58
+
59
+ it "should be redirected [string]" do
60
+ DashboardController.require_logged_user :to => "/login"
61
+
62
+ get :index
63
+ response.should redirect_to("/login")
64
+ end
65
+ end
66
+
67
+ context "logged user" do
68
+ before do
69
+ session[:record_id] = @user.id
70
+ get :index
71
+ end
72
+
73
+ it "should render page" do
74
+ response.should render_template(:index)
75
+ end
76
+ end
77
+ end
78
+
79
+ describe "redirect_logged_users" do
80
+ controller_name :session
81
+
82
+ context "unlogged user" do
83
+ before do
84
+ get :new
85
+ end
86
+
87
+ it "should render page" do
88
+ response.should render_template(:new)
89
+ end
90
+ end
91
+
92
+ context "logged user" do
93
+ before do
94
+ session[:record_id] = @user.id
95
+ get :new
96
+ end
97
+
98
+ it "should be redirected" do
99
+ response.should redirect_to("/dashboard")
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,85 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe SimpleAuth::ActiveRecord do
4
+ context "new record" do
5
+ subject { User.new }
6
+
7
+ before do
8
+ subject.should_not be_valid
9
+ end
10
+
11
+ it "should require password" do
12
+ subject.should have(1).error_on(:password)
13
+ end
14
+
15
+ it "should require password to be at least 4-chars long" do
16
+ subject.password = "123"
17
+ subject.should_not be_valid
18
+ subject.should have(1).error_on(:password)
19
+ end
20
+
21
+ it "should require password confirmation not to be empty" do
22
+ subject.password_confirmation = ""
23
+ subject.should have(1).error_on(:password_confirmation)
24
+ end
25
+
26
+ it "should require password confirmation not to be nil" do
27
+ subject.password_confirmation = nil
28
+ subject.should have(1).error_on(:password_confirmation)
29
+ end
30
+
31
+ it "should unset password after saving" do
32
+ subject = User.new(:password => "test", :password_confirmation => "test")
33
+ subject.save(false)
34
+ subject.password.should be_nil
35
+ subject.password_confirmation.should be_nil
36
+ end
37
+ end
38
+
39
+ context "existing record" do
40
+ subject {
41
+ User.new(
42
+ :email => "john@doe.com",
43
+ :login => "johndoe",
44
+ :password => "test",
45
+ :password_confirmation => "test",
46
+ :username => "john"
47
+ )
48
+ }
49
+
50
+ before do
51
+ subject.save!
52
+ end
53
+
54
+ it "should not require password when it hasn't changed" do
55
+ subject.login = "john"
56
+ subject.should be_valid
57
+ end
58
+
59
+ it "should not require password confirmation when it has changed" do
60
+ subject.password = "newpass"
61
+ subject.should have(1).error_on(:password_confirmation)
62
+ end
63
+
64
+ it "should authenticate using email" do
65
+ User.authenticate("john@doe.com", "test").should == subject
66
+ end
67
+
68
+ it "should authenticate using login" do
69
+ User.authenticate("johndoe", "test").should == subject
70
+ end
71
+
72
+ it "should authenticate using custom attribute" do
73
+ SimpleAuth::Config.credentials = [:username]
74
+ User.authenticate("john", "test").should == subject
75
+ end
76
+
77
+ it "should not authenticate using invalid credential" do
78
+ User.authenticate("invalid", "test").should be_nil
79
+ end
80
+
81
+ it "should not authenticate using wrong password" do
82
+ User.authenticate("johndoe", "invalid").should be_nil
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,29 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe SimpleAuth::Config do
4
+ it "should yield SimpleAuth::Config class" do
5
+ SimpleAuth.setup do |config|
6
+ config.should == SimpleAuth::Config
7
+ end
8
+ end
9
+
10
+ it "should use [:email, :login] as credential attributes" do
11
+ SimpleAuth::Config.credentials.should == [:email, :login]
12
+ end
13
+
14
+ it "should use User as default model" do
15
+ SimpleAuth::Config.model.should == :user
16
+ end
17
+
18
+ specify "crypter should expect 2 block arguments" do
19
+ SimpleAuth::Config.crypter.arity.should == 2
20
+ end
21
+
22
+ specify "salt should expect 1 block argument" do
23
+ SimpleAuth::Config.salt.arity.should == 1
24
+ end
25
+
26
+ specify "salt should return a 64-char long salt" do
27
+ SimpleAuth::Config.salt.call(nil).size.should == 64
28
+ end
29
+ end
@@ -0,0 +1,140 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe SimpleAuth::Session do
4
+ before do
5
+ @user = User.create!(
6
+ :login => "johndoe",
7
+ :email => "john@doe.com",
8
+ :password => "test",
9
+ :password_confirmation => "test"
10
+ )
11
+
12
+ @session = Hash.new
13
+ @controller = SampleController.new
14
+ @controller.session = @session
15
+
16
+ SimpleAuth::Config.controller = @controller
17
+ @user_session = SimpleAuth::Session.new(:credential => "johndoe", :password => "test")
18
+ end
19
+
20
+ context "valid credentials" do
21
+ before do
22
+ @user_session.save!
23
+ end
24
+
25
+ it "should return existing session" do
26
+ @user_session = SimpleAuth::Session.find
27
+ @user_session.should be_valid
28
+ @user_session.record.should == @user
29
+ end
30
+
31
+ it "should not be new record" do
32
+ @user_session.should_not be_new_record
33
+ end
34
+
35
+ it "should find record" do
36
+ @user_session.record.should == @user
37
+ end
38
+
39
+ it "should be a valid session" do
40
+ @user_session.should be_valid
41
+ end
42
+
43
+ it "should set record_id on session" do
44
+ @session[:record_id].should == @user.id
45
+ end
46
+
47
+ it "should be saved" do
48
+ @user_session.save.should be_true
49
+ end
50
+
51
+ it "should automatically save session when calling create!" do
52
+ @user_session = SimpleAuth::Session.create!(:credential => "johndoe", :password => "test")
53
+ @user_session.should be_valid
54
+ @user_session.record.should == @user
55
+ @session[:record_id].should == @user.id
56
+ end
57
+
58
+ it "should reset session" do
59
+ SimpleAuth::Config.reset_session = true
60
+ SimpleAuth::Config.controller.should_receive(:reset_session)
61
+ @user_session.save
62
+ end
63
+
64
+ it "should destroy session" do
65
+ @user_session.destroy.should be_true
66
+ @user_session.record.should be_nil
67
+ @session[:record_id].should be_nil
68
+ end
69
+ end
70
+
71
+ context "invalid credentials" do
72
+ before do
73
+ @user_session.credential = "invalid"
74
+ @user_session.save
75
+ end
76
+
77
+ it "should be new record" do
78
+ SimpleAuth::Session.new.should be_new_record
79
+ @user_session.should be_new_record
80
+ end
81
+
82
+ it "should have error message" do
83
+ @user_session.errors.full_messages[0].should == "Invalid username or password"
84
+ end
85
+
86
+ it "should not return error messages for attributes" do
87
+ @user_session.errors.on(:credential).should be_nil
88
+ @user_session.errors.on(:password).should be_nil
89
+ end
90
+
91
+ it "should have errors" do
92
+ @user_session.errors.should_not be_empty
93
+ end
94
+
95
+ it "should not find existing session" do
96
+ SimpleAuth::Session.find.should be_nil
97
+ end
98
+
99
+ it "should not find record" do
100
+ @user_session.record.should be_nil
101
+ end
102
+
103
+ it "should not be a valid session" do
104
+ @user_session.should_not be_valid
105
+ end
106
+
107
+ it "should unset record_id from session" do
108
+ @session[:record_id].should be_nil
109
+ end
110
+
111
+ it "should not be saved" do
112
+ @user_session.save.should be_false
113
+ end
114
+
115
+ it "should raise error with save!" do
116
+ doing { @user_session.save! }.should raise_error(SimpleAuth::NotAuthorized)
117
+ end
118
+
119
+ it "should raise error with create!" do
120
+ doing { SimpleAuth::Session.create!({}) }.should raise_error(SimpleAuth::NotAuthorized)
121
+ end
122
+ end
123
+
124
+ context "destroying valid session" do
125
+ before do
126
+ @user_session.save!
127
+ @user_session.destroy
128
+ end
129
+
130
+ it "should unset record_id from session" do
131
+ @session[:record_id].should be_nil
132
+ end
133
+
134
+ it "should unset current_user instance variable" do
135
+ SimpleAuth::Config.controller.send(:current_user).should be_nil
136
+ SimpleAuth::Config.controller.instance_variable_get("@current_user").should be_nil
137
+ SimpleAuth::Config.controller.instance_variable_get("@current_session").should be_nil
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,13 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe SimpleAuthHelper, :type => :helper do
4
+ it "should render block when user is logged" do
5
+ helper.should_receive(:logged_in?).and_return(true)
6
+ helper.when_logged { "logged" }.should == "logged"
7
+ end
8
+
9
+ it "should not render block when user is unlogged" do
10
+ helper.should_receive(:logged_in?).and_return(false)
11
+ helper.when_logged { "logged" }.should be_nil
12
+ end
13
+ end
@@ -0,0 +1,30 @@
1
+ # Load application RSpec helper
2
+ begin
3
+ require File.dirname(__FILE__) + "/../../../../spec/spec_helper"
4
+ rescue LoadError
5
+ puts "Your application hasn't been bootstraped with RSpec.\nI'll do it on my own!\n\n"
6
+ system "cd '#{File.dirname(__FILE__) + "/../../../../"}' && script/generate rspec"
7
+ puts "\n\nRun `rake spec` again."
8
+ exit
9
+ end
10
+
11
+ # Establish connection with in memory SQLite 3 database
12
+ ActiveRecord::Base.establish_connection :adapter => "sqlite3", :database => ":memory:"
13
+
14
+ # Load database schema
15
+ load File.dirname(__FILE__) + "/schema.rb"
16
+
17
+ # Create an alias for lambda
18
+ alias :doing :lambda
19
+
20
+ # Load resources
21
+ require File.dirname(__FILE__) + "/resources/user"
22
+ require File.dirname(__FILE__) + "/resources/controllers"
23
+
24
+ # Restore default configuration
25
+ Spec::Runner.configure do |config|
26
+ config.before :each do
27
+ load File.dirname(__FILE__) + "/../lib/simple_auth/config.rb"
28
+ SimpleAuth::Config.model = :user
29
+ end
30
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple_auth
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Nando Vieira
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-01-04 00:00:00 -02:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: |
17
+ When Authlogic & Devise are just too much.
18
+
19
+ email: fnando.vieira@gmail.com
20
+ executables: []
21
+
22
+ extensions: []
23
+
24
+ extra_rdoc_files:
25
+ - README.markdown
26
+ files:
27
+ - README.markdown
28
+ - Rakefile
29
+ - VERSION
30
+ - app/helpers/simple_auth_helper.rb
31
+ - config/locales/en.yml
32
+ - config/locales/pt.yml
33
+ - generators/simple_auth/USAGE
34
+ - generators/simple_auth/simple_auth_generator.rb
35
+ - generators/simple_auth/templates/simple_auth.rb
36
+ - init.rb
37
+ - lib/simple_auth.rb
38
+ - lib/simple_auth/action_controller.rb
39
+ - lib/simple_auth/active_record.rb
40
+ - lib/simple_auth/config.rb
41
+ - lib/simple_auth/session.rb
42
+ - lib/simple_auth/version.rb
43
+ - simple_auth.gemspec
44
+ - spec/resources/controllers.rb
45
+ - spec/resources/user.rb
46
+ - spec/schema.rb
47
+ - spec/simple_auth/action_controller_spec.rb
48
+ - spec/simple_auth/active_record_spec.rb
49
+ - spec/simple_auth/config_spec.rb
50
+ - spec/simple_auth/session_spec.rb
51
+ - spec/simple_auth/simple_auth_helper_spec.rb
52
+ - spec/spec_helper.rb
53
+ has_rdoc: true
54
+ homepage: http://github.com/fnando/simple_auth
55
+ licenses: []
56
+
57
+ post_install_message:
58
+ rdoc_options:
59
+ - --charset=UTF-8
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ requirements: []
75
+
76
+ rubyforge_project:
77
+ rubygems_version: 1.3.5
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: A simple authentication system for Rails apps
81
+ test_files:
82
+ - spec/resources/controllers.rb
83
+ - spec/resources/user.rb
84
+ - spec/schema.rb
85
+ - spec/simple_auth/action_controller_spec.rb
86
+ - spec/simple_auth/active_record_spec.rb
87
+ - spec/simple_auth/config_spec.rb
88
+ - spec/simple_auth/session_spec.rb
89
+ - spec/simple_auth/simple_auth_helper_spec.rb
90
+ - spec/spec_helper.rb