authpwn_rails 0.9.6 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. data/.travis.yml +6 -0
  2. data/Gemfile +3 -2
  3. data/Gemfile.lock +38 -36
  4. data/README.rdoc +6 -11
  5. data/VERSION +1 -1
  6. data/authpwn_rails.gemspec +30 -22
  7. data/lib/authpwn_rails.rb +2 -2
  8. data/lib/authpwn_rails/credential_model.rb +38 -0
  9. data/lib/authpwn_rails/credentials.rb +10 -0
  10. data/lib/authpwn_rails/credentials/email.rb +30 -0
  11. data/lib/authpwn_rails/credentials/facebook.rb +77 -0
  12. data/lib/authpwn_rails/credentials/password.rb +63 -0
  13. data/lib/authpwn_rails/engine.rb +5 -7
  14. data/lib/authpwn_rails/facebook_session.rb +5 -5
  15. data/lib/authpwn_rails/generators/{session_generator.rb → all_generator.rb} +28 -9
  16. data/lib/authpwn_rails/generators/templates/001_create_users.rb +3 -11
  17. data/lib/authpwn_rails/generators/templates/002_create_credentials.rb +19 -0
  18. data/lib/authpwn_rails/generators/templates/credential.rb +16 -0
  19. data/lib/authpwn_rails/generators/templates/credentials.yml +34 -0
  20. data/lib/authpwn_rails/generators/templates/session/forbidden.html.erb +2 -2
  21. data/lib/authpwn_rails/generators/templates/session/home.html.erb +1 -1
  22. data/lib/authpwn_rails/generators/templates/session/new.html.erb +6 -6
  23. data/lib/authpwn_rails/generators/templates/session_controller.rb +1 -1
  24. data/lib/authpwn_rails/generators/templates/session_controller_test.rb +2 -2
  25. data/lib/authpwn_rails/generators/templates/user.rb +2 -2
  26. data/lib/authpwn_rails/generators/templates/users.yml +5 -8
  27. data/lib/authpwn_rails/session.rb +7 -7
  28. data/lib/authpwn_rails/session_controller.rb +15 -13
  29. data/lib/authpwn_rails/test_extensions.rb +6 -6
  30. data/lib/authpwn_rails/user_model.rb +23 -92
  31. data/test/email_credential_test.rb +50 -0
  32. data/test/facebook_controller_test.rb +7 -2
  33. data/test/facebook_credential_test.rb +74 -0
  34. data/test/helpers/db_setup.rb +4 -4
  35. data/test/helpers/fbgraph.rb +6 -2
  36. data/test/password_credential_test.rb +67 -0
  37. data/test/session_controller_api_test.rb +12 -12
  38. data/test/test_helper.rb +1 -0
  39. data/test/user_test.rb +11 -100
  40. metadata +41 -25
  41. data/lib/authpwn_rails/facebook_token_model.rb +0 -66
  42. data/lib/authpwn_rails/generators/facebook_generator.rb +0 -18
  43. data/lib/authpwn_rails/generators/templates/002_create_facebook_tokens.rb +0 -15
  44. data/lib/authpwn_rails/generators/templates/facebook_token.rb +0 -6
  45. data/lib/authpwn_rails/generators/templates/facebook_tokens.yml +0 -10
  46. data/lib/authpwn_rails/generators/users_generator.rb +0 -16
  47. data/test/facebook_token_test.rb +0 -28
