cow_auth 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: dff8fe9127d7933119a7bc9e1a394b63459347b8
4
- data.tar.gz: 044fe42d8ab52301dcb26d555b2249a2e361469b
2
+ SHA256:
3
+ metadata.gz: '0855a2ef21dbcf97962fa31e9ebd51bd7b121c518b44eff213f0c220681e23e3'
4
+ data.tar.gz: fd087dde4492f753d7a6615513642a1c998d52fac85c45d38205d43cd2e33721
5
5
  SHA512:
6
- metadata.gz: 6470c86664faba0fa3e5900666cb3222a91b2516331809d642f3c6398317ed5a9814be3e8eab0aadb188a0387ff7254ca81f3757bc58566e5af834d384f44a75
7
- data.tar.gz: ce090243601ce2a58903a1881419837be92c0edb65b6681f5459c900c7baf7823d66d3eb118ed877d35b705712090898b3d58483c9617533ebcce5c06fb629f8
6
+ metadata.gz: ac2539f24adb657aa18bd40c508bc1a4076348db89c36f4a31ea25c5dc8b504b130e9462336b5d362de70958f471e73d1503e5535a14b028cb7e8091b705e535
7
+ data.tar.gz: 87a6185f361579d1b73e046fea742f5bae8b428ca8112afc5523a14f87cded892c9ccdfdd4eb002c0580eb5fa1659010b794d1488ab72493176461d01b9d4ae6
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # CowAuth
2
2
 
3
- The main goal of this gem is to provide session and / or API authentication for Rails (or Rails-like) web applications.
3
+ The main goal of this gem is to provide token-based authentication for Rails (or Rails-like) web applications.
4
4
 
5
5
  ## Installation
6
6
 
@@ -22,102 +22,43 @@ Or install it yourself as:
22
22
 
23
23
  ### Generator (Example)
24
24
 
25
- $ bundle exec rails generate model user uuid:string:uniq email:string:uniq sid:string:uniq encrypted_password:string first_name:string last_name:string sign_in_count:integer is_approved:boolean is_deleted:boolean
25
+ $ bundle exec rails generate model user uuid:string:uniq email:string:uniq sid:string:uniq encrypted_password:string locale:string first_name:string last_name:string role:integer sign_in_count:integer is_approved:boolean is_deleted:boolean
26
26
 
27
27
  ### Migration (Example)
28
28
 
29
29
  # Modified migration; includes indexes and other stuff you might not want.
30
- class CreateUsers < ActiveRecord::Migration[5.1]
30
+ class CreateUsers < ActiveRecord::Migration[5.2]
31
31
  def change
32
32
  create_table :users do |t|
33
33
  t.string :uuid, null: false
34
34
  t.string :email, null: false
35
35
  t.string :sid, null: false
36
36
  t.string :encrypted_password, null: false
37
+ t.string :locale, null: false
37
38
  t.string :first_name
38
39
  t.string :last_name
40
+ t.integer :role, default: 0, null: false
39
41
  t.integer :sign_in_count, default: 0, null: false
40
42
  t.boolean :is_approved, default: false, null: false
41
43
  t.boolean :is_deleted, default: false, null: false
42
44
  t.timestamps
45
+ t.index [:uuid], unique: true
46
+ t.index [:email], unique: true
47
+ t.index [:sid], unique: true
43
48
  end
44
- add_index :users, :uuid, unique: true
45
- add_index :users, :email, unique: true
46
- add_index :users, :sid, unique: true
47
49
  end
48
50
  end
49
51
 
50
- ### Model Inheritance
52
+ ### Model Concern
51
53
 
52
- class User < CowAuth::User
54
+ class User < ApplicationRecord
55
+ include CowAuth::User
53
56
  end
54
57
 
55
-
56
58
  ### Create User
57
59
 
58
60
  User.create! email: 'email', password: 'password'
59
61
 
