devise_sessionable 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +109 -0
- data/Rakefile +26 -0
- data/app/assets/config/devise_sessionable_manifest.js +2 -0
- data/app/assets/javascripts/devise_sessionable/application.js +13 -0
- data/app/assets/stylesheets/devise_sessionable/application.css +15 -0
- data/app/controllers/devise_sessionable/application_controller.rb +5 -0
- data/app/helpers/devise_sessionable/application_helper.rb +4 -0
- data/app/jobs/devise_sessionable/application_job.rb +4 -0
- data/app/mailers/devise_sessionable/application_mailer.rb +6 -0
- data/app/models/devise_sessionable/application_record.rb +5 -0
- data/app/models/devise_sessionable/session.rb +11 -0
- data/app/views/layouts/devise_sessionable/application.html.erb +14 -0
- data/config/initializers/simple_token_authentication.rb +31 -0
- data/config/routes.rb +3 -0
- data/lib/devise_sessionable.rb +15 -0
- data/lib/devise_sessionable/acts_as_sessionable.rb +17 -0
- data/lib/devise_sessionable/engine.rb +12 -0
- data/lib/devise_sessionable/version.rb +3 -0
- data/lib/generators/devise_sessionable/install/install_generator.rb +24 -0
- data/lib/generators/devise_sessionable/install/templates/migration.rb +16 -0
- data/lib/tasks/devise_sessionable_tasks.rake +4 -0
- data/spec/factories/sessions.rb +5 -0
- data/spec/factories/users.rb +4 -0
- data/spec/models/session_spec.rb +18 -0
- data/spec/rails_helper.rb +28 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/test_app/Rakefile +6 -0
- data/spec/test_app/app/assets/config/manifest.js +5 -0
- data/spec/test_app/app/assets/javascripts/application.js +13 -0
- data/spec/test_app/app/assets/javascripts/cable.js +13 -0
- data/spec/test_app/app/assets/stylesheets/application.css +15 -0
- data/spec/test_app/app/channels/application_cable/channel.rb +4 -0
- data/spec/test_app/app/channels/application_cable/connection.rb +4 -0
- data/spec/test_app/app/controllers/application_controller.rb +3 -0
- data/spec/test_app/app/helpers/application_helper.rb +2 -0
- data/spec/test_app/app/jobs/application_job.rb +2 -0
- data/spec/test_app/app/mailers/application_mailer.rb +4 -0
- data/spec/test_app/app/models/application_record.rb +3 -0
- data/spec/test_app/app/models/user.rb +2 -0
- data/spec/test_app/app/views/layouts/application.html.erb +14 -0
- data/spec/test_app/app/views/layouts/mailer.html.erb +13 -0
- data/spec/test_app/app/views/layouts/mailer.text.erb +1 -0
- data/spec/test_app/bin/bundle +3 -0
- data/spec/test_app/bin/rails +4 -0
- data/spec/test_app/bin/rake +4 -0
- data/spec/test_app/bin/setup +38 -0
- data/spec/test_app/bin/update +29 -0
- data/spec/test_app/bin/yarn +11 -0
- data/spec/test_app/config.ru +5 -0
- data/spec/test_app/config/application.rb +25 -0
- data/spec/test_app/config/boot.rb +5 -0
- data/spec/test_app/config/cable.yml +10 -0
- data/spec/test_app/config/database.yml +85 -0
- data/spec/test_app/config/environment.rb +5 -0
- data/spec/test_app/config/environments/development.rb +54 -0
- data/spec/test_app/config/environments/production.rb +91 -0
- data/spec/test_app/config/environments/test.rb +42 -0
- data/spec/test_app/config/initializers/application_controller_renderer.rb +6 -0
- data/spec/test_app/config/initializers/assets.rb +14 -0
- data/spec/test_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/test_app/config/initializers/cookies_serializer.rb +5 -0
- data/spec/test_app/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/test_app/config/initializers/inflections.rb +16 -0
- data/spec/test_app/config/initializers/mime_types.rb +4 -0
- data/spec/test_app/config/initializers/wrap_parameters.rb +14 -0
- data/spec/test_app/config/locales/en.yml +33 -0
- data/spec/test_app/config/puma.rb +56 -0
- data/spec/test_app/config/routes.rb +3 -0
- data/spec/test_app/config/secrets.yml +32 -0
- data/spec/test_app/config/spring.rb +6 -0
- data/spec/test_app/db/migrate/20170803015911_devise_sessionable_create_sessions.rb +16 -0
- data/spec/test_app/db/migrate/20170803015941_create_users.rb +8 -0
- data/spec/test_app/db/schema.rb +33 -0
- data/spec/test_app/log/development.log +274 -0
- data/spec/test_app/log/test.log +595 -0
- data/spec/test_app/package.json +5 -0
- data/spec/test_app/public/404.html +67 -0
- data/spec/test_app/public/422.html +67 -0
- data/spec/test_app/public/500.html +66 -0
- data/spec/test_app/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/test_app/public/apple-touch-icon.png +0 -0
- data/spec/test_app/public/favicon.ico +0 -0
- metadata +312 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a95a21c555e179b7fb4a070da9b5216559f6d4f9
|
4
|
+
data.tar.gz: 338c6fa0ded927243c6494ed48845832e9948b78
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 24ddfc4566e7085fddc548a50de36d199f970a706ef791862250b5bc5c5b2a008382af2bed4af91d4ec0afb7f2e5df1d74ff3de60ed21c67a821bae85d53a643
|
7
|
+
data.tar.gz: 72bd573b72411fa926c10239cf695e3a058245dcf5d94ede9b53d51925d407baa989e66279a833bea2fa1bdb3f2877e7dc24e8b0e37983cc0e4e697892d382e0
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2017 Isaac Norman
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
# DeviseSessionable
|
2
|
+
Devise Sessionable extends the [Simple Token Authentication](https://github.com/gonzalo-bulnes/simple_token_authentication) gem into a `Session` object to allow for easier and more secure token authentication.
|
3
|
+
|
4
|
+
## Installation
|
5
|
+
Add this line to your application's Gemfile:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
gem 'devise_sessionable'
|
9
|
+
```
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
```bash
|
13
|
+
$ bundle
|
14
|
+
```
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
```bash
|
18
|
+
$ gem install devise_sessionable
|
19
|
+
```
|
20
|
+
|
21
|
+
## Getting Started
|
22
|
+
|
23
|
+
First things first, run the installer:
|
24
|
+
|
25
|
+
```bash
|
26
|
+
rails generate devise_sessionable:install
|
27
|
+
```
|
28
|
+
|
29
|
+
This will generate a migration for the session object.
|
30
|
+
|
31
|
+
**NOTE:** This gem is setup to work with UUIDs as default. If you are _NOT_ using uuids you will need to update the migration to reflect this correctly.
|
32
|
+
|
33
|
+
Then simply run:
|
34
|
+
|
35
|
+
```bash
|
36
|
+
rails db:migrate
|
37
|
+
```
|
38
|
+
|
39
|
+
## Adding Session Authentication on a Model
|
40
|
+
|
41
|
+
simply add `acts_as_sessionable` to the devise enabled model that you wish to be session authable.
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
class User < ApplicationRecord
|
45
|
+
acts_as_sessionable
|
46
|
+
|
47
|
+
# Include default devise modules. Others available are:
|
48
|
+
# :confirmable, :lockable, :timeoutable and :omniauthable
|
49
|
+
devise :database_authenticatable, :registerable,
|
50
|
+
:recoverable, :rememberable, :trackable, :validatable
|
51
|
+
```
|
52
|
+
|
53
|
+
## Enabling Session Authentication in the Controller
|
54
|
+
|
55
|
+
Once you have a model with session authentication enabled on a model, you can start using it in your controller with just a few simple steps.
|
56
|
+
|
57
|
+
First, you need to put your controllers behind a layer of token authentication:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
module Api
|
61
|
+
module V1
|
62
|
+
class ApiController < ApplicationController
|
63
|
+
acts_as_token_authentication_handler_for DeviseSessionable::Session,
|
64
|
+
as: :session,
|
65
|
+
fallback: :exception
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
Secondly, because we are using the `Session` to authenticate, but are actually authenticating a `User`, we need to define the `current_authable` scope in our `ApiController`
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
private
|
75
|
+
|
76
|
+
def current_authable
|
77
|
+
current_user
|
78
|
+
end
|
79
|
+
```
|
80
|
+
|
81
|
+
Finally, we need to setup our Simple Token Authentication to refer to the sessions `id` when authenticating
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
# config/initializers/simple_token_authentication.rb
|
85
|
+
|
86
|
+
SimpleTokenAuthentication.configure do |config|
|
87
|
+
config.identifiers = { session: 'id' }
|
88
|
+
end
|
89
|
+
```
|
90
|
+
|
91
|
+
_(This is something that we plan to integrate into the gem itself in a future release)_
|
92
|
+
|
93
|
+
## Using Sessions for Authentication
|
94
|
+
|
95
|
+
Now that we have everything in place, we can authenticate using our new session objects. How you want to handle the creation, deletion and expiration of sessions is up to you, all the gem cares about is that a valid session is passed through to authenticate.
|
96
|
+
|
97
|
+
Underneath the gem we are still using the Simple Token Authentication gem to handle authentication, the usage is essentially the same, and you can refer to their documentation [here](https://github.com/gonzalo-bulnes/simple_token_authentication#usage)
|
98
|
+
|
99
|
+
Default Header Keys:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
'X-Session-Id' => session.id,
|
103
|
+
'X-Session-Token' => session.authentication_token
|
104
|
+
```
|
105
|
+
|
106
|
+
These can be overidden in the `SimpleTokenAuthentication` initializer, using the same methods the base gem uses.
|
107
|
+
|
108
|
+
## License
|
109
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'DeviseSessionable'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("../spec/test_app/Rakefile", __FILE__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
|
21
|
+
load 'rails/tasks/statistics.rake'
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
require 'bundler/gem_tasks'
|
26
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file. JavaScript code in this file should be added after the last require_* statement.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//
|
13
|
+
//= require_tree .
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Devise sessionable</title>
|
5
|
+
<%= stylesheet_link_tag "devise_sessionable/application", media: "all" %>
|
6
|
+
<%= javascript_include_tag "devise_sessionable/application" %>
|
7
|
+
<%= csrf_meta_tags %>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
|
11
|
+
<%= yield %>
|
12
|
+
|
13
|
+
</body>
|
14
|
+
</html>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
SimpleTokenAuthentication::ExceptionFallbackHandler.module_eval do
|
2
|
+
def fallback!(controller, entity)
|
3
|
+
return unless controller.send(:current_authable).nil?
|
4
|
+
|
5
|
+
throw(:warden, scope: entity.name_underscore.to_sym)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
# Overrides
|
10
|
+
SimpleTokenAuthentication::TokenAuthenticationHandler.module_eval do
|
11
|
+
# All the token authentication actually happens on the session object,
|
12
|
+
# However we want to `sign_in!` method to be passed the user.
|
13
|
+
# So we override it here.
|
14
|
+
def authenticate_entity_from_token!(entity)
|
15
|
+
record = find_record_from_identifier(entity)
|
16
|
+
|
17
|
+
return unless token_correct?(record, entity, token_comparator)
|
18
|
+
perform_sign_in!(record.authable, sign_in_handler)
|
19
|
+
end
|
20
|
+
|
21
|
+
def find_record_from_identifier(entity)
|
22
|
+
identifier_param_value = entity.get_identifier_from_params_or_headers(self)
|
23
|
+
.presence
|
24
|
+
|
25
|
+
# The finder method should be compatible with all the model adapters,
|
26
|
+
# namely ActiveRecord and Mongoid in all their supported versions.
|
27
|
+
identifier_param_value && entity.model.find_by(
|
28
|
+
entity.identifier => identifier_param_value
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
data/config/routes.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'simple_token_authentication'
|
2
|
+
require "devise_sessionable/engine"
|
3
|
+
|
4
|
+
module DeviseSessionable
|
5
|
+
extend ActiveSupport::Autoload
|
6
|
+
|
7
|
+
autoload :ActsAsSessionable, 'devise_sessionable/acts_as_sessionable'
|
8
|
+
end
|
9
|
+
|
10
|
+
module ActiveRecord
|
11
|
+
class Base
|
12
|
+
include DeviseSessionable::ActsAsSessionable
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module DeviseSessionable
|
2
|
+
module ActsAsSessionable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def acts_as_sessionable(_options = {})
|
10
|
+
has_many :sessions,
|
11
|
+
as: :authable,
|
12
|
+
class_name: 'DeviseSessionable::Session',
|
13
|
+
dependent: :destroy
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module DeviseSessionable
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
isolate_namespace DeviseSessionable
|
4
|
+
|
5
|
+
config.generators do |g|
|
6
|
+
g.test_framework :rspec, :fixture => false
|
7
|
+
g.fixture_replacement :factory_girl, :dir => 'spec/factories'
|
8
|
+
g.assets false
|
9
|
+
g.helper false
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rails/generators/active_record'
|
2
|
+
|
3
|
+
module DeviseSessionable
|
4
|
+
class InstallGenerator < Rails::Generators::Base
|
5
|
+
include Rails::Generators::Migration
|
6
|
+
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
|
9
|
+
def copy_migration
|
10
|
+
migration_template 'migration.rb',
|
11
|
+
'db/migrate/devise_sessionable_create_sessions.rb'
|
12
|
+
end
|
13
|
+
|
14
|
+
# Implement the required interface for Rails::Generators::Migration.
|
15
|
+
def self.next_migration_number(dirname)
|
16
|
+
next_migration_number = current_migration_number(dirname) + 1
|
17
|
+
if ActiveRecord::Base.timestamped_migrations
|
18
|
+
[Time.now.utc.strftime('%Y%m%d%H%M%S'), '%.14d' % next_migration_number].max
|
19
|
+
else
|
20
|
+
'%.3d' % next_migration_number
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class DeviseSessionableCreateSessions < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :devise_sessionable_sessions, id: :uuid do |t|
|
4
|
+
t.string :authentication_token
|
5
|
+
t.uuid :authable_id, null: false
|
6
|
+
t.string :authable_type, null: false
|
7
|
+
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
|
11
|
+
add_index :devise_sessionable_sessions,
|
12
|
+
[:authable_id, :authable_type],
|
13
|
+
name: 'index_devise_sessionable_sessions_on_authable'
|
14
|
+
add_index :devise_sessionable_sessions, :authentication_token
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
module DeviseSessionable
|
4
|
+
RSpec.describe Session, type: :model do
|
5
|
+
it { is_expected.to belong_to(:authable) }
|
6
|
+
it { is_expected.to validate_presence_of(:authable) }
|
7
|
+
|
8
|
+
describe 'Simple token auth' do
|
9
|
+
it 'sets the authentication_token automatically' do
|
10
|
+
session = build(:session, authentication_token: nil)
|
11
|
+
|
12
|
+
expect do
|
13
|
+
session.save
|
14
|
+
end.to change(session, :authentication_token).from nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|