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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a0f77e5a23fef6d16a82c095c2f76b9840dcf33f
4
- data.tar.gz: c77e75b1605e0ea51c1bd589b47e9ca859735ba1
3
+ metadata.gz: 1ad42a62cd052be494876ad2448c87fadc49d779
4
+ data.tar.gz: 63e6a369a12ea65833c62330d6f1df2a25ed1473
5
5
  SHA512:
6
- metadata.gz: fb9a4ed3c1c41e5e3ef207521fcc33d1fe50177eafdfb4037702ae0bf81a941b48d81b266230339a71cdf2e896616325d009f08f656f1a869fa4220588edee63
7
- data.tar.gz: 0afea4d9d48418bae6f32d597f15c440259c49e84da4d4403dfdb41ca30e7d3b6d0102f7b5e01f98aba9f40f9cd332b8f1f3b9cd065c970a4f86b1274207e110
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
@@ -1,7 +1,9 @@
1
1
  sudo: false
2
2
  language: ruby
3
+ services:
4
+ - redis-server
3
5
  rvm:
4
- - 2.3.1
6
+ - 2.3.3
5
7
  before_install: gem install bundler -v 1.12.5
6
8
  deploy:
7
9
  provider: rubygems
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: [:spec, :rubocop]
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
@@ -0,0 +1,10 @@
1
+ # User verifications
2
+ class AddVerifiedToUser < ActiveRecord::Migration[5.0]
3
+ def change
4
+ change_table :users do |t|
5
+ t.boolean :verified
6
+ t.string :verification_token
7
+ t.index :verified
8
+ end
9
+ end
10
+ 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: 20170208022427) do
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", limit: 65535
88
+ t.text "password_digest", limit: 65535
89
89
  t.string "full_name"
90
- t.datetime "created_at", null: false
91
- t.datetime "updated_at", null: false
92
- t.boolean "admin", default: false, null: false
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: [:myself, :admin]) do
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: [:myself, :admin]) do
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: [:myself, :admin]) do
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: [:admin, :owner]) do
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: [:admin, :owner]) do
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: [:admin, :owner]) do
42
+ fetch(roles: %i(admin owner)) do
43
43
  resource.users
44
44
  end
45
45
 
46
- replace(roles: [:admin, :owner]) do |rios|
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: [:admin, :owner]) do |rios|
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: [:admin, :owner]) do |rios|
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: [:admin, :trusted]) do
17
+ index(roles: %i(admin trusted)) do
18
18
  Models::Identity.all
19
19
  end
20
20
 
21
- show(roles: [:myself, :admin, :trusted]) do
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: [:myself, :admin]) do
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: [:myself, :admin, :trusted]) do
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
- :name,
20
- :public_email,
21
- :gravatar_email,
22
- :billing_email,
23
- :description,
24
- :url,
25
- :location
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: [:admin]) do
45
- Models::Organization.all
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
- next resource
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
- o.admins << current_user
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: [:owner, :admin]) do |attrs|
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: [:owner, :admin]) do
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: [:owner, :admin, :member]) do
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: [:owner, :admin, :member]) do
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: [:owner, :admin]) do
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
- [:full_name, :email].tap do |a|
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: [:user, :trusted]) do
37
+ index(roles: %i(user trusted)) do
38
38
  Models::User.all
39
39
  end
40
40
 
41
- show(roles: [:user, :trusted]) do
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: [:myself, :admin]) do
66
+ fetch(roles: %i(myself admin)) do
58
67
  resource.apikeys
59
68
  end
60
69
 
61
- clear(roles: [:myself, :admin]) do
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: [:myself, :admin]) do |rios|
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: [:myself, :admin, :trusted]) do
84
+ fetch(roles: %i(myself admin trusted)) do
76
85
  resource.identities
77
86
  end
78
87
 
79
- clear(roles: [:myself, :admin]) do
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::Identities.new(attrs) }
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: [:myself, :admin]) do |rios|
91
- refs = rios.map { |attrs| Models::Identities.find(attrs) }
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: [:user, :myself]) do
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: [:myself, :admin]) do
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 current_user && current_user.admin?
19
+ scopes << :admin_access if user.admin?
20
20
  end,
21
21
  user: {
22
22
  username: user.email,
@@ -19,7 +19,8 @@ module Authify
19
19
 
20
20
  has_many :admins, -> { where admin: true },
21
21
  through: :organization_memberships,
22
- class_name: 'Authify::API::Models::User'
22
+ class_name: 'Authify::API::Models::User',
23
+ source: 'user'
23
24
  end
24
25
  end
25
26
  end
@@ -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)
@@ -9,6 +9,7 @@ module Authify
9
9
  attribute :full_name
10
10
  attribute :admin
11
11
  attribute :created_at
12
+ attribute :verified
12
13
 
13
14
  has_many :apikeys
14
15
  has_many :groups
@@ -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 trusted_delegate
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 || trusted_delegate
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
- { id: new_user.id, email: new_user.email, jwt: jwt_token(new_user) }.to_json
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
@@ -2,7 +2,7 @@ module Authify
2
2
  module API
3
3
  VERSION = [
4
4
  0, # Major
5
- 1, # Minor
5
+ 2, # Minor
6
6
  0 # Patch
7
7
  ].join('.')
8
8
  end
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.1.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-02-16 00:00:00.000000000 Z
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