token_auth 0.3.0.beta1
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 +111 -0
- data/Rakefile +52 -0
- data/app/controllers/token_auth/api/authentication_tokens_controller.rb +53 -0
- data/app/controllers/token_auth/api/base_controller.rb +7 -0
- data/app/controllers/token_auth/api/payloads_controller.rb +108 -0
- data/app/controllers/token_auth/authentication_tokens_controller.rb +45 -0
- data/app/controllers/token_auth/base_controller.rb +5 -0
- data/app/controllers/token_auth/concerns/api_resources.rb +51 -0
- data/app/controllers/token_auth/concerns/cors_settings.rb +16 -0
- data/app/controllers/token_auth/configuration_tokens_controller.rb +49 -0
- data/app/controllers/token_auth/tokens_controller.rb +13 -0
- data/app/models/token_auth/authentication_token.rb +33 -0
- data/app/models/token_auth/configuration_token.rb +65 -0
- data/app/models/token_auth/payload.rb +77 -0
- data/app/models/token_auth/synchronizable_resource.rb +34 -0
- data/app/models/token_auth/uuid_enabled.rb +15 -0
- data/app/serializers/token_auth/synchronizable_resource_serializer.rb +8 -0
- data/app/views/token_auth/tokens/index.html.erb +55 -0
- data/config/locales/en.yml +31 -0
- data/config/locales/es-PE.yml +31 -0
- data/config/locales/pt-BR.yml +31 -0
- data/config/routes.rb +18 -0
- data/db/migrate/20150428210721_create_configuration_tokens.rb +21 -0
- data/db/migrate/20150428211137_create_authentication_tokens.rb +25 -0
- data/db/migrate/20151229184253_create_token_auth_synchronizable_resources.rb +25 -0
- data/lib/tasks/token_auth_server_rails_tasks.rake +5 -0
- data/lib/token_auth/engine.rb +7 -0
- data/lib/token_auth/version.rb +5 -0
- data/lib/token_auth.rb +9 -0
- metadata +229 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 064111700731121265d4aada907cee407a956a06
|
4
|
+
data.tar.gz: d3b86f096bd944e54e154c9da276f304617946e1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5bb1c3bf891008100dc89ca0e9996c04b4fe0e1e301a7d9ecc7915e6e73675794ba553d5accaf1750441308caa3116d61a6457eb9001ceb58c82a627f0df364b
|
7
|
+
data.tar.gz: 5a2d00439e671fa715bb52de55a89f5f8146592d922155a81350224af4b52095e434900103e3accd44333637dabd60ca0c43215f072be3412717428069f088df
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2015 Eric Carty-Fickes
|
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,111 @@
|
|
1
|
+
# Token Authentication
|
2
|
+
|
3
|
+
This Rails Engine implements a simple configuration handshake with clients. It
|
4
|
+
also provides Controller Concerns for authenticating clients via an API.
|
5
|
+
|
6
|
+
## Overview
|
7
|
+
|
8
|
+
The basic workflow is as follows:
|
9
|
+
|
10
|
+
1. A user generates a Configuration Token within your host application tied to
|
11
|
+
an "entity" within the application. This entity will likely represent a human
|
12
|
+
user.
|
13
|
+
1. The Configuration Token is shared with the client you wish to authorize.
|
14
|
+
1. If the Configuration Token is transmitted along with a unique client
|
15
|
+
identifier while the Token is still valid, the Configuration Token will be
|
16
|
+
destroyed and an Authentication Token will be created and returned to the
|
17
|
+
client.
|
18
|
+
1. The Authentication Token can be used to authenticate subsequent requests, as
|
19
|
+
long as it is accompanied by the unique client identifier.
|
20
|
+
1. The Authentication Token can be disabled temporarily or permanently, and it
|
21
|
+
can be destroyed. If it is destroyed, this process must be repeated.
|
22
|
+
|
23
|
+
## Installation
|
24
|
+
|
25
|
+
Add the gem to your Gemfile:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
# Gemfile
|
29
|
+
|
30
|
+
gem 'token_auth',
|
31
|
+
git: 'https://github.com/NU-CBITS/token_auth_server_rails',
|
32
|
+
tag: '0.1.1'
|
33
|
+
```
|
34
|
+
|
35
|
+
Install it:
|
36
|
+
|
37
|
+
```
|
38
|
+
bundle
|
39
|
+
```
|
40
|
+
|
41
|
+
Install and run the migrations:
|
42
|
+
|
43
|
+
```
|
44
|
+
rake token_auth:install:migrations; rake db:migrate
|
45
|
+
```
|
46
|
+
|
47
|
+
Mount the Engine and make its routes available to the host application:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
# config/routes.rb
|
51
|
+
|
52
|
+
mount TokenAuth::Engine => '/token_auth'
|
53
|
+
```
|
54
|
+
|
55
|
+
## Configuration
|
56
|
+
|
57
|
+
To customize the behavior of the token management functions, you can override
|
58
|
+
the `BaseController` class:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
# app/controllers/token_auth/base_controller.rb
|
62
|
+
|
63
|
+
module TokenAuth
|
64
|
+
class BaseController < ApplicationController
|
65
|
+
before_action :authenticate_user!
|
66
|
+
end
|
67
|
+
end
|
68
|
+
```
|
69
|
+
|
70
|
+
To authenticate an API controller:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
# app/controllers/api/my_controller.rb
|
74
|
+
|
75
|
+
module Api
|
76
|
+
class MyController < ActionController::Base
|
77
|
+
include TokenAuth::Concerns::ApiResources
|
78
|
+
|
79
|
+
after_action do |controller|
|
80
|
+
controller.cors_set_access_control_headers(allow_methods: "GET, OPTIONS")
|
81
|
+
end
|
82
|
+
|
83
|
+
def show
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
```
|
88
|
+
|
89
|
+
## Testing
|
90
|
+
|
91
|
+
After generating a configuration token, test authentication token generation:
|
92
|
+
|
93
|
+
```
|
94
|
+
curl --data "data[clientUuid]=asdf&configurationToken=4C3LM9" http://localhost:3000/token_auth/api/authentication_tokens
|
95
|
+
```
|
96
|
+
|
97
|
+
## Development
|
98
|
+
|
99
|
+
Clone the repository and install dependencies:
|
100
|
+
|
101
|
+
```
|
102
|
+
git clone git@github.com:NU-CBITS/token_auth_server_rails.git
|
103
|
+
bundle
|
104
|
+
```
|
105
|
+
|
106
|
+
Run the unit tests and linters for this Engine:
|
107
|
+
|
108
|
+
```
|
109
|
+
RAILS_ENV=test bin/rake db:create db:migrate
|
110
|
+
bin/rake
|
111
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
begin
|
3
|
+
require "bundler/setup"
|
4
|
+
rescue LoadError
|
5
|
+
puts "You must `gem install bundler` and `bundle install` to run rake tasks"
|
6
|
+
end
|
7
|
+
|
8
|
+
require "rdoc/task"
|
9
|
+
|
10
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
11
|
+
rdoc.rdoc_dir = "rdoc"
|
12
|
+
rdoc.title = "TokenAuth"
|
13
|
+
rdoc.options << "--line-numbers"
|
14
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
15
|
+
end
|
16
|
+
|
17
|
+
require "rspec/core/rake_task"
|
18
|
+
|
19
|
+
desc "Run all specs in spec directory (excluding plugin specs)"
|
20
|
+
RSpec::Core::RakeTask.new(:spec)
|
21
|
+
|
22
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
23
|
+
load "rails/tasks/engine.rake"
|
24
|
+
|
25
|
+
Bundler::GemHelper.install_tasks
|
26
|
+
|
27
|
+
require "rubocop/rake_task"
|
28
|
+
|
29
|
+
RuboCop::RakeTask.new
|
30
|
+
|
31
|
+
dir = File.dirname(__FILE__)
|
32
|
+
|
33
|
+
desc "Run Brakeman"
|
34
|
+
task :brakeman do
|
35
|
+
puts `#{ File.join(dir, "bin", "brakeman") } #{ File.join(dir, ".") }`
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "Run MarkDown lint"
|
39
|
+
task :mdl do
|
40
|
+
results = `#{ File.join(dir, "bin", "mdl") } #{ File.join(dir, "README.md") }`
|
41
|
+
unless results.strip.empty?
|
42
|
+
puts results
|
43
|
+
exit 1
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
task :default do
|
48
|
+
Rake::Task["spec"].invoke
|
49
|
+
Rake::Task["rubocop"].invoke
|
50
|
+
Rake::Task["brakeman"].invoke
|
51
|
+
Rake::Task["mdl"].invoke
|
52
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TokenAuth
|
4
|
+
module Api
|
5
|
+
# API to manage Authentication Tokens.
|
6
|
+
class AuthenticationTokensController < ::TokenAuth::Api::BaseController
|
7
|
+
RESOURCE_TYPE = "authenticationTokens"
|
8
|
+
|
9
|
+
include Concerns::CorsSettings
|
10
|
+
|
11
|
+
after_action do |controller|
|
12
|
+
controller.cors_set_access_control_headers(
|
13
|
+
allow_methods: "POST, OPTIONS"
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
def options
|
18
|
+
render json: {}, status: 200
|
19
|
+
end
|
20
|
+
|
21
|
+
def create
|
22
|
+
if configuration_token && authentication_token
|
23
|
+
render(json: {
|
24
|
+
data: {
|
25
|
+
type: RESOURCE_TYPE,
|
26
|
+
id: authentication_token.uuid,
|
27
|
+
value: authentication_token.value
|
28
|
+
}
|
29
|
+
},
|
30
|
+
status: 201)
|
31
|
+
else
|
32
|
+
render json: {}, status: 400
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def authentication_token
|
39
|
+
@authentication_token ||=
|
40
|
+
configuration_token.make_authentication_token(token_params)
|
41
|
+
end
|
42
|
+
|
43
|
+
def token_params
|
44
|
+
{ client_uuid: (params[:data] || {})[:clientUuid] }
|
45
|
+
end
|
46
|
+
|
47
|
+
def configuration_token
|
48
|
+
@configuration_token ||=
|
49
|
+
ConfigurationToken.find_match(params[:configurationToken])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "openssl"
|
3
|
+
|
4
|
+
module TokenAuth
|
5
|
+
module Api
|
6
|
+
# Processes inbound and outbound resources.
|
7
|
+
class PayloadsController < ActionController::Base
|
8
|
+
include TokenAuth::Concerns::CorsSettings
|
9
|
+
|
10
|
+
attr_reader :authentication_token
|
11
|
+
|
12
|
+
rescue_from TokenAuth::Concerns::ApiResources::Api::Unauthorized,
|
13
|
+
with: :unauthorized
|
14
|
+
|
15
|
+
before_action do |controller|
|
16
|
+
controller.cors_set_access_control_headers(
|
17
|
+
allow_methods: "GET, POST, OPTIONS",
|
18
|
+
allow_headers: "Authorization"
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
def index
|
23
|
+
authenticate!
|
24
|
+
render json: pullable_records,
|
25
|
+
meta: { timestamp: Time.zone.now.iso8601 }
|
26
|
+
end
|
27
|
+
|
28
|
+
def options
|
29
|
+
render json: {}, status: 200
|
30
|
+
end
|
31
|
+
|
32
|
+
def create
|
33
|
+
authenticate!
|
34
|
+
payload = Payload.new(entity_id: authentication_token.entity_id)
|
35
|
+
payload.save request_data
|
36
|
+
|
37
|
+
headers["Errors"] = payload.errors.join(", ")
|
38
|
+
render json: payload.valid_resources, status: 201
|
39
|
+
rescue TokenAuth::Payload::MalformedPayloadError
|
40
|
+
render json: {}, status: 400
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def find_token!
|
46
|
+
@authentication_token = TokenAuth::AuthenticationToken.find_by(
|
47
|
+
client_uuid: @metadata[:key],
|
48
|
+
is_enabled: true
|
49
|
+
)
|
50
|
+
|
51
|
+
return if @authentication_token
|
52
|
+
|
53
|
+
raise TokenAuth::Concerns::ApiResources::Api::Unauthorized
|
54
|
+
end
|
55
|
+
|
56
|
+
def request_data
|
57
|
+
return nil unless request.post?
|
58
|
+
|
59
|
+
params[:data] || []
|
60
|
+
end
|
61
|
+
|
62
|
+
def calculate_signature
|
63
|
+
OpenSSL::Digest::MD5.hexdigest([
|
64
|
+
request_data ? request_data.to_json : nil,
|
65
|
+
@metadata[:key],
|
66
|
+
@metadata[:nonce],
|
67
|
+
@metadata[:timestamp],
|
68
|
+
@metadata[:url],
|
69
|
+
@metadata[:method],
|
70
|
+
authentication_token.value
|
71
|
+
].compact.join)
|
72
|
+
end
|
73
|
+
|
74
|
+
def split_header
|
75
|
+
if request.headers[:Authorization].nil?
|
76
|
+
raise TokenAuth::Concerns::ApiResources::Api::Unauthorized
|
77
|
+
end
|
78
|
+
|
79
|
+
auth_headers = request.headers[:Authorization].split(",")
|
80
|
+
@metadata = auth_headers.each_with_object({}) do |h, metadata|
|
81
|
+
p = h.split("=")
|
82
|
+
metadata[p[0].to_sym] = p[1].gsub(/(^")|("$)/m, "")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def authenticate!
|
87
|
+
split_header
|
88
|
+
find_token!
|
89
|
+
|
90
|
+
return if @metadata[:signature] == calculate_signature
|
91
|
+
|
92
|
+
raise TokenAuth::Concerns::ApiResources::Api::Unauthorized
|
93
|
+
end
|
94
|
+
|
95
|
+
def pullable_records
|
96
|
+
entity_id = authentication_token.entity_id
|
97
|
+
SynchronizableResource.pullable_records_for(
|
98
|
+
entity_id: entity_id,
|
99
|
+
filter: params[:filter]
|
100
|
+
)
|
101
|
+
end
|
102
|
+
|
103
|
+
def unauthorized
|
104
|
+
render json: {}, status: 401
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module TokenAuth
|
3
|
+
# Manages Authentication Tokens.
|
4
|
+
class AuthenticationTokensController < ::TokenAuth::BaseController
|
5
|
+
def update
|
6
|
+
token = AuthenticationToken.find_by_entity_id(params[:entity_id])
|
7
|
+
|
8
|
+
if token.update(token_params)
|
9
|
+
redirect_to tokens_url(token.entity_id),
|
10
|
+
notice: t("activerecord.success_saving",
|
11
|
+
name: token.class.model_name.human)
|
12
|
+
else
|
13
|
+
redirect_to tokens_url(token.entity_id),
|
14
|
+
alert: t("activerecord.failure_saving",
|
15
|
+
name: token.class.model_name.human,
|
16
|
+
errors: errors_on(token))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def destroy
|
21
|
+
token = AuthenticationToken.find_by_entity_id(params[:entity_id])
|
22
|
+
|
23
|
+
if token.destroy
|
24
|
+
redirect_to tokens_url(token.entity_id),
|
25
|
+
notice: t("activerecord.success_destroying",
|
26
|
+
name: token.class.model_name.human)
|
27
|
+
else
|
28
|
+
redirect_to tokens_url(token.entity_id),
|
29
|
+
alert: t("activerecord.failure_destroying",
|
30
|
+
name: token.class.model_name.human,
|
31
|
+
errors: errors_on(token))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def errors_on(model)
|
38
|
+
model.errors.full_messages.join ", "
|
39
|
+
end
|
40
|
+
|
41
|
+
def token_params
|
42
|
+
params.permit(:is_enabled)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module TokenAuth
|
3
|
+
module Concerns
|
4
|
+
# Behavior related to authentication and CORS.
|
5
|
+
module ApiResources
|
6
|
+
module Api
|
7
|
+
class Unauthorized < StandardError
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
include ::TokenAuth::Concerns::CorsSettings
|
14
|
+
|
15
|
+
included do
|
16
|
+
before_action :authenticate_token!
|
17
|
+
|
18
|
+
rescue_from Api::Unauthorized, with: :unauthorized
|
19
|
+
end
|
20
|
+
|
21
|
+
AUTH_HEADER = "X-AUTH-TOKEN"
|
22
|
+
|
23
|
+
def options
|
24
|
+
render nothing: true
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def authenticate_token!
|
30
|
+
@authentication_token = client_uuid && auth_header &&
|
31
|
+
::TokenAuth::AuthenticationToken
|
32
|
+
.find_enabled(client_uuid: client_uuid,
|
33
|
+
value: auth_header)
|
34
|
+
|
35
|
+
raise Api::Unauthorized unless @authentication_token
|
36
|
+
end
|
37
|
+
|
38
|
+
def client_uuid
|
39
|
+
params[:clientUuid]
|
40
|
+
end
|
41
|
+
|
42
|
+
def auth_header
|
43
|
+
request.headers[AUTH_HEADER]
|
44
|
+
end
|
45
|
+
|
46
|
+
def unauthorized
|
47
|
+
render json: {}, status: 401
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module TokenAuth
|
3
|
+
module Concerns
|
4
|
+
# Allow cross-domain requests.
|
5
|
+
module CorsSettings
|
6
|
+
def cors_set_access_control_headers(allow_methods:, allow_headers: "")
|
7
|
+
headers["Access-Control-Allow-Origin"] = "*"
|
8
|
+
headers["Access-Control-Allow-Methods"] = allow_methods
|
9
|
+
headers["Access-Control-Allow-Headers"] = [
|
10
|
+
"Content-Type",
|
11
|
+
allow_headers
|
12
|
+
].join(", ")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module TokenAuth
|
3
|
+
# Manages Configuration Tokens.
|
4
|
+
class ConfigurationTokensController < ApplicationController
|
5
|
+
def create
|
6
|
+
token = ConfigurationToken.new(entity_id: params[:entity_id])
|
7
|
+
|
8
|
+
if token.save
|
9
|
+
redirect_to tokens_index,
|
10
|
+
notice: t("activerecord.success_saving",
|
11
|
+
name: token.class.model_name.human)
|
12
|
+
else
|
13
|
+
redirect_to tokens_index,
|
14
|
+
alert: t("activerecord.failure_saving",
|
15
|
+
name: token.class.model_name.human,
|
16
|
+
errors: errors_on(token))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def destroy
|
21
|
+
token = ConfigurationToken.find_by_entity_id(params[:entity_id])
|
22
|
+
|
23
|
+
if token.nil?
|
24
|
+
redirect_to tokens_index,
|
25
|
+
alert: t("activerecord.cannot_find",
|
26
|
+
name: ConfigurationToken.model_name.human)
|
27
|
+
elsif token.destroy
|
28
|
+
redirect_to tokens_index,
|
29
|
+
notice: t("activerecord.success_destroying",
|
30
|
+
name: ConfigurationToken.model_name.human)
|
31
|
+
else
|
32
|
+
redirect_to tokens_index,
|
33
|
+
alert: t("activerecord.failure_destroying",
|
34
|
+
name: ConfigurationToken.model_name.human,
|
35
|
+
errors: errors_on(token))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def tokens_index
|
42
|
+
tokens_url params[:entity_id]
|
43
|
+
end
|
44
|
+
|
45
|
+
def errors_on(model)
|
46
|
+
model.errors.full_messages.join ", "
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module TokenAuth
|
3
|
+
# Manage configuration and authentication tokens.
|
4
|
+
class TokensController < ::TokenAuth::BaseController
|
5
|
+
def index
|
6
|
+
@entity_id = params[:entity_id]
|
7
|
+
@authentication_token = AuthenticationToken
|
8
|
+
.find_by_entity_id(@entity_id)
|
9
|
+
@configuration_token = ConfigurationToken
|
10
|
+
.find_by_entity_id(@entity_id)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module TokenAuth
|
3
|
+
# A key shared with a client for authenticating requests.
|
4
|
+
class AuthenticationToken < ActiveRecord::Base
|
5
|
+
TOKEN_LENGTH = 32
|
6
|
+
UUID_LENGTH = 36
|
7
|
+
|
8
|
+
validates :entity_id, :value, :uuid, :client_uuid, presence: true
|
9
|
+
validates :value, :entity_id, :client_uuid, uniqueness: true
|
10
|
+
validates :value, length: { is: TOKEN_LENGTH }
|
11
|
+
validates :uuid, length: { is: UUID_LENGTH }
|
12
|
+
validates :is_enabled, inclusion: { in: [true, false] }
|
13
|
+
|
14
|
+
before_validation :set_value, :set_uuid, on: :create
|
15
|
+
|
16
|
+
def self.find_enabled(client_uuid:, value:)
|
17
|
+
find_by(client_uuid: client_uuid, value: value, is_enabled: true)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def set_value
|
23
|
+
loop do
|
24
|
+
self.value = SecureRandom.hex(TOKEN_LENGTH / 2)
|
25
|
+
break unless self.class.exists?(value: value)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def set_uuid
|
30
|
+
self.uuid = SecureRandom.uuid
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TokenAuth
|
4
|
+
# A single use human readable token for use with client configuration.
|
5
|
+
class ConfigurationToken < ActiveRecord::Base
|
6
|
+
mattr_accessor :valid_period
|
7
|
+
self.valid_period = 4.hours
|
8
|
+
SAMPLE_SET = %w( A B C D E F H J K L M N P Q R S T U V W X Y Z
|
9
|
+
2 3 4 5 7 8 9
|
10
|
+
# $ ).freeze
|
11
|
+
TOKEN_LENGTH = 6
|
12
|
+
|
13
|
+
validates :expires_at, :entity_id, :value, presence: true
|
14
|
+
validates :value, :entity_id, uniqueness: true
|
15
|
+
|
16
|
+
before_validation :set_value, :set_expires_at, on: :create
|
17
|
+
|
18
|
+
# Returns case insensitive match.
|
19
|
+
# rubocop:disable Rails/FindBy
|
20
|
+
def self.find_match(value)
|
21
|
+
return nil unless value.is_a?(String)
|
22
|
+
|
23
|
+
query = value.gsub(/[\s]+/, "")
|
24
|
+
|
25
|
+
return nil unless query.length == TOKEN_LENGTH
|
26
|
+
|
27
|
+
where(arel_table[:expires_at].gt(Time.zone.now))
|
28
|
+
.where(arel_table[:value].matches(query))
|
29
|
+
.first
|
30
|
+
end
|
31
|
+
# rubocop:enable Rails/FindBy
|
32
|
+
|
33
|
+
def make_authentication_token(client_uuid:)
|
34
|
+
return nil if expired?
|
35
|
+
|
36
|
+
authentication_token = AuthenticationToken
|
37
|
+
.new(entity_id: entity_id,
|
38
|
+
client_uuid: client_uuid)
|
39
|
+
transaction do
|
40
|
+
authentication_token.save! && destroy!
|
41
|
+
end
|
42
|
+
|
43
|
+
authentication_token
|
44
|
+
rescue
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
|
48
|
+
def expired?
|
49
|
+
Time.zone.now > expires_at
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def set_value
|
55
|
+
loop do
|
56
|
+
self.value = (0...TOKEN_LENGTH).map { SAMPLE_SET.sample }.join
|
57
|
+
break unless self.class.exists?(value: value)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def set_expires_at
|
62
|
+
self.expires_at = Time.zone.now + self.class.valid_period
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module TokenAuth
|
3
|
+
# An inbound resource. Inbound resource requests are validated and an
|
4
|
+
# attempt is made to upsert them.
|
5
|
+
class Payload
|
6
|
+
attr_reader :valid_resources, :errors
|
7
|
+
|
8
|
+
class MalformedPayloadError < StandardError
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.resource_type(params)
|
12
|
+
params.extract!(:type)[:type]
|
13
|
+
|
14
|
+
rescue NoMethodError
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(entity_id:)
|
19
|
+
@entity_id = entity_id
|
20
|
+
@valid_resources = []
|
21
|
+
@errors = []
|
22
|
+
end
|
23
|
+
|
24
|
+
def save(entities_params)
|
25
|
+
raise MalformedPayloadError unless entities_params.respond_to?(:each)
|
26
|
+
|
27
|
+
entities_params.each do |entity_params|
|
28
|
+
type = self.class.resource_type(entity_params)
|
29
|
+
resource = find_pushable_resource(type)
|
30
|
+
|
31
|
+
if resource
|
32
|
+
upsert_resource(
|
33
|
+
klass: resource.klass,
|
34
|
+
params: entity_params.merge(
|
35
|
+
"#{ resource.entity_id_attribute_name }": @entity_id
|
36
|
+
)
|
37
|
+
)
|
38
|
+
else
|
39
|
+
@errors << "invalid resource '#{ type }'"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def find_pushable_resource(type)
|
47
|
+
SynchronizableResource.find_by(
|
48
|
+
name: type,
|
49
|
+
is_pushable: true,
|
50
|
+
entity_id: @entity_id
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
def upsert_resource(klass:, params:)
|
55
|
+
attributes = deserialize(params)
|
56
|
+
resource = klass.find_or_initialize_by(uuid: attributes.delete("uuid"))
|
57
|
+
|
58
|
+
if resource.update(attributes)
|
59
|
+
@valid_resources << resource
|
60
|
+
else
|
61
|
+
@errors << resource.errors.full_messages.join(", ")
|
62
|
+
end
|
63
|
+
|
64
|
+
rescue ActiveRecord::UnknownAttributeError => error
|
65
|
+
@errors << error.message
|
66
|
+
end
|
67
|
+
|
68
|
+
def deserialize(params)
|
69
|
+
params.each_with_object({}) do |pair, attrs|
|
70
|
+
name, value = pair
|
71
|
+
name = name.to_s.underscore
|
72
|
+
name = "uuid" if name == "id"
|
73
|
+
attrs[name] = value
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module TokenAuth
|
3
|
+
# A resource that may be pushed and/or pulled by an entity.
|
4
|
+
class SynchronizableResource < ActiveRecord::Base
|
5
|
+
include UuidEnabled
|
6
|
+
|
7
|
+
validates :uuid, :entity_id, :entity_id_attribute_name, :name, :class_name,
|
8
|
+
presence: true
|
9
|
+
validates :is_pullable, :is_pushable, inclusion: { in: [true, false] }
|
10
|
+
|
11
|
+
def self.pullable_records_for(entity_id:, filter:)
|
12
|
+
where(is_pullable: true, entity_id: entity_id)
|
13
|
+
.map { |r| apply_filter(r.records, filter) }
|
14
|
+
.flatten
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.apply_filter(relation, filter)
|
18
|
+
return relation unless filter && filter[:updated_at] &&
|
19
|
+
filter[:updated_at][:gt]
|
20
|
+
|
21
|
+
timestamp = filter[:updated_at][:gt]
|
22
|
+
|
23
|
+
relation.where(relation.arel_table[:updated_at].gt(timestamp))
|
24
|
+
end
|
25
|
+
|
26
|
+
def records
|
27
|
+
klass.where(entity_id_attribute_name => entity_id)
|
28
|
+
end
|
29
|
+
|
30
|
+
def klass
|
31
|
+
class_name.constantize
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "active_support/concern"
|
3
|
+
|
4
|
+
module TokenAuth
|
5
|
+
# Create a uuid, and add validation for format and presence of uuid.
|
6
|
+
module UuidEnabled
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
before_validation { self.uuid ||= SecureRandom.uuid }
|
11
|
+
|
12
|
+
validates :uuid, length: { is: 36 }, uniqueness: true, presence: true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
<h2><%= t(".manage_tokens_for", default: "Manage tokens for") %> <%= @entity || @entity_id %></h2>
|
2
|
+
|
3
|
+
<table class="table">
|
4
|
+
<% unless @authentication_token %>
|
5
|
+
<tr id="config-token">
|
6
|
+
<td class="lead">
|
7
|
+
<%= TokenAuth::ConfigurationToken.model_name.human %>
|
8
|
+
</td>
|
9
|
+
<td>
|
10
|
+
<% if @configuration_token %>
|
11
|
+
<% if @configuration_token.expired? %>
|
12
|
+
<span class="label label-warning"><%= t(".expired", default: "Expired") %></span>
|
13
|
+
<% else %>
|
14
|
+
<%= t(".expires_in", default: "Expires in") %> <%= time_ago_in_words @configuration_token.expires_at %>
|
15
|
+
<% end %>
|
16
|
+
<% else %>
|
17
|
+
<%= button_to t(".create", default: "Create"), configuration_token_path(@entity_id), class: "btn btn-default" %>
|
18
|
+
<% end %>
|
19
|
+
</td>
|
20
|
+
<% if @configuration_token %>
|
21
|
+
<td>
|
22
|
+
<% unless @configuration_token.expired? %>
|
23
|
+
<%= t(".value", default: "Value") %> <mark class="lead"><%= @configuration_token.value %></mark>
|
24
|
+
<p><small><%= t(".case_insensitive", default: "case insensitive") %></small></p>
|
25
|
+
<% end %>
|
26
|
+
</td>
|
27
|
+
<td>
|
28
|
+
<%= button_to t(".destroy", default: "Destroy"), token_auth.configuration_token_path(@entity_id), method: :delete, class: "btn btn-warning" %>
|
29
|
+
</td>
|
30
|
+
<% end %>
|
31
|
+
</tr>
|
32
|
+
<% else %>
|
33
|
+
<tr id="auth-token">
|
34
|
+
<td class="lead">
|
35
|
+
<%= @authentication_token.model_name.human %>
|
36
|
+
<% unless @authentication_token.is_enabled? %>
|
37
|
+
<span class="label label-danger"><%= t(".disabled", default: "Disabled") %></span>
|
38
|
+
<% end %>
|
39
|
+
</td>
|
40
|
+
<td>
|
41
|
+
<%= t("activerecord.attributes.token_auth/authentication_token.client_uuid", default: "Client uuid") %> <%= @authentication_token.client_uuid %>
|
42
|
+
</td>
|
43
|
+
<td>
|
44
|
+
<% if @authentication_token.is_enabled? %>
|
45
|
+
<%= button_to t(".disable", default: "Disable"), authentication_token_path(@entity_id), method: :patch, class: "btn btn-warning", params: { is_enabled: false } %>
|
46
|
+
<% else %>
|
47
|
+
<%= button_to t(".enable", default: "Enable"), authentication_token_path(@entity_id), method: :patch, class: "btn btn-info", params: { is_enabled: true } %>
|
48
|
+
<% end %>
|
49
|
+
</td>
|
50
|
+
<td>
|
51
|
+
<%= button_to t(".destroy", default: "Destroy"), authentication_token_path(@entity_id), method: :delete, class: "btn btn-danger", data: { confirm: t(".are_you_sure", default: "Are you sure?") } %>
|
52
|
+
</td>
|
53
|
+
</tr>
|
54
|
+
<% end %>
|
55
|
+
</table>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
en:
|
2
|
+
activerecord:
|
3
|
+
attributes:
|
4
|
+
token_auth/authentication_token:
|
5
|
+
client_uuid: Client uuid
|
6
|
+
cannot_find: Unable to find %{name}
|
7
|
+
success_saving: Successfully saved %{name}
|
8
|
+
failure_saving: "Unable to save %{name}: %{errors}"
|
9
|
+
success_destroying: Successfully destroyed %{name}
|
10
|
+
failure_destroying: "Unable to destroy %{name}: %{errors}"
|
11
|
+
models:
|
12
|
+
token_auth/authentication_token:
|
13
|
+
one: Authentication token
|
14
|
+
other: Authentication tokens
|
15
|
+
token_auth/configuration_token:
|
16
|
+
one: Configuration token
|
17
|
+
other: Configuration tokens
|
18
|
+
token_auth:
|
19
|
+
tokens:
|
20
|
+
index:
|
21
|
+
are_you_sure: Are you sure?
|
22
|
+
case_insensitive: Case insensitive
|
23
|
+
create: Create
|
24
|
+
disable: Disable
|
25
|
+
disabled: Disabled
|
26
|
+
destroy: Destroy
|
27
|
+
enable: Enable
|
28
|
+
expired: Expired
|
29
|
+
expires_in: Expires in
|
30
|
+
manage_tokens_for: Manage tokens for
|
31
|
+
value: Value
|
@@ -0,0 +1,31 @@
|
|
1
|
+
es-PE:
|
2
|
+
activerecord:
|
3
|
+
attributes:
|
4
|
+
token_auth/authentication_token:
|
5
|
+
client_uuid: Identificador único universal (uuid) del cliente
|
6
|
+
cannot_find: No se pudo encontrar %{name}
|
7
|
+
success_saving: Guardado exitosamente %{name}
|
8
|
+
failure_saving: "No se pudo guardar %{name}: %{errors}"
|
9
|
+
success_destroying: Destruido exitosamente %{name}
|
10
|
+
failure_destroying: "No se pudo destruir %{name}: %{errors}"
|
11
|
+
models:
|
12
|
+
token_auth/authentication_token:
|
13
|
+
one: Autorizar identificador
|
14
|
+
other: Autorizar identificador
|
15
|
+
token_auth/configuration_token:
|
16
|
+
one: Identificador
|
17
|
+
other: Identificador
|
18
|
+
token_auth:
|
19
|
+
tokens:
|
20
|
+
index:
|
21
|
+
are_you_sure: ¿Estás seguro?
|
22
|
+
case_insensitive: No distingue mayúsculas y minúsculas
|
23
|
+
create: Crear identificador
|
24
|
+
disable: Desactivar
|
25
|
+
disabled: Inhabilitado
|
26
|
+
destroy: Destruir
|
27
|
+
enable: Activar
|
28
|
+
expired: Vencido
|
29
|
+
expires_in: Vence en
|
30
|
+
manage_tokens_for: Administrar identificador para
|
31
|
+
value: Valor
|
@@ -0,0 +1,31 @@
|
|
1
|
+
pt-BR:
|
2
|
+
activerecord:
|
3
|
+
attributes:
|
4
|
+
token_auth/authentication_token:
|
5
|
+
client_uuid: Identificador Único Universal (uuid) do cliente
|
6
|
+
cannot_find: Não foi possível encontrar %{name}
|
7
|
+
success_saving: Salvo com sucesso %{name}
|
8
|
+
failure_saving: "Não foi possível salvar %{name}: %{errors}"
|
9
|
+
success_destroying: Destruído com sucesso %{name}
|
10
|
+
failure_destroying: "Não foi possível destruir %{name}: %{errors}"
|
11
|
+
models:
|
12
|
+
token_auth/authentication_token:
|
13
|
+
one: Autorizar Token
|
14
|
+
other: Autorizar Token
|
15
|
+
token_auth/configuration_token:
|
16
|
+
one: Configurar token
|
17
|
+
other: Configurar token
|
18
|
+
token_auth:
|
19
|
+
tokens:
|
20
|
+
index:
|
21
|
+
are_you_sure: Está certo disto?
|
22
|
+
case_insensitive: Não distingue maiúsculas e minúsculas
|
23
|
+
create: Criar token
|
24
|
+
disable: Desativar
|
25
|
+
disabled: Desabilitado
|
26
|
+
destroy: Destruir
|
27
|
+
enable: Ativar
|
28
|
+
expired: Expirado
|
29
|
+
expires_in: Expira em
|
30
|
+
manage_tokens_for: Gerenciar Token para
|
31
|
+
value: Valor
|
data/config/routes.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
TokenAuth::Engine.routes.draw do
|
2
|
+
scope '/entities/:entity_id' do
|
3
|
+
resource :authentication_token, only: [:update, :destroy]
|
4
|
+
resource :configuration_token, only: [:create, :destroy]
|
5
|
+
resources :tokens, only: :index
|
6
|
+
end
|
7
|
+
|
8
|
+
namespace :api do
|
9
|
+
match 'authentication_tokens',
|
10
|
+
to: 'authentication_tokens#options',
|
11
|
+
via: :options
|
12
|
+
resources :authentication_tokens, only: :create
|
13
|
+
match 'payloads',
|
14
|
+
to: 'payloads#options',
|
15
|
+
via: :options
|
16
|
+
resources :payloads, only: [:index, :create]
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module CreateConfigurationTokensMigration
|
2
|
+
def change
|
3
|
+
create_table :token_auth_configuration_tokens do |t|
|
4
|
+
t.datetime :expires_at, null: false
|
5
|
+
t.string :value, null: false
|
6
|
+
t.integer :entity_id, null: false
|
7
|
+
end
|
8
|
+
|
9
|
+
add_index :token_auth_configuration_tokens, :entity_id, unique: true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
if ActiveRecord::Migration.respond_to? :[]
|
14
|
+
class CreateConfigurationTokens < ActiveRecord::Migration[4.2]
|
15
|
+
include CreateConfigurationTokensMigration
|
16
|
+
end
|
17
|
+
else
|
18
|
+
class CreateConfigurationTokens < ActiveRecord::Migration
|
19
|
+
include CreateConfigurationTokensMigration
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module CreateAuthenticationTokensMigration
|
2
|
+
def change
|
3
|
+
create_table :token_auth_authentication_tokens do |t|
|
4
|
+
t.integer :entity_id, null: false
|
5
|
+
t.string :value, null: false, limit: ::TokenAuth::AuthenticationToken::TOKEN_LENGTH
|
6
|
+
t.boolean :is_enabled, null: false, default: true
|
7
|
+
t.string :uuid, null: false, limit: ::TokenAuth::AuthenticationToken::UUID_LENGTH
|
8
|
+
t.string :client_uuid, null: false
|
9
|
+
end
|
10
|
+
|
11
|
+
add_index :token_auth_authentication_tokens, :entity_id, unique: true
|
12
|
+
add_index :token_auth_authentication_tokens, :value, unique: true
|
13
|
+
add_index :token_auth_authentication_tokens, :client_uuid, unique: true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
if ActiveRecord::Migration.respond_to? :[]
|
18
|
+
class CreateAuthenticationTokens < ActiveRecord::Migration[4.2]
|
19
|
+
include CreateAuthenticationTokensMigration
|
20
|
+
end
|
21
|
+
else
|
22
|
+
class CreateAuthenticationTokens < ActiveRecord::Migration
|
23
|
+
include CreateAuthenticationTokensMigration
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module CreateTokenAuthSynchronizableResourcesMigration
|
2
|
+
def change
|
3
|
+
create_table :token_auth_synchronizable_resources do |t|
|
4
|
+
t.string :uuid, null: false
|
5
|
+
t.integer :entity_id, null: false
|
6
|
+
t.string :entity_id_attribute_name, null: false
|
7
|
+
t.string :name, null: false
|
8
|
+
t.string :class_name, null: false
|
9
|
+
t.boolean :is_pullable, default: false, null: false
|
10
|
+
t.boolean :is_pushable, default: false, null: false
|
11
|
+
|
12
|
+
t.timestamps null: false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
if ActiveRecord::Migration.respond_to? :[]
|
18
|
+
class CreateTokenAuthSynchronizableResources < ActiveRecord::Migration[4.2]
|
19
|
+
include CreateTokenAuthSynchronizableResourcesMigration
|
20
|
+
end
|
21
|
+
else
|
22
|
+
class CreateTokenAuthSynchronizableResources < ActiveRecord::Migration
|
23
|
+
include CreateTokenAuthSynchronizableResourcesMigration
|
24
|
+
end
|
25
|
+
end
|
data/lib/token_auth.rb
ADDED
metadata
ADDED
@@ -0,0 +1,229 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: token_auth
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0.beta1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Eric Carty-Fickes
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-05-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: active_model_serializers
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.10.0.rc3
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.10.0.rc3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: actionpack
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 5.0.0.rc1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 5.0.0.rc1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: activerecord
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 5.0.0.rc1
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 5.0.0.rc1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: railties
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 5.0.0.rc1
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 5.0.0.rc1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pg
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec-rails
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 3.5.0.beta3
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 3.5.0.beta3
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: capybara
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '2.5'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '2.5'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: brakeman
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rubocop
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: mdl
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: simplecov
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0.11'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0.11'
|
167
|
+
description: A Rails engine that allows for configuring secure communication between
|
168
|
+
client and server via a shared human-readable token.
|
169
|
+
email:
|
170
|
+
- ericcf@northwestern.edu
|
171
|
+
executables: []
|
172
|
+
extensions: []
|
173
|
+
extra_rdoc_files: []
|
174
|
+
files:
|
175
|
+
- MIT-LICENSE
|
176
|
+
- README.md
|
177
|
+
- Rakefile
|
178
|
+
- app/controllers/token_auth/api/authentication_tokens_controller.rb
|
179
|
+
- app/controllers/token_auth/api/base_controller.rb
|
180
|
+
- app/controllers/token_auth/api/payloads_controller.rb
|
181
|
+
- app/controllers/token_auth/authentication_tokens_controller.rb
|
182
|
+
- app/controllers/token_auth/base_controller.rb
|
183
|
+
- app/controllers/token_auth/concerns/api_resources.rb
|
184
|
+
- app/controllers/token_auth/concerns/cors_settings.rb
|
185
|
+
- app/controllers/token_auth/configuration_tokens_controller.rb
|
186
|
+
- app/controllers/token_auth/tokens_controller.rb
|
187
|
+
- app/models/token_auth/authentication_token.rb
|
188
|
+
- app/models/token_auth/configuration_token.rb
|
189
|
+
- app/models/token_auth/payload.rb
|
190
|
+
- app/models/token_auth/synchronizable_resource.rb
|
191
|
+
- app/models/token_auth/uuid_enabled.rb
|
192
|
+
- app/serializers/token_auth/synchronizable_resource_serializer.rb
|
193
|
+
- app/views/token_auth/tokens/index.html.erb
|
194
|
+
- config/locales/en.yml
|
195
|
+
- config/locales/es-PE.yml
|
196
|
+
- config/locales/pt-BR.yml
|
197
|
+
- config/routes.rb
|
198
|
+
- db/migrate/20150428210721_create_configuration_tokens.rb
|
199
|
+
- db/migrate/20150428211137_create_authentication_tokens.rb
|
200
|
+
- db/migrate/20151229184253_create_token_auth_synchronizable_resources.rb
|
201
|
+
- lib/tasks/token_auth_server_rails_tasks.rake
|
202
|
+
- lib/token_auth.rb
|
203
|
+
- lib/token_auth/engine.rb
|
204
|
+
- lib/token_auth/version.rb
|
205
|
+
homepage: https://github.com/NU-CBITS/token_auth
|
206
|
+
licenses:
|
207
|
+
- MIT
|
208
|
+
metadata: {}
|
209
|
+
post_install_message:
|
210
|
+
rdoc_options: []
|
211
|
+
require_paths:
|
212
|
+
- lib
|
213
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
214
|
+
requirements:
|
215
|
+
- - ">="
|
216
|
+
- !ruby/object:Gem::Version
|
217
|
+
version: '0'
|
218
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - ">"
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: 1.3.1
|
223
|
+
requirements: []
|
224
|
+
rubyforge_project:
|
225
|
+
rubygems_version: 2.6.4
|
226
|
+
signing_key:
|
227
|
+
specification_version: 4
|
228
|
+
summary: Rails engine for authenticating clients anonymously.
|
229
|
+
test_files: []
|