@@ -0,0 +1,63 @@
1
+ # :namespace
2
+ module Credentials
3
+
4
+ # Associates a password with the user account.
5
+ class Password < ::Credential
6
+ # Virtual attribute: the user's password.
7
+ attr_accessor :password
8
+ validates :password, :confirmation => true, :presence => true
9
+
10
+ # Virtual attribute: confirmation for the user's password.
11
+ attr_accessor :password_confirmation
12
+
13
+ # A user can have a single password
14
+ validates :user_id, :uniqueness => true
15
+
16
+ # Compares the given password against the user's stored password.
17
+ #
18
+ # Returns +true+ for a match, +false+ otherwise.
19
+ def authenticate(password)
20
+ return false unless key
21
+ key == self.class.hash_password(password, key.split('|', 2).first)
22
+ end
23
+
24
+ # Password virtual attribute.
25
+ def password=(new_password)
26
+ @password = new_password
27
+ salt = self.class.random_salt
28
+ self.key = new_password && self.class.hash_password(new_password, salt)
29
+ end
30
+
31
+ # Resets the virtual password attributes.
32
+ def clear_plaintext
33
+ @password = @password_confirmation = nil
34
+ end
35
+
36
+ # The authenticated user or nil.
37
+ def self.authenticate_email(email, password)
38
+ email_cred = Credentials::Email.where(:name => email).
39
+ includes(:user => :credentials).first
40
+ return nil unless email_cred
41
+ credential = email_cred.user.credentials.
42
+ find { |c| c.kind_of? Credentials::Password }
43
+ credential.authenticate(password) ? email_cred.user : nil
44
+ end
45
+
46
+ # Computes a password hash from a raw password and a salt.
47
+ def self.hash_password(password, salt)
48
+ salt + '|' + Digest::SHA2.hexdigest(password + salt)
49
+ end
50
+
51
+ # Generates a random salt value.
52
+ def self.random_salt
53
+ [(0...12).map { |i| 1 + rand(255) }.pack('C*')].pack('m').strip
54
+ end
55
+ end # class Credentials::Password
56
+
57
+ end # namespace Credentials
58
+
59
+ module Authpwn::UserModel::InstanceMethods
60
+ def password_credential
61
+ credentials.find { |c| c.instance_of?(Credentials::Password) }
62
+ end
63
+ end
@@ -2,13 +2,11 @@ require 'authpwn_rails'
2
2
  require 'rails'
3
3
 
4
4
  # :nodoc: namespace
5
- module AuthpwnRails
5
+ module Authpwn
6
6
 
7
7
  class Engine < Rails::Engine
8
8
  generators do
9
- require 'authpwn_rails/generators/facebook_generator.rb'
10
- require 'authpwn_rails/generators/session_generator.rb'
11
- require 'authpwn_rails/generators/users_generator.rb'
9
+ require 'authpwn_rails/generators/all_generator.rb'
12
10
  end
13
11
 
14
12
  initializer 'authpwn.rspec.extensions' do
@@ -16,12 +14,12 @@ class Engine < Rails::Engine
16
14
  require 'rspec'
17
15
 
18
16
  RSpec.configure do |c|
19
- c.include AuthpwnRails::TestExtensions
17
+ c.include Authpwn::TestExtensions
20
18
  end
21
19
  rescue LoadError
22
20
  # No RSpec, no extensions.
23
21
  end
24
22
  end
25
- end # class AuthpwnRails::Engine
23
+ end # class Authpwn::Engine
26
24
 
27
- end # namespace AuthpwnRails
25
+ end # namespace Authpwn
@@ -8,13 +8,13 @@ class ActionController::Base
8
8
  # should obtain the Facebook token, using probes_facebook_access_token or
9
9
  # requires_facebook_access_token.
10
10
  def self.authenticates_using_facebook(options = {})
11
- include AuthpwnRails::FacebookControllerInstanceMethods
11
+ include Authpwn::FacebookControllerInstanceMethods
12
12
  before_filter :authenticate_using_facebook_access_token, options
13
13
  end
14
- end # module AuthpwnRails::FacebookExtensions::ControllerClassMethods
14
+ end # module Authpwn::FacebookExtensions::ControllerClassMethods
15
15
 
16
16
  # :nodoc: namespace
17
- module AuthpwnRails
17
+ module Authpwn
18
18
 
19
19
  # Included in controllers that call authenticates_using_facebook.
20
20
  module FacebookControllerInstanceMethods
@@ -28,6 +28,6 @@ module FacebookControllerInstanceMethods
28
28
  end
29
29
  end
30
30
  private :authenticate_using_facebook_access_token
31
- end # module AuthpwnRails::FacebookControllerInstanceMethods
31
+ end # module Authpwn::FacebookControllerInstanceMethods
32
32
 
33
- end # namespace AuthpwnRails
33
+ end # namespace Authpwn
@@ -1,13 +1,36 @@
1
1
  # :nodoc: namespace
2
2
  module Authpwn
3
3
 
4
- # rails g authpwn:session
5
- class SessionGenerator < Rails::Generators::Base
4
+ # rails g authpwn:all
5
+ class AllGenerator < Rails::Generators::Base
6
6
  source_root File.expand_path("../templates", __FILE__)
7
7
 