60
- ## Session Authentication
61
-
62
- ### Sign In View Example
63
-
64
- <%= form_tag '/sessions' do %>
65
- <%= label_tag(:email) %><br>
66
- <%= text_field_tag(:email) %><br>
67
- <%= label_tag(:password) %><br>
68
- <%= password_field_tag(:password) %><br>
69
- <%= submit_tag('Sign In') %>
70
- <% end %>
71
-
72
- ### Routes Example
73
-
74
- get 'sessions/new' => 'sessions#new'
75
- post 'sessions' => 'sessions#create'
76
- delete 'sessions' => 'sessions#destroy'
77
-
78
- ### Controllers
79
-
80
- Add the following lines in the controller(s) that you want to enforce authentication for.
81
-
82
- include CowAuth::SessionAuth::AuthenticateRequest
83
- before_action :authenticate_user
84
-
85
- ### Application Controller Example
86
-
87
- class ApplicationController < ActionController::Base
88
- include CowAuth::SessionAuth::AuthenticateRequest
89
-
90
- protect_from_forgery with: :exception
91
-
92
- before_action :authenticate_user
93
-
94
- rescue_from CowAuth::NotAuthenticatedError, with: :user_not_authenticated
95
-
96
- private
97
-
98
- def user_not_authenticated(exception)
99
- flash[:notice] = exception.message
100
- render sessions_new_path
101
- end
102
- end
103
-
104
- ### Sessions Controller Example
105
-
106
- class SessionsController < ApplicationController
107
- include CowAuth::SessionAuth::SessionEndpoints
108
-
109
- skip_before_action :authenticate_user, only: [:new, :create]
110
-
111
- def sign_in_success_path
112
- flash[:notice] = 'Successfully signed in.'
113
- return home_path
114
- end
115
-
116
- def sign_out_success_path
117
- return sessions_new_path
118
- end
119
- end
120
-
121
62
  ## Token Authentication
122
63
 
123
64
  ### Authenticate (Example)
@@ -141,6 +82,12 @@ Add the following lines in the controller(s) that you want to enforce authentica
141
82
  include CowAuth::TokenAuth::AuthenticateRequest
142
83
  before_action :authenticate_user
143
84
 
85
+ Add the following private method to the ApplicationController (assuming User is the correct model).
86
+
87
+ def authentication_class
88
+ return User
89
+ end
90
+
144
91
  ### Application Controller Example
145
92
 
146
93
  class ApplicationController < ActionController::API
@@ -155,6 +102,10 @@ Add the following lines in the controller(s) that you want to enforce authentica
155
102
  def user_not_authenticated(exception)
156
103
  render json: { error: exception.message }, status: :unauthorized
157
104
  end
105
+
106
+ def authentication_class
107
+ return User
108
+ end
158
109
  end
159
110
 
160
111
  ### Sessions Controller Example
data/cow_auth.gemspec CHANGED
@@ -21,9 +21,8 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.required_ruby_version = '~> 2.3'
23
23
 
24
- spec.add_development_dependency 'bundler', '~> 1.14'
25
- spec.add_development_dependency 'rake', '~> 12.0'
24
+ spec.add_development_dependency 'bundler', '~> 1.16'
25
+ spec.add_development_dependency 'rake', '~> 12.3'
26
26
  spec.add_development_dependency 'minitest', '~> 5.10'
27
- spec.add_runtime_dependency 'active_model_serializers', '~> 0.10'
28
27
  spec.add_runtime_dependency 'scrypt', '~> 3.0'
29
28
  end
@@ -10,7 +10,8 @@ module CowAuth
10
10
 
11
11
  def authenticate_user
12
12
  authenticate_or_request_with_http_token do |token, options|
13
- @current_user = User.authenticate_from_token(options[:sid], token)
13
+ user = authentication_class.find_by(sid: options[:sid])
14
+ @current_user = user.try(:authenticate_with_token, token) ? user : nil
14
15
  raise CowAuth::NotAuthenticatedError.new('User not authenticated.') if @current_user.blank?
15
16
  return true
16
17
  end
@@ -1,4 +1,3 @@
1
- require 'cow_auth/user_serializer'
2
1
  require 'cow_auth/exceptions'
3
2
 
4
3
  module CowAuth
@@ -7,10 +6,10 @@ module CowAuth
7
6
  extend ActiveSupport::Concern
8
7
 
9
8
  def create
10
- @user = User.find_by(email: params[:email])
11
- if @user.try(:authenticate, params[:password])
12
- @user.api_sign_in
13
- render json: UserSerializer.new(@user), status: :ok
9
+ user = authentication_class.find_by(email: params[:email])
10
+ if user.try(:authenticate_with_password, params[:password])
11
+ user.api_sign_in
12
+ render json: { sid: user.sid, auth_token: user.auth_token }, status: :ok
14
13
  else
15
14
  raise CowAuth::NotAuthenticatedError.new('Invalid user credentials.')
16
15
  end
data/lib/cow_auth/user.rb CHANGED
@@ -1,24 +1,22 @@
1
1
  require 'scrypt'
2
+ require 'cow_auth/exceptions'
2
3
 
3
4
  module CowAuth
