token_auth 0.3.0.beta1
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 +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: []
|