devise_rails_api_authentication 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2f30aa2cc6ab1eef2fe5de23b8a632288ee98203
4
+ data.tar.gz: 408e1da7a2c029e66a2d5a3c3a1976413335feb2
5
+ SHA512:
6
+ metadata.gz: 4d45f3df76cd214c3c7ba5047a19a0cbd6a97963c55fbe41ac949327725d94935f6ce22f4e5ee586db735d634c63bf77ba72e16a071504291dbbf91c52e87df2
7
+ data.tar.gz: 480198af4ea432fa8b2299988436d5d30345921a65c60e770614d894f2e9faf29fc0426bec65f5d7104a7778a2aa637272bbb72febd28c647a8e0ca9f66fe5cf
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rubocop.yml ADDED
@@ -0,0 +1,12 @@
1
+ AllCops:
2
+ Exclude:
3
+ - Gemfile
4
+ - Guardfile
5
+ - devise_rails_api_authentication.gemspec
6
+ - spec/**/*
7
+ Style/MultilineBlockChain:
8
+ Enabled: false
9
+ Style/MultilineOperationIndentation:
10
+ Enabled: false
11
+ Documentation:
12
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2
data/Dockerfile ADDED
@@ -0,0 +1,8 @@
1
+ FROM ruby:2.2
2
+
3
+ WORKDIR /app
4
+ ADD Gemfile /app/Gemfile
5
+ ADD devise_rails_api_authentication.gemspec /app/devise_rails_api_authentication.gemspec
6
+ ADD lib/devise_rails_api_authentication/version.rb /app/lib/devise_rails_api_authentication/version.rb
7
+ RUN bundle install --jobs 4
8
+ ADD . /app
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem 'rails-api'
7
+ gem 'rspec-rails', '~> 3.0'
8
+ gem 'sqlite3', '~> 1.3.0'
9
+ gem 'activerecord', '~> 4.1.0'
10
+ end
data/Guardfile ADDED
@@ -0,0 +1,19 @@
1
+ guard :rspec, cmd: "bundle exec rspec" do
2
+ require "guard/rspec/dsl"
3
+ dsl = Guard::RSpec::Dsl.new(self)
4
+
5
+ # RSpec files
6
+ rspec = dsl.rspec
7
+ watch(rspec.spec_helper) { rspec.spec_dir }
8
+ watch(rspec.spec_support) { rspec.spec_dir }
9
+ watch(rspec.spec_files)
10
+
11
+ # Ruby files
12
+ ruby = dsl.ruby
13
+ dsl.watch_spec_files_for(ruby.lib_files)
14
+ end
15
+
16
+ guard :rubocop do
17
+ watch(%r{.+\.rb$})
18
+ watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
19
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Altmetric LLP
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,78 @@
1
+ # DeviseRailsApiAuthentication [![Build Status](https://travis-ci.org/altmetric/devise-rails-api-authentication.svg?branch=master)](https://travis-ci.org/altmetric/devise-rails-api-authentication)
2
+
3
+ Token-based rails-api authentication with Devise.
4
+
5
+ Devise does not support [token-based authentication anymore](https://github.com/plataformatec/devise/issues/2739)
6
+ and [devise_token_auth](https://github.com/lynndylanhurley/devise_token_auth) does not work with rails-api.
7
+
8
+ It's basically [this gist](https://gist.github.com/josevalim/fb706b1e933ef01e4fb6) wrapped as a gem with specs.
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'devise_rails_api_authentication'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install devise_rails_api_authentication
25
+
26
+ ## Usage
27
+
28
+ First of all make sure you have a model class with `authentication_token` and `email` fields.
29
+ Otherwise create a migration, here's an example for a `User` model and ActiveRecord:
30
+
31
+ ```ruby
32
+ class AddDeviseToUsers < ActiveRecord::Migration
33
+ def self.change
34
+ add_column :users, :email, :text, null: false, default: ''
35
+ add_index :users, :email, unique: true
36
+ add_column :users, :authentication_token, :text, null: false, default: ''
37
+ add_index :users, :authentication_token, unique: true
38
+ end
39
+ end
40
+ ```
41
+
42
+ Next add the following lines to ApplicationController - see [source](https://github.com/altmetric/devise-rails-api-authentication/blob/master/lib/devise_rails_api_authentication/context.rb):
43
+
44
+ ```ruby
45
+ class ApplicationController
46
+ include DeviseRailsApiAuthentication::Context
47
+
48
+ private def user
49
+ User.where(email: user_email).first
50
+ end
51
+ end
52
+ ```
53
+
54
+ and the following line to your model class - see [source](https://github.com/altmetric/devise-rails-api-authentication/blob/master/lib/devise_rails_api_authentication/authenticatable.rb):
55
+
56
+ ```ruby
57
+ class YourUserModel
58
+ include DeviseRailsApiAuthentication::Authenticatable
59
+ end
60
+ ```
61
+
62
+ Once you run the migration, create a new user, and boot up your app, just do:
63
+
64
+ ```shell
65
+ curl -H "X_USER_EMAIL: <email>" -H "X_USER_TOKEN: <token>" http://<where-your-app-lives>
66
+ ```
67
+
68
+ ## Contributing
69
+
70
+ 1. Fork it ( https://github.com/altmetric/devise_rails_api_authentication/fork )
71
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
72
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
73
+ 4. Push to the branch (`git push origin my-new-feature`)
74
+ 5. Create a new Pull Request
75
+
76
+ ## License
77
+
78
+ This project is released under the [MIT license](https://github.com/altmetric/devise-rails-api-authentication/blob/master/LICENSE.txt).
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ RSpec::Core::RakeTask.new(:spec)
4
+
5
+ task default: :spec
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'devise_rails_api_authentication/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'devise_rails_api_authentication'
8
+ spec.version = DeviseRailsApiAuthentication::VERSION
9
+ spec.authors = ['Jakub Pawlowicz', 'Matthew MacLeod', 'Paul Mucur']
10
+ spec.email = %w(jakub@altmetric.com matt@matt-m.co.uk paul@altmetric.com)
11
+ spec.summary = %q{Token-based rails-api authentication with Devise}
12
+ spec.homepage = 'https://github.com/altmetric/devise-rails-api-authentication'
13
+ spec.license = 'MIT'
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.add_dependency 'actionpack', '~> 4.1.0'
21
+ spec.add_dependency 'devise', '~> 3.4.0'
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.6'
24
+ spec.add_development_dependency 'rake', '~> 10.0'
25
+ spec.add_development_dependency 'rubocop', '~> 0.28.0'
26
+ spec.add_development_dependency 'guard-rubocop'
27
+ spec.add_development_dependency 'guard-rspec'
28
+ end
@@ -0,0 +1,7 @@
1
+ dev:
2
+ build: .
3
+ volumes:
4
+ - lib:/app/lib
5
+ - spec:/app/spec
6
+ - Gemfile:/app/Gemfile
7
+ - Guardfile:/app/Guardfile
@@ -0,0 +1,6 @@
1
+ require 'devise_rails_api_authentication/version'
2
+ require 'devise_rails_api_authentication/authenticatable'
3
+ require 'devise_rails_api_authentication/context'
4
+
5
+ module DeviseRailsApiAuthentication
6
+ end
@@ -0,0 +1,25 @@
1
+ require 'devise'
2
+
3
+ module DeviseRailsApiAuthentication
4
+ module Authenticatable
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ devise :database_authenticatable, :trackable
9
+ before_save :ensure_authentication_token
10
+ end
11
+
12
+ def ensure_authentication_token
13
+ return unless authentication_token.blank?
14
+
15
+ self.authentication_token = generate_authentication_token
16
+ end
17
+
18
+ def generate_authentication_token
19
+ loop do
20
+ token = Devise.friendly_token
21
+ break token if self.class.where(authentication_token: token).count == 0
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,40 @@
1
+ require 'devise'
2
+
3
+ module DeviseRailsApiAuthentication
4
+ module Context
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ include Devise::Controllers::Helpers
9
+ include ActionController::MimeResponds
10
+ before_action :authenticate_user_from_token!
11
+ end
12
+
13
+ def authenticate_user_from_token!
14
+ return if Rails.env.development?
15
+
16
+ if user && Devise.secure_compare(user.authentication_token, user_token)
17
+ warden.set_user(user, scope: :user, store: false)
18
+ else
19
+ not_authenticated_error
20
+ end
21
+ end
22
+
23
+ def user_email
24
+ request.headers['HTTP_X_USER_EMAIL']
25
+ end
26
+
27
+ def user_token
28
+ request.headers['HTTP_X_USER_TOKEN']
29
+ end
30
+
31
+ def not_authenticated_error
32
+ response.headers['WWW-Authenticate'] = 'Token'
33
+ head status: 401
34
+ end
35
+
36
+ def user
37
+ fail NotImplementedError
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,3 @@
1
+ module DeviseRailsApiAuthentication
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe DeviseRailsApiAuthentication::Authenticatable do
4
+ subject(:user) { User.new }
5
+
6
+ describe '#ensure_authentication_token' do
7
+ it 'generates a token if not given' do
8
+ expect { user.save }.to change { user.authentication_token }.from(nil)
9
+ end
10
+
11
+ it 'does not generate a token if given' do
12
+ user.authentication_token = 'test'
13
+ expect { user.save }.not_to change { user.authentication_token }
14
+ end
15
+
16
+ it 'generates a new token if one is taken' do
17
+ expect(Devise).to receive(:friendly_token).and_return('1', '2')
18
+
19
+ another_user = User.create(authentication_token: '1')
20
+ expect { user.save }.to change { user.authentication_token }.to('2')
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+ require 'ostruct'
3
+
4
+ class TestController
5
+ def self.before_action(*_); end
6
+ def self.helper_method(*_); end
7
+
8
+ include DeviseRailsApiAuthentication::Context
9
+
10
+ def request
11
+ @_request ||= OpenStruct.new(headers: {})
12
+ end
13
+
14
+ def response
15
+ @_response ||= OpenStruct.new(headers: {}, status: 200)
16
+ end
17
+
18
+ def head(opts)
19
+ opts.each { |k, v| response.send("#{k}=", v) }
20
+ end
21
+
22
+ def index
23
+ authenticate_user_from_token!
24
+ response
25
+ end
26
+
27
+ private
28
+
29
+ def user
30
+ User.where(email: user_email).first
31
+ end
32
+ end
33
+
34
+ RSpec.describe TestController do
35
+ let(:user) { User.create(email: 'test@altmetric.com') }
36
+ let(:warden) { double(Warden::Proxy) }
37
+ subject(:context) { described_class.new }
38
+ subject(:response) { context.index }
39
+
40
+ context 'no auth token' do
41
+ it 'should get 401 Unauthorized' do
42
+ expect(response.status).to eq(401)
43
+ end
44
+
45
+ it 'should unauthorized header' do
46
+ expect(response.headers).to eq('WWW-Authenticate' => 'Token')
47
+ end
48
+ end
49
+
50
+ context 'with auth token' do
51
+ before do
52
+ context.request.headers['HTTP_X_USER_EMAIL'] = user.email
53
+ context.request.headers['HTTP_X_USER_TOKEN'] = user.authentication_token
54
+ allow(context)
55
+ .to receive(:warden)
56
+ .and_return(warden)
57
+ allow(warden)
58
+ .to receive(:set_user)
59
+ .with(kind_of(User), hash_including(store: false))
60
+ .and_return(true)
61
+ end
62
+
63
+ it 'should get 200 OK' do
64
+ expect(response.status).to eq(200)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,22 @@
1
+ ENV['RACK_ENV'] = 'test'
2
+ require 'rails-api'
3
+ require 'rspec/rails'
4
+
5
+ require_relative '../lib/devise_rails_api_authentication'
6
+
7
+ require 'active_record'
8
+ require 'sqlite3'
9
+
10
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
11
+ ActiveRecord::Base.connection.execute <<-SQL
12
+ CREATE TABLE users (
13
+ id INTEGER,
14
+ email TEXT,
15
+ authentication_token TEXT
16
+ )
17
+ SQL
18
+ ActiveRecord::Base.extend Devise::Models
19
+
20
+ class User < ActiveRecord::Base
21
+ include DeviseRailsApiAuthentication::Authenticatable
22
+ end
metadata ADDED
@@ -0,0 +1,167 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: devise_rails_api_authentication
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jakub Pawlowicz
8
+ - Matthew MacLeod
9
+ - Paul Mucur
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2015-07-15 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: actionpack
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 4.1.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ version: 4.1.0
29
+ - !ruby/object:Gem::Dependency
30
+ name: devise
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ~>
34
+ - !ruby/object:Gem::Version
35
+ version: 3.4.0
36
+ type: :runtime
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ~>
41
+ - !ruby/object:Gem::Version
42
+ version: 3.4.0
43
+ - !ruby/object:Gem::Dependency
44
+ name: bundler
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ~>
48
+ - !ruby/object:Gem::Version
49
+ version: '1.6'
50
+ type: :development
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ version: '1.6'
57
+ - !ruby/object:Gem::Dependency
58
+ name: rake
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ~>
62
+ - !ruby/object:Gem::Version
63
+ version: '10.0'
64
+ type: :development
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ version: '10.0'
71
+ - !ruby/object:Gem::Dependency
72
+ name: rubocop
73
+ requirement: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 0.28.0
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ~>
83
+ - !ruby/object:Gem::Version
84
+ version: 0.28.0
85
+ - !ruby/object:Gem::Dependency
86
+ name: guard-rubocop
87
+ requirement: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ type: :development
93
+ prerelease: false
94
+ version_requirements: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ - !ruby/object:Gem::Dependency
100
+ name: guard-rspec
101
+ requirement: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - '>='
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ type: :development
107
+ prerelease: false
108
+ version_requirements: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ description:
114
+ email:
115
+ - jakub@altmetric.com
116
+ - matt@matt-m.co.uk
117
+ - paul@altmetric.com
118
+ executables: []
119
+ extensions: []
120
+ extra_rdoc_files: []
121
+ files:
122
+ - .gitignore
123
+ - .rubocop.yml
124
+ - .travis.yml
125
+ - Dockerfile
126
+ - Gemfile
127
+ - Guardfile
128
+ - LICENSE.txt
129
+ - README.md
130
+ - Rakefile
131
+ - devise_rails_api_authentication.gemspec
132
+ - docker-compose.yml
133
+ - lib/devise_rails_api_authentication.rb
134
+ - lib/devise_rails_api_authentication/authenticatable.rb
135
+ - lib/devise_rails_api_authentication/context.rb
136
+ - lib/devise_rails_api_authentication/version.rb
137
+ - spec/devise_rails_api_authentication/authenticatable_spec.rb
138
+ - spec/devise_rails_api_authentication/context_spec.rb
139
+ - spec/spec_helper.rb
140
+ homepage: https://github.com/altmetric/devise-rails-api-authentication
141
+ licenses:
142
+ - MIT
143
+ metadata: {}
144
+ post_install_message:
145
+ rdoc_options: []
146
+ require_paths:
147
+ - lib
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 2.0.14
161
+ signing_key:
162
+ specification_version: 4
163
+ summary: Token-based rails-api authentication with Devise
164
+ test_files:
165
+ - spec/devise_rails_api_authentication/authenticatable_spec.rb
166
+ - spec/devise_rails_api_authentication/context_spec.rb
167
+ - spec/spec_helper.rb