devise_rails_api_authentication 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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