4
- class User < ActiveRecord::Base
5
- after_initialize :generate_sid_if_necessary
6
-
7
- validates :email, presence: true
8
- validates :email, uniqueness: true
9
- validates :encrypted_password, presence: true
10
- validates :sid, presence: true
11
- validates :sid, uniqueness: true
12
- validates :sid, format: { with: /\AC[a-z0-9]{32}\z/ }
13
-
14
- def password=(new_password)
15
- return false if new_password.blank?
16
- salt = SCrypt::Engine.generate_salt
17
- self.encrypted_password = SCrypt::Engine.hash_secret(new_password, salt)
18
- return true
5
+ module User
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ after_initialize :generate_sid_if_necessary
10
+
11
+ validates :email, presence: true
12
+ validates :email, uniqueness: true
13
+ validates :encrypted_password, presence: true
14
+ validates :sid, presence: true
15
+ validates :sid, uniqueness: true
16
+ validates :sid, format: { with: /\AC[a-z0-9]{32}\z/ }
19
17
  end
20
18
 
21
- def authenticate(password)
19
+ def authenticate_with_password(password)
22
20
  return false if self.encrypted_password.blank?
23
21
  if SCrypt::Password.new(self.encrypted_password) == password
24
22
  self.update(sign_in_count: self.sign_in_count + 1)
@@ -27,43 +25,66 @@ module CowAuth
27
25
  return false
28
26
  end
29
27
 
28
+ def authenticate_with_token(auth_token)
29
+ api_key = self.fetch_api_key_from_redis(sid)
30
+ if api_key.present? &&
31
+ api_key.key?(:auth_token) &&
32
+ api_key.key?(:expires_at) &&
33
+ api_key[:auth_token] == auth_token &&
34
+ api_key[:expires_at] > Time.zone.now
35
+ return true
36
+ end
37
+ return false
38
+ end
39
+
30
40
  def api_sign_in
