authify-api 0.1.0 → 0.2.0

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