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 +5 -5
- data/README.md +21 -70
- data/cow_auth.gemspec +2 -3
- data/lib/cow_auth/token_auth/authenticate_request.rb +2 -1
- data/lib/cow_auth/token_auth/session_endpoints.rb +4 -5
- data/lib/cow_auth/user.rb +56 -53
- data/lib/cow_auth/version.rb +1 -1
- data/lib/cow_auth.rb +0 -2
- metadata +7 -24
- data/lib/cow_auth/session_auth/authenticate_request.rb +0 -21
- data/lib/cow_auth/session_auth/session_endpoints.rb +0 -32
- data/lib/cow_auth/user_serializer.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: '0855a2ef21dbcf97962fa31e9ebd51bd7b121c518b44eff213f0c220681e23e3'
|
4
|
+
data.tar.gz: fd087dde4492f753d7a6615513642a1c998d52fac85c45d38205d43cd2e33721
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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.
|
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
|
52
|
+
### Model Concern
|
51
53
|
|
52
|
-
class 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.
|
25
|
-
spec.add_development_dependency 'rake', '~> 12.
|
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
|
-
|
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
|
-
|
11
|
-
if
|
12
|
-
|
13
|
-
render json:
|
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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
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
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
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
|
52
|
+
return self.fetch_api_key_from_redis(self.sid).try(:[], :auth_token)
|
45
53
|
end
|
46
54
|
|
47
|
-
def
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
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 =
|
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
|
data/lib/cow_auth/version.rb
CHANGED
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
|
+
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-
|
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.
|
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.
|
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.
|
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.
|
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.
|
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
|