31
- User.assert_redis_handle_present
32
- $redis.set(self.redis_key, {
33
- auth_token: self.token_valid? ? self.auth_token : User.generate_auth_token,
34
- expires_at: User.generate_token_expires_at
41
+ self.redis_handle.set(self.redis_key, {
42
+ auth_token: self.token_valid? ? self.auth_token : self.generate_auth_token,
43
+ expires_at: self.generate_token_expires_at
35
44
  }.to_json)
36
45
  end
37
46
 
38
47
  def api_sign_out
39
- User.assert_redis_handle_present
40
- $redis.del(self.redis_key)
48
+ self.redis_handle.del(self.redis_key)
41
49
  end
42
50
 
43
51
  def auth_token
44
- return User.fetch_api_key_from_redis(self.sid).try(:[], :auth_token)
52
+ return self.fetch_api_key_from_redis(self.sid).try(:[], :auth_token)
45
53
  end
46
54
 
47
- def self.authenticate_from_token(sid, auth_token)
48
- api_key = User.fetch_api_key_from_redis(sid)
49
- if api_key.present? &&
50
- api_key.key?(:auth_token) &&
51
- api_key.key?(:expires_at) &&
52
- api_key[:auth_token] == auth_token &&
53
- api_key[:expires_at] > Time.zone.now
54
- return User.find_by(sid: sid)
55
- end
56
- return nil
55
+ def password=(new_password)
56
+ return false if new_password.blank?
57
+ salt = SCrypt::Engine.generate_salt
58
+ self.encrypted_password = SCrypt::Engine.hash_secret(new_password, salt)
59
+ return true
57
60
  end
58
61
 
59
62
  protected
60
63
 
64
+ def fetch_api_key_from_redis(sid)
65
+ api_key = self.redis_handle.get(self.redis_key)
66
+ return api_key.present? ? JSON.parse(api_key).try(:symbolize_keys) : nil
67
+ end
68
+
69
+ def generate_auth_token
70
+ return SecureRandom.hex(64)
71
+ end
72
+
73
+ def generate_token_expires_at
74
+ return 1.month.from_now
75
+ end
76
+
77
+ def redis_handle
78
+ raise CowAuth::RedisHandleMissingError.new('"$redis" handle not found.') unless $redis.present?
79
+ return $redis
80
+ end
81
+
61
82
  def redis_key
62
- return "user_#{self.sid}"
83
+ return "user_#{self.sid.downcase}"
63
84
  end
64
85
 
65
86
  def token_valid?
66
- api_key = User.fetch_api_key_from_redis(self.sid)
87
+ api_key = self.fetch_api_key_from_redis(self.sid)
67
88
  return api_key.present? &&
68
89
  api_key.key?(:auth_token) &&
69
90
  api_key.key?(:expires_at) &&
@@ -76,23 +97,5 @@ module CowAuth
76
97
  self.sid ||= "C#{SecureRandom.hex(16)}"
77
98
  return true
78
99
  end
79
-
80
- def self.generate_auth_token
81
- return SecureRandom.hex(32)
82
- end
83
-
84
- def self.generate_token_expires_at
85
- return 1.month.from_now
86
- end
87
-
88
- def self.fetch_api_key_from_redis(sid)
89
- User.assert_redis_handle_present
90
- api_key = $redis.get("user_#{sid}")
91
- return api_key.present? ? JSON.parse(api_key).try(:symbolize_keys) : nil
92
- end
93
-
94
- def self.assert_redis_handle_present
95
- raise CowAuth::RedisHandleMissingError.new('"$redis" handle not found.') unless $redis.present?
96
- end
97
100
  end
98
101
  end
@@ -1,3 +1,3 @@
1
1
  module CowAuth
2
- VERSION = '0.4.2'
2
+ VERSION = '0.5.0'
3
3
  end
data/lib/cow_auth.rb CHANGED
@@ -1,8 +1,6 @@
1
1
  require 'cow_auth/version'
2
2
  require 'cow_auth/user'
3
3
  require 'cow_auth/exceptions'
4
- require 'cow_auth/session_auth/session_endpoints'
5
- require 'cow_auth/session_auth/authenticate_request'
6
4
  require 'cow_auth/token_auth/session_endpoints'
7
5
  require 'cow_auth/token_auth/authenticate_request'
8
6
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cow_auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mickey Cowden
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-06-27 00:00:00.000000000 Z
11
+ date: 2017-12-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.14'
19
+ version: '1.16'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.14'
26
+ version: '1.16'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '12.0'
33
+ version: '12.3'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '12.0'
40
+ version: '12.3'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: minitest
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,20 +52,6 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '5.10'
55
- - !ruby/object:Gem::Dependency
56
- name: active_model_serializers
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '0.10'
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '0.10'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: scrypt
71
57
  requirement: !ruby/object:Gem::Requirement
@@ -100,12 +86,9 @@ files:
100
86
  - cow_auth.gemspec
101
87
  - lib/cow_auth.rb
102
88
  - lib/cow_auth/exceptions.rb
103
- - lib/cow_auth/session_auth/authenticate_request.rb
104
- - lib/cow_auth/session_auth/session_endpoints.rb
105
89
  - lib/cow_auth/token_auth/authenticate_request.rb
106
90
  - lib/cow_auth/token_auth/session_endpoints.rb
107
91
  - lib/cow_auth/user.rb
108
- - lib/cow_auth/user_serializer.rb
109
92
  - lib/cow_auth/version.rb
110
93
  homepage: https://github.com/mickey13/cow_auth
111
94
  licenses:
@@ -127,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
127
110
  version: '0'
128
111
  requirements: []
129
112
  rubyforge_project:
130
- rubygems_version: 2.6.12
113
+ rubygems_version: 2.7.3
131
114
  signing_key:
132
115
  specification_version: 4
133
116
  summary: Authentication gem
@@ -1,21 +0,0 @@
1
- require 'cow_auth/exceptions'
2
-
3
- module CowAuth
4
- module SessionAuth
5
- module AuthenticateRequest
6
- extend ActiveSupport::Concern
7
-
8
- private
9
-
10
- def authenticate_user
11
- @current_user = User.find_by(uuid: session[:current_user])
12
- raise CowAuth::NotAuthenticatedError.new('User not authenticated.') if @current_user.blank?
13
- return true
14
- end
15
-
16
- def current_user
17
- return @current_user
18
- end
19
- end
20
- end
21
- end
@@ -1,32 +0,0 @@
1
- require 'cow_auth/exceptions'
2
-
3
- module CowAuth
4
- module SessionAuth
5
- module SessionEndpoints
6
- extend ActiveSupport::Concern
7
-
8
- def new
9
- end
10
-
11
- def create
12
- user = User.find_by(email: params[:email])
13
- if user.try(:authenticate, params[:password])
14
- session[:current_user] = user.uuid
15
- redirect_to sign_in_success_path
16
- else
17
- session[:current_user] = nil
18
- raise CowAuth::NotAuthenticatedError.new('Invalid user credentials.')
19
- end
20
- end
21
-
22
- def destroy
23
- if @current_user.present?
24
- session[:current_user] = nil
25
- redirect_to sign_out_success_path
26
- else
27
- raise CowAuth::StandardError.new('Could not sign user out.')
28
- end
29
- end
30
- end
31
- end
32
- end
@@ -1,7 +0,0 @@
1
- require 'active_model_serializers'
2
-
3
- module CowAuth
4
- class UserSerializer < ActiveModel::Serializer
5
- attributes :email, :sid, :auth_token, :first_name, :last_name, :sign_in_count
6
- end
7
- end