8
- def create_session
8
+ def create_user_model
9
+ copy_file 'user.rb', File.join('app', 'models', 'user.rb')
10
+ copy_file '001_create_users.rb',
11
+ File.join('db', 'migrate', '20100725000001_create_users.rb')
12
+ copy_file 'users.yml', File.join('test', 'fixtures', 'users.yml')
13
+ end
14
+
15
+ def create_credential_model
16
+ copy_file 'credential.rb', File.join('app', 'models', 'credential.rb')
17
+ copy_file '002_create_credentials.rb',
18
+ File.join('db', 'migrate', '20100725000002_create_credentials.rb')
19
+ copy_file 'credentials.yml',
20
+ File.join('test', 'fixtures', 'credentials.yml')
21
+ end
22
+
23
+ def create_session_controller
9
24
  copy_file 'session_controller.rb',
10
25
  File.join('app', 'controllers', 'session_controller.rb')
26
+ copy_file File.join('session_controller_test.rb'),
27
+ File.join('test', 'functional', 'session_controller_test.rb')
28
+
29
+ route "resource :session, :controller => 'session'"
30
+ route "root :to => 'session#show'"
31
+ end
32
+
33
+ def create_session_views
11
34
  copy_file File.join('session', 'forbidden.html.erb'),
12
35
  File.join('app', 'views', 'session', 'forbidden.html.erb')
13
36
  copy_file File.join('session', 'home.html.erb'),
@@ -16,11 +39,7 @@ class SessionGenerator < Rails::Generators::Base
16
39
  File.join('app', 'views', 'session', 'new.html.erb')
17
40
  copy_file File.join('session', 'welcome.html.erb'),
18
41
  File.join('app', 'views', 'session', 'welcome.html.erb')
19
- copy_file File.join('session_controller_test.rb'),
20
- File.join('test', 'functional', 'session_controller_test.rb')
21
-
22
- route "resource :session, :controller => 'session'"
23
- end
24
- end # class Authpwn::SessionViewsGenerator
42
+ end
43
+ end # class Authpwn::AllGenerator
25
44
 
26
45
  end # namespace Authpwn
@@ -1,19 +1,11 @@
1
1
  class CreateUsers < ActiveRecord::Migration
2
- def self.up
2
+ def change
3
3
  create_table :users do |t|
4
- t.string :email, :limit => 128, :null => false
5
- t.string :email_hash, :limit => 64, :null => false
6
- t.string :password_salt, :limit => 16, :null => true
7
- t.string :password_hash, :limit => 64, :null => true
4
+ t.string :exuid, :limit => 32, :null => false
8
5
 
9
6
  t.timestamps
10
7
  end
11
8
 
12
- add_index :users, :email, :unique => true, :null => false
13
- add_index :users, :email_hash, :unique => true, :null => false
14
- end
15
-
16
- def self.down
17
- drop_table :users
9
+ add_index :users, :exuid, :unique => true, :null => false
18
10
  end
19
11
  end
@@ -0,0 +1,19 @@
1
+ class CreateCredentials < ActiveRecord::Migration
2
+ def change
3
+ create_table :credentials do |t|
4
+ t.references :user, :null => false
5
+ t.string :type, :limit => 32, :null => false
6
+ t.string :name, :limit => 256, :null => true
7
+
8
+ t.boolean :verified, :null => false, :default => false
9
+
10
+ t.binary :key, :limit => 2.kilobytes, :null => true
11
+ end
12
+
13
+ # All the credentials (maybe of a specific type) belonging to a user.
14
+ add_index :credentials, [:user_id, :type], :unique => false,
15
+ :null => false
16
+ # A specific credential, to find out what user it belongs to.
17
+ add_index :credentials, [:type, :name], :unique => true, :null => true
18
+ end
19
+ end
@@ -0,0 +1,16 @@
1
+ # Credential used to prove the identity of a user.
2
+ class Credential < ActiveRecord::Base
3
+ include Authpwn::CredentialModel
4
+
5
+ # Add your extensions to the Credential class here.
6
+ end
7
+
8
+ # Load built-in credential types, such as Email and Password.
9
+ require 'authpwn_rails/credentials.rb'
10
+
11
+ # namespace for all Credential subclasses
12
+ module Credentials
13
+
14
+ # Add your custom Credential types here.
15
+
16
+ end
@@ -0,0 +1,34 @@
1
+ jane_email:
2
+ type: Credentials::Email
3
+ user: jane
4
+ name: jane@gmail.com
5
+ key: "1"
6
+
7
+ john_email:
8
+ type: Credentials::Email
9
+ user: john
10
+ name: john@gmail.com
11
+ key: "0"
12
+
13
+ jane_password:
14
+ type: Credentials::Password
15
+ user: jane
16
+ key: <%= Credentials::Password.hash_password('pa55w0rd', '5678').inspect %>
17
+
18
+ john_password:
19
+ type: Credentials::Password
20
+ user: john
21
+ key: <%= Credentials::Password.hash_password('password', '1234').inspect %>
22
+
23
+ # Test account vic.tor@costan.us
24
+ jane_facebook:
25
+ user: jane
26
+ type: Credentials::Facebook
27
+ name: 1011950666
28
+ key: AAAEj8jKX2a8BAA4kNheRhOs6SlECVcZCE9o5pPKMytOjjoiNAoZBGZAwuL4KrrxXWesfJRhzDZCJiqrcQG3UdjRRNtyMJQMZD
29
+
30
+ john_facebook:
31
+ user: john
32
+ type: Credentials::Facebook
33
+ name: 702659
34
+ key: 702659|ffffffffffffffffffffffff-702659|ZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
@@ -4,8 +4,8 @@
4
4
 
