cow_auth 0.4.2 → 0.5.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.
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