authify-api 0.1.0 → 0.2.0
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 +4 -4
- data/.rubocop.yml +3 -1
- data/.travis.yml +3 -1
- data/Dockerfile +46 -0
- data/Rakefile +36 -1
- data/authify-api.gemspec +4 -1
- data/db/migrate/20170328151033_add_verified_to_user.rb +10 -0
- data/db/schema.rb +8 -5
- data/lib/authify/api.rb +5 -0
- data/lib/authify/api/controllers/apikey.rb +3 -3
- data/lib/authify/api/controllers/group.rb +6 -6
- data/lib/authify/api/controllers/identity.rb +4 -4
- data/lib/authify/api/controllers/organization.rb +29 -23
- data/lib/authify/api/controllers/user.rb +23 -14
- data/lib/authify/api/helpers/jwt_encryption.rb +1 -1
- data/lib/authify/api/models/organization.rb +2 -1
- data/lib/authify/api/models/user.rb +28 -2
- data/lib/authify/api/serializers/user_serializer.rb +1 -0
- data/lib/authify/api/services/jwt_provider.rb +1 -8
- data/lib/authify/api/services/registration.rb +40 -10
- data/lib/authify/api/version.rb +1 -1
- metadata +36 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ad42a62cd052be494876ad2448c87fadc49d779
|
4
|
+
data.tar.gz: 63e6a369a12ea65833c62330d6f1df2a25ed1473
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c17f797d481991ff2237c8c9d16b965670094394609a9b0e20fd1745ca6b84de4610a843ee8010bc999f4815975d0cc12aeb678966232f8fc0137b50c2835d80
|
7
|
+
data.tar.gz: 0eb621c92eaa49877952c8b3cf03741056af7084170c05af708ba0d921dbc4f62d741bdddefa5cad85975a4457ba593a494302324abb62478cd20ff470faf31e
|
data/.rubocop.yml
CHANGED
@@ -16,12 +16,14 @@ Metrics/CyclomaticComplexity:
|
|
16
16
|
Metrics/PerceivedComplexity:
|
17
17
|
Max: 9
|
18
18
|
|
19
|
-
BlockLength:
|
19
|
+
Metrics/BlockLength:
|
20
20
|
Max: 30
|
21
21
|
Exclude:
|
22
22
|
- '*.gemspec'
|
23
23
|
- 'lib/authify/api/controllers/*.rb'
|
24
24
|
- Rakefile
|
25
|
+
- 'spec/**/*_spec.rb'
|
26
|
+
- 'spec/spec_helper.rb'
|
25
27
|
|
26
28
|
AllCops:
|
27
29
|
Exclude:
|
data/.travis.yml
CHANGED
data/Dockerfile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
FROM ruby:2.3.3-alpine
|
2
|
+
|
3
|
+
ENV AUTHIFY_PORT=9292
|
4
|
+
ENV AUTHIFY_ENVIRONMENT=development
|
5
|
+
ENV AUTHIFY_DB_URL=sqlite3:///app/authify-api.db
|
6
|
+
ENV AUTHIFY_REDIS_HOST=redis
|
7
|
+
ENV AUTHIFY_PUBKEY_PATH=/ssl/public.pem
|
8
|
+
ENV AUTHIFY_PRIVKEY_PATH=/ssl/private.pem
|
9
|
+
ENV AUTHIFY_JWT_ISSUER="My Awesome Company Inc."
|
10
|
+
ENV AUTHIFY_JWT_ALGORITHM="ES512"
|
11
|
+
ENV AUTHIFY_JWT_EXPIRATION="15"
|
12
|
+
|
13
|
+
RUN apk --no-cache upgrade \
|
14
|
+
&& apk --no-cache add \
|
15
|
+
git \
|
16
|
+
sqlite-libs mariadb-client mariadb-client-libs
|
17
|
+
|
18
|
+
RUN apk --no-cache add --virtual build-dependencies \
|
19
|
+
build-base \
|
20
|
+
ruby-dev \
|
21
|
+
sqlite-dev \
|
22
|
+
mariadb-dev
|
23
|
+
|
24
|
+
COPY . /app
|
25
|
+
RUN cd /app \
|
26
|
+
&& bundle install --jobs=4 \
|
27
|
+
&& apk del build-dependencies
|
28
|
+
|
29
|
+
RUN mkdir /ssl
|
30
|
+
|
31
|
+
RUN chown -R root:root /app \
|
32
|
+
&& chown nobody:nogroup /app/db \
|
33
|
+
&& chown nobody:nogroup /app/db/schema.rb \
|
34
|
+
&& rm -f /app/.travis.yml \
|
35
|
+
&& chown -R nobody:nogroup /ssl
|
36
|
+
|
37
|
+
USER nobody
|
38
|
+
WORKDIR /app
|
39
|
+
|
40
|
+
VOLUME /ssl
|
41
|
+
|
42
|
+
CMD bundle exec rake db:migrate \
|
43
|
+
&& bundle exec rackup \
|
44
|
+
-o 0.0.0.0 \
|
45
|
+
-p $AUTHIFY_PORT \
|
46
|
+
-E $AUTHIFY_ENVIRONMENT
|
data/Rakefile
CHANGED
@@ -12,13 +12,41 @@ end
|
|
12
12
|
RSpec::Core::RakeTask.new(:spec)
|
13
13
|
RuboCop::RakeTask.new(:rubocop)
|
14
14
|
|
15
|
-
task default:
|
15
|
+
task default: %i(spec rubocop)
|
16
16
|
|
17
17
|
desc 'Start the demo using `rackup`'
|
18
18
|
task :start do
|
19
19
|
exec 'rackup config.ru'
|
20
20
|
end
|
21
21
|
|
22
|
+
namespace :jwt do
|
23
|
+
desc 'Generate a Signer Certificate'
|
24
|
+
task :gencert do
|
25
|
+
jwtalgo = ENV['AUTHIFY_JWT_ALGORITHM']
|
26
|
+
privpath = ENV['AUTHIFY_PRIVKEY_PATH']
|
27
|
+
pubpath = ENV['AUTHIFY_PUBKEY_PATH']
|
28
|
+
raise 'Missing ENV settings' unless jwtalgo && privpath && pubpath
|
29
|
+
|
30
|
+
require 'authify/api'
|
31
|
+
algo = case jwtalgo
|
32
|
+
when 'ES256'
|
33
|
+
'prime256v1'
|
34
|
+
when 'ES384'
|
35
|
+
'secp384r1'
|
36
|
+
when 'ES512'
|
37
|
+
'secp521r1'
|
38
|
+
end
|
39
|
+
secret_key = OpenSSL::PKey::EC.new(algo)
|
40
|
+
secret_key.generate_key
|
41
|
+
# write out the private key to a file...
|
42
|
+
File.write(File.expand_path(privpath), secret_key.to_pem)
|
43
|
+
public_key = secret_key
|
44
|
+
public_key.private_key = nil
|
45
|
+
# write out the public key to a file...
|
46
|
+
File.write(File.expand_path(pubpath), public_key.to_pem)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
22
50
|
namespace :delegate do
|
23
51
|
desc 'Add a Trusted Delegate'
|
24
52
|
task :add, [:name] do |_t, args|
|
@@ -56,3 +84,10 @@ namespace :delegate do
|
|
56
84
|
end
|
57
85
|
end
|
58
86
|
end
|
87
|
+
|
88
|
+
namespace :docker do
|
89
|
+
desc 'Build a fresh docker image'
|
90
|
+
task :build do
|
91
|
+
exec 'docker build -t authify/api .'
|
92
|
+
end
|
93
|
+
end
|
data/authify-api.gemspec
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
|
2
3
|
lib = File.expand_path('../lib', __FILE__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require 'authify/api/version'
|
@@ -22,7 +23,7 @@ Gem::Specification.new do |spec|
|
|
22
23
|
|
23
24
|
spec.required_ruby_version = '~> 2.0'
|
24
25
|
|
25
|
-
spec.add_runtime_dependency 'authify-core'
|
26
|
+
spec.add_runtime_dependency 'authify-core', '~> 0.1'
|
26
27
|
spec.add_runtime_dependency 'authify-middleware'
|
27
28
|
spec.add_runtime_dependency 'connection_pool', '~> 2.2'
|
28
29
|
spec.add_runtime_dependency 'sinatra', '>= 2.0.0.beta2', '< 3'
|
@@ -35,6 +36,7 @@ Gem::Specification.new do |spec|
|
|
35
36
|
spec.add_runtime_dependency 'jsonapi-serializers', '~> 0.16'
|
36
37
|
# spec.add_runtime_dependency 'sinja', '~> 1.2', '>= 1.2.4'
|
37
38
|
spec.add_runtime_dependency 'puma', '~> 3.7'
|
39
|
+
spec.add_runtime_dependency 'resque', '~> 1.26'
|
38
40
|
|
39
41
|
spec.add_development_dependency 'bundler', '~> 1.12'
|
40
42
|
spec.add_development_dependency 'rake', '~> 10.0'
|
@@ -43,4 +45,5 @@ Gem::Specification.new do |spec|
|
|
43
45
|
spec.add_development_dependency 'yard', '~> 0.8'
|
44
46
|
spec.add_development_dependency 'travis', '~> 1.8'
|
45
47
|
spec.add_development_dependency 'simplecov', '~> 0.13'
|
48
|
+
spec.add_development_dependency 'rack-test', '~> 0.6'
|
46
49
|
end
|
data/db/schema.rb
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
#
|
11
11
|
# It's strongly recommended that you check this file into your version control system.
|
12
12
|
|
13
|
-
ActiveRecord::Schema.define(version:
|
13
|
+
ActiveRecord::Schema.define(version: 20170328151033) do
|
14
14
|
|
15
15
|
create_table "apikeys", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
|
16
16
|
t.integer "user_id"
|
@@ -85,13 +85,16 @@ ActiveRecord::Schema.define(version: 20170208022427) do
|
|
85
85
|
|
86
86
|
create_table "users", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
|
87
87
|
t.string "email"
|
88
|
-
t.text "password_digest",
|
88
|
+
t.text "password_digest", limit: 65535
|
89
89
|
t.string "full_name"
|
90
|
-
t.datetime "created_at",
|
91
|
-
t.datetime "updated_at",
|
92
|
-
t.boolean "admin",
|
90
|
+
t.datetime "created_at", null: false
|
91
|
+
t.datetime "updated_at", null: false
|
92
|
+
t.boolean "admin", default: false, null: false
|
93
|
+
t.boolean "verified"
|
94
|
+
t.string "verification_token"
|
93
95
|
t.index ["admin"], name: "index_users_on_admin", using: :btree
|
94
96
|
t.index ["email"], name: "index_users_on_email", using: :btree
|
97
|
+
t.index ["verified"], name: "index_users_on_verified", using: :btree
|
95
98
|
end
|
96
99
|
|
97
100
|
end
|
data/lib/authify/api.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
# External Requirements
|
4
4
|
require 'authify/core'
|
5
|
+
require 'authify/core/jobs/email'
|
5
6
|
require 'authify/middleware'
|
6
7
|
require 'sinatra/base'
|
7
8
|
require 'sinatra/activerecord'
|
@@ -10,6 +11,7 @@ require 'sinatra/jsonapi'
|
|
10
11
|
require 'tilt/erb'
|
11
12
|
require 'connection_pool'
|
12
13
|
require 'moneta'
|
14
|
+
require 'resque'
|
13
15
|
|
14
16
|
# Internal Requirements
|
15
17
|
module Authify
|
@@ -26,6 +28,9 @@ module Authify
|
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
31
|
+
redis_config = Authify::API::CONFIG[:redis]
|
32
|
+
Resque.redis = "#{redis_config[:host]}:#{redis_config[:port]}"
|
33
|
+
|
29
34
|
require 'authify/api/version'
|
30
35
|
require 'authify/api/jsonapi_utils'
|
31
36
|
require 'authify/api/controllers/apikey'
|
@@ -18,7 +18,7 @@ module Authify
|
|
18
18
|
Models::APIKey.all
|
19
19
|
end
|
20
20
|
|
21
|
-
show(roles:
|
21
|
+
show(roles: %i(myself admin)) do
|
22
22
|
last_modified resource.updated_at
|
23
23
|
next resource, exclude: [:secret_key]
|
24
24
|
end
|
@@ -31,7 +31,7 @@ module Authify
|
|
31
31
|
next key.id, key
|
32
32
|
end
|
33
33
|
|
34
|
-
destroy(roles:
|
34
|
+
destroy(roles: %i(myself admin)) do
|
35
35
|
resource.destroy
|
36
36
|
end
|
37
37
|
|
@@ -40,7 +40,7 @@ module Authify
|
|
40
40
|
end
|
41
41
|
|
42
42
|
has_one :user do
|
43
|
-
pluck(roles:
|
43
|
+
pluck(roles: %i(myself admin)) do
|
44
44
|
resource.user
|
45
45
|
end
|
46
46
|
end
|
@@ -19,7 +19,7 @@ module Authify
|
|
19
19
|
Models::Group.all
|
20
20
|
end
|
21
21
|
|
22
|
-
show(roles:
|
22
|
+
show(roles: %i(admin owner)) do
|
23
23
|
last_modified resource.updated_at
|
24
24
|
next resource
|
25
25
|
end
|
@@ -30,7 +30,7 @@ module Authify
|
|
30
30
|
next g
|
31
31
|
end
|
32
32
|
|
33
|
-
destroy(roles:
|
33
|
+
destroy(roles: %i(admin owner)) do
|
34
34
|
resource.destroy
|
35
35
|
end
|
36
36
|
|
@@ -39,23 +39,23 @@ module Authify
|
|
39
39
|
end
|
40
40
|
|
41
41
|
has_many :users do
|
42
|
-
fetch(roles:
|
42
|
+
fetch(roles: %i(admin owner)) do
|
43
43
|
resource.users
|
44
44
|
end
|
45
45
|
|
46
|
-
replace(roles:
|
46
|
+
replace(roles: %i(admin owner)) do |rios|
|
47
47
|
refs = rios.map { |attrs| Models::User.find(attrs) }
|
48
48
|
resource.users = refs
|
49
49
|
resource.save
|
50
50
|
end
|
51
51
|
|
52
|
-
merge(roles:
|
52
|
+
merge(roles: %i(admin owner)) do |rios|
|
53
53
|
refs = rios.map { |attrs| Models::User.find(attrs) }
|
54
54
|
resource.users << refs
|
55
55
|
resource.save
|
56
56
|
end
|
57
57
|
|
58
|
-
subtract(roles:
|
58
|
+
subtract(roles: %i(admin owner)) do |rios|
|
59
59
|
refs = rios.map { |attrs| Models::User.find(attrs) }
|
60
60
|
# This only removes the linkage, not the actual users
|
61
61
|
resource.users.delete(refs)
|
@@ -14,11 +14,11 @@ module Authify
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
index(roles:
|
17
|
+
index(roles: %i(admin trusted)) do
|
18
18
|
Models::Identity.all
|
19
19
|
end
|
20
20
|
|
21
|
-
show(roles:
|
21
|
+
show(roles: %i(myself admin trusted)) do
|
22
22
|
last_modified resource.updated_at
|
23
23
|
next resource
|
24
24
|
end
|
@@ -30,7 +30,7 @@ module Authify
|
|
30
30
|
next ident.id, ident
|
31
31
|
end
|
32
32
|
|
33
|
-
destroy(roles:
|
33
|
+
destroy(roles: %i(myself admin)) do
|
34
34
|
resource.destroy
|
35
35
|
end
|
36
36
|
|
@@ -39,7 +39,7 @@ module Authify
|
|
39
39
|
end
|
40
40
|
|
41
41
|
has_one :user do
|
42
|
-
pluck(roles:
|
42
|
+
pluck(roles: %i(myself admin trusted)) do
|
43
43
|
resource.user
|
44
44
|
end
|
45
45
|
end
|
@@ -4,7 +4,7 @@ module Authify
|
|
4
4
|
Organization = proc do
|
5
5
|
helpers do
|
6
6
|
def find(id)
|
7
|
-
Models::Organization.find(id.to_i)
|
7
|
+
Models::Organization.includes(:users, :groups, :admins).find(id.to_i)
|
8
8
|
end
|
9
9
|
|
10
10
|
def role
|
@@ -15,15 +15,15 @@ module Authify
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def modifiable_fields
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
18
|
+
%i(
|
19
|
+
name
|
20
|
+
public_email
|
21
|
+
gravatar_email
|
22
|
+
billing_email
|
23
|
+
description
|
24
|
+
url
|
25
|
+
location
|
26
|
+
)
|
27
27
|
end
|
28
28
|
|
29
29
|
def filtered_attributes(attributes)
|
@@ -41,54 +41,60 @@ module Authify
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
index(roles:
|
45
|
-
Models::Organization.
|
44
|
+
index(roles: %i(admin user)) do
|
45
|
+
Models::Organization.includes(:users, :groups, :admins)
|
46
46
|
end
|
47
47
|
|
48
48
|
get '/mine' do
|
49
49
|
halt(403) unless can?(:create)
|
50
|
-
serialize_models current_user.organizations
|
50
|
+
serialize_models current_user.organizations.includes(:users, :groups, :admins)
|
51
51
|
end
|
52
52
|
|
53
53
|
show(roles: [:user]) do
|
54
54
|
last_modified resource.updated_at
|
55
|
-
|
55
|
+
exclude = []
|
56
|
+
unless role?(:admin, :owner)
|
57
|
+
exclude << 'billing_email'
|
58
|
+
exclude << 'gravatar_email'
|
59
|
+
end
|
60
|
+
next resource, exclude: exclude
|
56
61
|
end
|
57
62
|
|
58
63
|
show_many do |ids|
|
59
|
-
Models::Organization.find(ids)
|
64
|
+
Models::Organization.includes(:users, :groups, :admins).find(ids)
|
60
65
|
end
|
61
66
|
|
62
67
|
create(roles: [:user]) do |attrs|
|
63
|
-
o = Models::Organization.new(attrs)
|
64
|
-
|
68
|
+
o = Models::Organization.new filtered_attributes(attrs)
|
69
|
+
new_member = Models::OrganizationMembership.new(user: current_user, admin: true)
|
70
|
+
o.organization_memberships << new_member
|
65
71
|
o.save
|
66
|
-
next o
|
72
|
+
next o.id, o
|
67
73
|
end
|
68
74
|
|
69
|
-
update(roles:
|
75
|
+
update(roles: %i(owner admin)) do |attrs|
|
70
76
|
resource.update filtered_attributes(attrs)
|
71
77
|
next resource
|
72
78
|
end
|
73
79
|
|
74
|
-
destroy(roles:
|
80
|
+
destroy(roles: %i(owner admin)) do
|
75
81
|
resource.destroy
|
76
82
|
end
|
77
83
|
|
78
84
|
has_many :users do
|
79
|
-
fetch(roles:
|
85
|
+
fetch(roles: %i(owner admin member)) do
|
80
86
|
resource.users
|
81
87
|
end
|
82
88
|
end
|
83
89
|
|
84
90
|
has_many :admins do
|
85
|
-
fetch(roles:
|
91
|
+
fetch(roles: %i(owner admin member)) do
|
86
92
|
resource.admins
|
87
93
|
end
|
88
94
|
end
|
89
95
|
|
90
96
|
has_many :groups do
|
91
|
-
fetch(roles:
|
97
|
+
fetch(roles: %i(owner admin member)) do
|
92
98
|
resource.groups
|
93
99
|
end
|
94
100
|
end
|
@@ -8,13 +8,13 @@ module Authify
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def role
|
11
|
-
Array(super).tap do |a|
|
11
|
+
Array(super.dup).tap do |a|
|
12
12
|
a << :myself if current_user && resource && (resource.id == current_user.id)
|
13
13
|
end.uniq
|
14
14
|
end
|
15
15
|
|
16
16
|
def modifiable_fields
|
17
|
-
|
17
|
+
%i(full_name email).tap do |a|
|
18
18
|
a << :admin if role.include?(:admin)
|
19
19
|
end
|
20
20
|
end
|
@@ -34,11 +34,11 @@ module Authify
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
index(roles:
|
37
|
+
index(roles: %i(user trusted)) do
|
38
38
|
Models::User.all
|
39
39
|
end
|
40
40
|
|
41
|
-
show(roles:
|
41
|
+
show(roles: %i(user trusted)) do
|
42
42
|
last_modified resource.updated_at
|
43
43
|
next resource
|
44
44
|
end
|
@@ -49,21 +49,30 @@ module Authify
|
|
49
49
|
next user
|
50
50
|
end
|
51
51
|
|
52
|
+
update(roles: %i(admin myself)) do |attrs|
|
53
|
+
# Necessary because #password= is overridden for Models::User
|
54
|
+
new_pass = attrs[:password] if attrs && attrs.key?(:password)
|
55
|
+
resource.update filtered_attributes(attrs)
|
56
|
+
resource.password = new_pass if new_pass
|
57
|
+
resource.save
|
58
|
+
next resource
|
59
|
+
end
|
60
|
+
|
52
61
|
show_many do |ids|
|
53
62
|
Models::User.find(ids)
|
54
63
|
end
|
55
64
|
|
56
65
|
has_many :apikeys do
|
57
|
-
fetch(roles:
|
66
|
+
fetch(roles: %i(myself admin)) do
|
58
67
|
resource.apikeys
|
59
68
|
end
|
60
69
|
|
61
|
-
clear(roles:
|
70
|
+
clear(roles: %i(myself admin)) do
|
62
71
|
resource.apikeys.destroy_all
|
63
72
|
resource.save
|
64
73
|
end
|
65
74
|
|
66
|
-
subtract(roles:
|
75
|
+
subtract(roles: %i(myself admin)) do |rios|
|
67
76
|
refs = rios.map { |attrs| Models::APIKey.find(attrs) }
|
68
77
|
# This actually calls #destroy on the keys (we don't need orphaned keys)
|
69
78
|
resource.apikeys.destroy(refs)
|
@@ -72,36 +81,36 @@ module Authify
|
|
72
81
|
end
|
73
82
|
|
74
83
|
has_many :identities do
|
75
|
-
fetch(roles:
|
84
|
+
fetch(roles: %i(myself admin trusted)) do
|
76
85
|
resource.identities
|
77
86
|
end
|
78
87
|
|
79
|
-
clear(roles:
|
88
|
+
clear(roles: %i(myself admin)) do
|
80
89
|
resource.identities.destroy_all
|
81
90
|
resource.save
|
82
91
|
end
|
83
92
|
|
84
93
|
merge(roles: [:myself]) do |rios|
|
85
|
-
refs = rios.map { |attrs| Models::
|
94
|
+
refs = rios.map { |attrs| Models::Identity.new(attrs) }
|
86
95
|
resource.identities << refs
|
87
96
|
resource.save
|
88
97
|
end
|
89
98
|
|
90
|
-
subtract(roles:
|
91
|
-
refs = rios.map { |attrs| Models::
|
99
|
+
subtract(roles: %i(myself admin)) do |rios|
|
100
|
+
refs = rios.map { |attrs| Models::Identity.find(attrs) }
|
92
101
|
resource.identities.destroy(refs)
|
93
102
|
resource.save
|
94
103
|
end
|
95
104
|
end
|
96
105
|
|
97
106
|
has_many :organizations do
|
98
|
-
fetch(roles:
|
107
|
+
fetch(roles: %i(user myself admin)) do
|
99
108
|
resource.organizations
|
100
109
|
end
|
101
110
|
end
|
102
111
|
|
103
112
|
has_many :groups do
|
104
|
-
fetch(roles:
|
113
|
+
fetch(roles: %i(myself admin)) do
|
105
114
|
resource.groups
|
106
115
|
end
|
107
116
|
end
|
@@ -16,7 +16,7 @@ module Authify
|
|
16
16
|
iat: Time.now.to_i,
|
17
17
|
iss: CONFIG[:jwt][:issuer],
|
18
18
|
scopes: Core::Constants::JWTSCOPES.dup.tap do |scopes|
|
19
|
-
scopes << :admin_access if
|
19
|
+
scopes << :admin_access if user.admin?
|
20
20
|
end,
|
21
21
|
user: {
|
22
22
|
username: user.email,
|
@@ -38,21 +38,47 @@ module Authify
|
|
38
38
|
|
39
39
|
def authenticate(unencrypted_password)
|
40
40
|
return false unless unencrypted_password && !unencrypted_password.empty?
|
41
|
+
return false unless password_digest && !password_digest.empty?
|
41
42
|
compare_salted_sha512(unencrypted_password, password_digest)
|
42
43
|
end
|
43
44
|
|
45
|
+
def verify(vtoken)
|
46
|
+
return false unless verification_token
|
47
|
+
token, valid_until = verification_token.split(':')
|
48
|
+
token == vtoken && Time.now.to_i <= Integer(valid_until)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Both sets a token in the DB *and* emails it to the user
|
52
|
+
def set_verification_token!
|
53
|
+
return false if verified?
|
54
|
+
token = peppered_sha512(rand(999).to_s)[0...16]
|
55
|
+
valid_until = (Time.now + (15 * 60)).to_i
|
56
|
+
self.verification_token = "#{token}:#{valid_until}"
|
57
|
+
|
58
|
+
email_opts = {
|
59
|
+
body: "Your verification token is: #{token}"
|
60
|
+
}
|
61
|
+
|
62
|
+
Resque.enqueue(
|
63
|
+
Authify::Core::Jobs::Email,
|
64
|
+
email,
|
65
|
+
'Authify Verification Email',
|
66
|
+
email_opts
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
44
70
|
def admin_for?(organization)
|
45
71
|
admin? || organization.admins.include?(self)
|
46
72
|
end
|
47
73
|
|
48
74
|
def self.from_api_key(access, secret)
|
49
75
|
key = APIKey.find_by_access_key(access)
|
50
|
-
key.user if key && key.compare_secret(secret)
|
76
|
+
key.user if key && key.compare_secret(secret) && key.user.verified?
|
51
77
|
end
|
52
78
|
|
53
79
|
def self.from_email(email, password)
|
54
80
|
found_user = Models::User.find_by_email(email)
|
55
|
-
found_user if found_user && found_user.authenticate(password)
|
81
|
+
found_user if found_user && found_user.authenticate(password) && found_user.verified?
|
56
82
|
end
|
57
83
|
|
58
84
|
def self.from_identity(provider, uid)
|
@@ -36,19 +36,12 @@ module Authify
|
|
36
36
|
email = @parsed_body[:email]
|
37
37
|
password = @parsed_body[:password]
|
38
38
|
# For Trusted Delegates signing users in via omniauth
|
39
|
-
del_data = @parsed_body[:delegate]
|
40
39
|
omni_provider = @parsed_body[:provider]
|
41
40
|
omni_uid = @parsed_body[:uid]
|
42
|
-
trusted_delegate = if del_data
|
43
|
-
Models::TrustedDelegate.from_access_key(
|
44
|
-
del_data[:access],
|
45
|
-
del_data[:secret]
|
46
|
-
)
|
47
|
-
end
|
48
41
|
|
49
42
|
found_user = if access
|
50
43
|
Models::User.from_api_key(access, secret)
|
51
|
-
elsif
|
44
|
+
elsif remote_app
|
52
45
|
Models::User.from_identity(omni_provider, omni_uid)
|
53
46
|
elsif email
|
54
47
|
Models::User.from_email(email, password)
|
@@ -33,29 +33,59 @@ module Authify
|
|
33
33
|
via = @parsed_body[:via]
|
34
34
|
password = @parsed_body[:password]
|
35
35
|
name = @parsed_body[:name]
|
36
|
-
del_data = @parsed_body[:delegate]
|
37
|
-
trusted_delegate = if del_data
|
38
|
-
Models::TrustedDelegate.from_access_key(
|
39
|
-
del_data[:access],
|
40
|
-
del_data[:secret]
|
41
|
-
)
|
42
|
-
end
|
43
36
|
|
44
37
|
halt(422, 'Duplicate User') if Models::User.exists?(email: email)
|
45
|
-
halt(403, 'Password Required') unless password ||
|
38
|
+
halt(403, 'Password Required') unless password || remote_app
|
46
39
|
|
47
40
|
new_user = Models::User.new(email: email)
|
48
41
|
new_user.full_name = name if name
|
49
42
|
new_user.password = password if password
|
50
|
-
if via && via[:provider]
|
43
|
+
if via && via[:provider] && remote_app
|
51
44
|
new_user.identities.build(
|
52
45
|
provider: via[:provider],
|
53
46
|
uid: via[:uid] ? via[:uid] : email
|
54
47
|
)
|
48
|
+
new_user.verified = true
|
49
|
+
else
|
50
|
+
new_user.set_verification_token!
|
55
51
|
end
|
52
|
+
|
56
53
|
new_user.save
|
57
54
|
update_current_user new_user
|
58
|
-
|
55
|
+
|
56
|
+
response = { id: new_user.id, email: new_user.email }
|
57
|
+
if new_user.verified?
|
58
|
+
response[:verified] = true
|
59
|
+
response[:jwt] = jwt_token(new_user)
|
60
|
+
else
|
61
|
+
response[:verified] = false
|
62
|
+
end
|
63
|
+
response.to_json
|
64
|
+
end
|
65
|
+
|
66
|
+
post '/verify' do
|
67
|
+
email = @parsed_body[:email]
|
68
|
+
password = @parsed_body[:password]
|
69
|
+
token = @parsed_body[:token]
|
70
|
+
|
71
|
+
halt(422, 'Invalid User') unless Models::User.exists?(email: email)
|
72
|
+
halt(403, 'Missing Parameters') unless email && password && token
|
73
|
+
|
74
|
+
found_user = Models::User.find_by_email(email)
|
75
|
+
if found_user.authenticate(password) && found_user.verify(token)
|
76
|
+
found_user.verified = true
|
77
|
+
else
|
78
|
+
halt(422, 'Verification Failed')
|
79
|
+
end
|
80
|
+
found_user.save
|
81
|
+
update_current_user found_user
|
82
|
+
|
83
|
+
{
|
84
|
+
id: found_user.id,
|
85
|
+
email: found_user.email,
|
86
|
+
verified: found_user.verified?,
|
87
|
+
jwt: jwt_token(found_user)
|
88
|
+
}.to_json
|
59
89
|
end
|
60
90
|
end
|
61
91
|
end
|
data/lib/authify/api/version.rb
CHANGED
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: authify-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Gnagy
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-03-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: authify-core
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
19
|
+
version: '0.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
26
|
+
version: '0.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: authify-middleware
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -190,6 +190,20 @@ dependencies:
|
|
190
190
|
- - "~>"
|
191
191
|
- !ruby/object:Gem::Version
|
192
192
|
version: '3.7'
|
193
|
+
- !ruby/object:Gem::Dependency
|
194
|
+
name: resque
|
195
|
+
requirement: !ruby/object:Gem::Requirement
|
196
|
+
requirements:
|
197
|
+
- - "~>"
|
198
|
+
- !ruby/object:Gem::Version
|
199
|
+
version: '1.26'
|
200
|
+
type: :runtime
|
201
|
+
prerelease: false
|
202
|
+
version_requirements: !ruby/object:Gem::Requirement
|
203
|
+
requirements:
|
204
|
+
- - "~>"
|
205
|
+
- !ruby/object:Gem::Version
|
206
|
+
version: '1.26'
|
193
207
|
- !ruby/object:Gem::Dependency
|
194
208
|
name: bundler
|
195
209
|
requirement: !ruby/object:Gem::Requirement
|
@@ -288,6 +302,20 @@ dependencies:
|
|
288
302
|
- - "~>"
|
289
303
|
- !ruby/object:Gem::Version
|
290
304
|
version: '0.13'
|
305
|
+
- !ruby/object:Gem::Dependency
|
306
|
+
name: rack-test
|
307
|
+
requirement: !ruby/object:Gem::Requirement
|
308
|
+
requirements:
|
309
|
+
- - "~>"
|
310
|
+
- !ruby/object:Gem::Version
|
311
|
+
version: '0.6'
|
312
|
+
type: :development
|
313
|
+
prerelease: false
|
314
|
+
version_requirements: !ruby/object:Gem::Requirement
|
315
|
+
requirements:
|
316
|
+
- - "~>"
|
317
|
+
- !ruby/object:Gem::Version
|
318
|
+
version: '0.6'
|
291
319
|
description:
|
292
320
|
email:
|
293
321
|
- jgnagy@knuedge.com
|
@@ -299,6 +327,7 @@ files:
|
|
299
327
|
- ".rspec"
|
300
328
|
- ".rubocop.yml"
|
301
329
|
- ".travis.yml"
|
330
|
+
- Dockerfile
|
302
331
|
- Gemfile
|
303
332
|
- LICENSE.txt
|
304
333
|
- README.md
|
@@ -315,6 +344,7 @@ files:
|
|
315
344
|
- db/migrate/20170204001405_create_trusted_delegates.rb
|
316
345
|
- db/migrate/20170208021933_add_admin_to_user.rb
|
317
346
|
- db/migrate/20170208022427_set_default_for_user_admin.rb
|
347
|
+
- db/migrate/20170328151033_add_verified_to_user.rb
|
318
348
|
- db/schema.rb
|
319
349
|
- lib/authify/api.rb
|
320
350
|
- lib/authify/api/controllers/apikey.rb
|