5
5
  <% if current_user %>
6
6
  <p>
7
- You should inform the user that they are logged in as
8
- <%= current_user.email %> and suggest them to
7
+ You should inform the user that they are logged in as
8
+ <%= current_user.exuid %> and suggest them to
9
9
  <%= link_to 'Log out', session_path, :method => :destroy %> and log in as a
10
10
  different user.
11
11
  </p>
@@ -1,5 +1,5 @@
1
1
  <p>
2
2
  This view gets displayed when the user is logged in. Right now,
3
- <%= current_user.email %> is logged in. You should allow the user to
3
+ user <%= current_user.exuid %> is logged in. You should allow the user to
4
4
  <%= link_to 'Log out', session_path, :method => :destroy %>.
5
5
  </p>
@@ -11,19 +11,19 @@
11
11
  </p>
12
12
  <% end %>
13
13
 
14
- <%= form_for @user, :url => session_path do |f| %>
14
+ <%= form_tag :url => session_path do %>
15
15
  <div class="field">
16
- <%= f.label :email, 'Email Address' %><br />
17
- <%= f.email_field :email %>
16
+ <%= label_tag :email, 'Email Address' %><br />
17
+ <%= email_field_tag :email, @email %>
18
18
  </div>
19
19
 
20
20
  <div class="field">
21
- <%= f.label :password %><br />
22
- <%= f.password_field :password %>
21
+ <%= label_tag :password %><br />
22
+ <%= password_field_tag :password %>
23
23
  </div>
24
24
 
25
25
  <div class="actions">
26
- <%= f.submit 'Log in' %>
26
+ <%= submit_tag 'Log in' %>
27
27
 
28
28
  <% if @redirect_url %>
29
29
  <%= hidden_field_tag :redirect_url, @redirect_url %>
@@ -1,6 +1,6 @@
1
1
  # Manages logging in and out of the application.
2
2
  class SessionController < ApplicationController
3
- include AuthpwnRails::SessionController
3
+ include Authpwn::SessionController
4
4
 
5
5
  # Sets up the 'session/welcome' view. No user is logged in.
6
6
  def welcome
@@ -17,8 +17,8 @@ class SessionControllerTest < ActionController::TestCase
17
17
  set_session_current_user @user
18
18
  get :show, :format => 'json'
19
19
 
20
- assert_equal @user.email,
21
- ActiveSupport::JSON.decode(response.body)['user']['email']
20
+ assert_equal @user.exuid,
21
+ ActiveSupport::JSON.decode(response.body)['user']['exuid']
22
22
  end
23
23
 
24
24
  test "application welcome page" do
@@ -1,6 +1,6 @@
1
1
  # An user account.
2
2
  class User < ActiveRecord::Base
3
- include AuthpwnRails::UserModel
3
+ include Authpwn::UserModel
4
4
 
5
- # Add your extensions to the User class here.
5
+ # Add your extensions to the User class here.
6
6
  end
@@ -1,11 +1,8 @@
1
1
  jane:
2
- email: jane@gmail.com
3
- email_hash: <%= Digest::SHA2.hexdigest('jane@gmail.com') %>
4
- password_salt: 5678
5
- password_hash: <%= User.hash_password('pa55w0rd', '5678').inspect %>
2
+ exuid: 12345
6
3
 
7
4
  john:
8
- email: john@gmail.com
9
- email_hash: <%= Digest::SHA2.hexdigest('john@gmail.com') %>
10
- password_salt: 1234
11
- password_hash: <%= User.hash_password('password', '1234').inspect %>
5
+ exuid: 56789
6
+
7
+ bill:
8
+ exuid: 98765
@@ -8,13 +8,13 @@ class ActionController::Base
8
8
  # trick. Model instances must implement id, and the model class must implement
9
9
  # find_by_id.
10
10
  def self.authenticates_using_session(options = {})
11
- include AuthpwnRails::ControllerInstanceMethods
11
+ include Authpwn::ControllerInstanceMethods
12
12
  before_filter :authenticate_using_session, options
13
13
  end
14
14
  end
15
15
 
16
16
  # :nodoc: namespace
17
- module AuthpwnRails
17
+ module Authpwn
18
18
 
19
19
  # Included in controllers that call authenticates_using_session.
20
20
  module ControllerInstanceMethods
@@ -23,15 +23,15 @@ module ControllerInstanceMethods
23
23
  def current_user=(user)
24
24
  @current_user = user
25
25
  if user
26
- session[:current_user_pid] = user.to_param
26
+ session[:user_exuid] = user.to_param
27
27
  else
28
- session.delete :current_user_pid
28
+ session.delete :user_exuid
29
29
  end
30
30
  end
31
31
 
32
32
  def authenticate_using_session
33
33
  return true if current_user
34
- user_param = session[:current_user_pid]
34
+ user_param = session[:user_exuid]
35
35
  user = user_param && User.find_by_param(user_param)
36
36
  self.current_user = user if user
37
37
  end
@@ -63,6 +63,6 @@ module ControllerInstanceMethods
63
63
  end
64
64
  end
65
65
  end
66
- end # module AuthpwnRails::ControllerInstanceMethods
66
+ end # module Authpwn::ControllerInstanceMethods
67
67
 
68
- end # namespace AuthpwnRails
68
+ end # namespace Authpwn
@@ -1,7 +1,7 @@
1
1
  require 'active_support'
2
2
 
3
3
  # :nodoc: namespace
4
- module AuthpwnRails
4
+ module Authpwn
5
5
 
6
6
  # Included by the controller that handles user authentication.
7
7
  #
@@ -14,11 +14,11 @@ module SessionController
14
14
  authenticates_using_session
15
15
  end
16
16
 
17
- # Included in controllers that include AuthpwnRails::SessionController.
17
+ # Included in controllers that include Authpwn::SessionController.
18
18
  module InstanceMethods
19
19
  # GET /session/new
20
20
  def new
21
- @user = User.new
21
+ @email = params[:email]
22
22
  @redirect_url = flash[:auth_redirect_url]
23
23
  redirect_to session_url if current_user
24
24
  end
@@ -52,25 +52,27 @@ module SessionController
52
52
 
53
53
  # POST /session
54
54
  def create
55
- @user = User.new params[:user]
56
55
  @redirect_url = params[:redirect_url] || session_url
57
- self.current_user =
58
- User.find_by_email_and_password @user.email, @user.password
56
+ @email = params[:email]
57
+ self.current_user = Credentials::Password.authenticate_email(@email,
58
+ params[:password])
59
59
 
60
60
  respond_to do |format|
61
61
  if current_user
62
62
  format.html { redirect_to @redirect_url }
63
63
  format.json do
64
- user_data = @user.as_json
65
- user_data = user_data['user'] if @user.class.include_root_in_json
64
+ user_data = current_user.as_json
65
+ if current_user.class.include_root_in_json
66
+ user_data = user_data['user']
67
+ end
66
68
  render :json => { :user => user_data,
67
69
  :csrf => form_authenticity_token }
68
70
  end
69
71
  else
70
72
  notice = 'Invalid e-mail or password'
71
73
  format.html do
72
- redirect_to new_session_url, :flash => {
73
- :notice => notice, :auth_redirect_url => @redirect_url }
74
+ redirect_to new_session_url, :flash => { :notice => notice,
75
+ :auth_redirect_url => @redirect_url }
74
76
  end
75
77
  format.json { render :json => { :error => notice} }
76
78
  end
@@ -95,8 +97,8 @@ module SessionController
95
97
  def welcome
96
98
  end
97
99
  private :welcome
98
- end # module AuthpwnRails::SessionController::InstanceMethods
100
+ end # module Authpwn::SessionController::InstanceMethods
99
101
 
100
- end # module AuthpwnRails::SessionController
102
+ end # module Authpwn::SessionController
101
103
 
102
- end # namespace AuthpwnRails
104
+ end # namespace Authpwn