authify-api 0.0.6 → 0.1.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: d0212938c798f261b1090fb3f324e1e092bd6d42
4
- data.tar.gz: 71144d630505d1f7d358868d358d5f408b1c1239
3
+ metadata.gz: a0f77e5a23fef6d16a82c095c2f76b9840dcf33f
4
+ data.tar.gz: c77e75b1605e0ea51c1bd589b47e9ca859735ba1
5
5
  SHA512:
6
- metadata.gz: 25f7cd520b354df503b74aecac21523b8333df8103970e1ba6ae18d8a2b2b9b8dae79d17c2d28408bac22b34fd2a86707cb21302d2431748b597593dacfb6410
7
- data.tar.gz: 28dddd5daba389f4d4b813fa1f8c83def144136552c307eac8d9ea9e2e92ccb9552da358a3ddbfe74a0c4461f04c53e21eb94133b28658f9ffba14eac16f4efb
6
+ metadata.gz: fb9a4ed3c1c41e5e3ef207521fcc33d1fe50177eafdfb4037702ae0bf81a941b48d81b266230339a71cdf2e896616325d009f08f656f1a869fa4220588edee63
7
+ data.tar.gz: 0afea4d9d48418bae6f32d597f15c440259c49e84da4d4403dfdb41ca30e7d3b6d0102f7b5e01f98aba9f40f9cd332b8f1f3b9cd065c970a4f86b1274207e110
@@ -13,10 +13,15 @@ Metrics/MethodLength:
13
13
  Metrics/CyclomaticComplexity:
14
14
  Max: 10
15
15
 
16
+ Metrics/PerceivedComplexity:
17
+ Max: 9
18
+
16
19
  BlockLength:
20
+ Max: 30
17
21
  Exclude:
18
22
  - '*.gemspec'
19
23
  - 'lib/authify/api/controllers/*.rb'
24
+ - Rakefile
20
25
 
21
26
  AllCops:
22
27
  Exclude:
data/Gemfile CHANGED
@@ -2,3 +2,6 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in authify-api.gemspec
4
4
  gemspec
5
+
6
+ gem 'sinja',
7
+ git: 'https://github.com/mwpastore/sinja.git', branch: 'master'
data/README.md CHANGED
@@ -19,12 +19,14 @@ The Authify API service consists of a database for storing:
19
19
 
20
20
  Nearly all API endpoints available via Authify implement the [{json:api}](http://jsonapi.org/) 1.0 specification. The exceptions are:
21
21
 
22
- * `GET /jwt/key` - Returns Content Type: `application/x-pem-file`. This endpoint returns the PEM-encoded public key ([ES512](https://tools.ietf.org/html/rfc7518#section-3.4) (ECDSA)) which should be used to verify the signature made by the Authify service.
23
- * `POST /jwt/token` - Returns (and only accepts) Content Type: `application/json`. This endpoint is used to obtain a [JWT token](https://en.wikipedia.org/wiki/JSON_Web_Token) for authentication when interacting with restricted endpoints (both on this service and for other integrated services). This endpoint expects a JSON Object with either the keys `access_key` and `secret_key` _OR_ `email` and `password`. There is no firm requirement to use either pair for any particular purpose, but for scenarios where the credentials may be stored on local disk (like an API command-line client), that the `access_key` and `secret_key` be used since those can easily be revoked if necessary. Upon successful authentication, the endpoint provides an JSON Object with the key `jwt` and a signed -- but not encrypted -- JWT. There should be nothing highly sensitive embedded in the JWT. The JWT defaults to expiring every 15 minutes.
22
+ * `GET /jwt/key` - Returns Content Type: `application/json`. This endpoint returns a JSON Object with the key `data` whose value is a PEM-encoded ECDSA public key, which should be used to verify the signature made by the Authify service.
23
+ * `GET /jwt/meta` - Returns Content Type: `application/json`. This endpoint returns a JSON Object with the keys `algorithm`, `issuer`, and `expiration` that describe the kind of JWTs produced by this service.
24
+ * `POST /jwt/token` - Returns (and only accepts) Content Type: `application/json`. This endpoint is used to obtain a [JWT](https://en.wikipedia.org/wiki/JSON_Web_Token). This endpoint expects a JSON Object with either the keys `access_key` and `secret_key` _OR_ `email` and `password`. There is no firm requirement to use either pair for any particular purpose, but for scenarios where the credentials may be stored, the `access_key` and `secret_key` may be used since those can easily be revoked if necessary. Upon successful authentication, the endpoint provides a JSON Object with the key `jwt` and a signed JWT. There should be nothing highly sensitive embedded in the JWT. The JWT defaults to expiring every 15 minutes.
25
+ * `POST /registration/signup` - Returns (and only accepts) Content Type: `application/json`. This endpoint is used to signup for an account with Authify. This endpoint expects a JSON Object, requiring the keys `email` and `password`, with `name` and `via` being optional. If `via` is provided, then it must be a JSON Object with the keys `provider` and `uid`, otherwise it will be ignored. The `via` key is used to add an alternate identity (meaning they logged-in through an integration, like Github). This endpoint returns a JSON Object with the keys `id`, `email`, and `jwt` on success.
24
26
 
25
27
  All other endpoints adhere to the {json:api} specification and can be found at the following base paths:
26
28
 
27
- * `/api-keys` - User API keys. Index is restricted. Should only really be useful for users manipulating their own keys.
29
+ * `/apikeys` - User API keys. Index is restricted. Should only really be useful for users manipulating their own keys.
28
30
  * `/groups` - Groups. Index is restricted. Most interactions with groups should be scoped via organizations.
29
31
  * `/identities` - Alternate User Identities. These are other services that the user can login via (web UI only).
30
32
  * `/organizations` - Organizations. These are high-level groupings of users and groups. Non-administrators should only be able to see limited amounts of information about organizations.
@@ -57,12 +59,158 @@ Or install it yourself as:
57
59
  The Authify API services supports the following configuration settings, managed via environment variables of the same name:
58
60
 
59
61
  * `AUTHIFY_DB_URL` - The URL used by [ActiveRecord](http://guides.rubyonrails.org/configuring.html#configuring-a-database) to connect to the database. Currently supports `mysql2://` or `sqlite3://` URLs, though any driver supported by ActiveRecord should work if the required gems are installed. Defaults to `mysql2://root@localhost:3306/authifydb`.
60
- * `AUTHIFY_PUBKEY_PATH` - The path on the filesystem to the PEM-encoded, public ECDSA key.
61
- * `AUTHIFY_PRIVKEY_PATH` - The path on the filesystem to the PEM-encoded, private ECDSA key. Currently, Authify only supports a [ECDSA](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm) key using a `secp521r1` curve and the [SHA-512](https://en.wikipedia.org/wiki/SHA-2) hashing algorithm.
62
- * `AUTHIFY_JWT_ISSUER` - The name of the issuer ([iss field](https://en.wikipedia.org/wiki/JSON_Web_Token#Standard_fields)) used when creating the JWT. This **must** match on any service that verifies the JWT (meaning any service relying on Authify for authentication).
62
+ * `AUTHIFY_PUBKEY_PATH` - The path on the filesystem to the PEM-encoded, public ECDSA key. Defaults to `~/.authify/ssl/public.pem`.
63
+ * `AUTHIFY_PRIVKEY_PATH` - The path on the filesystem to the PEM-encoded, private ECDSA key. Currently, Authify only supports an [ECDSA](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm) keys. Options include using a `secp521r1` curve and the [SHA-512](https://en.wikipedia.org/wiki/SHA-2) hashing algorithm (called `ES512`), a `secp384r1` curve and the SHA-384 hashing algorithm (called `ES384`), or a `prime256v1` curve and the SHA-256 hashing algorithm (called `ES256`). See `AUTHIFY_JWT_ALGORITHM` below for information on how to configure Authify's algorithm to match the public and private keys you provide. The keys you specify **must** match the ECDSA algortihm and curve used to create them.
64
+ * `AUTHIFY_JWT_ISSUER` - The name of the issuer ([iss field](https://en.wikipedia.org/wiki/JSON_Web_Token#Standard_fields)) used when creating the JWT. This **must** match on any service that verifies the JWT (meaning any service relying on Authify for authentication), and it **must** be the same for all services that integrate with Authify.
65
+ * `AUTHIFY_JWT_ALGORITHM` - The name of the [JWA](https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40) algorithm to use when loading keys and creating or verifying JWT signatures. Valid values are `ES256`, `ES384`, or `ES512`. Defaults to `ES512`. This **must** match the curve and algorithm used to produce the public and private keys found at `AUTHIFY_PUBKEY_PATH` and `AUTHIFY_PRIVKEY_PATH`, respectively. Note that the curves `prime256v1` (also called NIST P-256) used by `ES256` and `secp384r1` (also called NIST P-384) used by `ES384`, while offering a wider range of compatible SSL libraries, are described as unsafe on [SafeCurves](https://safecurves.cr.yp.to/) for several reasons described there.
66
+ * `AUTHIFY_JWT_EXPIRATION` - How long should a JWT be valid (in minutes). Defaults to 15. Too small of a value will mean a lot more requests to the API; too high increases the possibility of viable keys being captured.
63
67
 
64
68
  ## Usage and Authentication Workflow
65
69
 
70
+ ### Generating an SSL Certificate
71
+
72
+ Here is an example in Ruby for generating an SSL cert for use with the Authify API server:
73
+
74
+ ```ruby
75
+ require 'openssl'
76
+ # Using ES512. For others, switch 'secp512r1' to the desired curve
77
+ secret_key = OpenSSL::PKey::EC.new('secp521r1')
78
+ secret_key.generate_key
79
+ # write out the private key to a file...
80
+ File.write(File.expand_path('/path/to/keys/private.pem'), secret_key.to_pem)
81
+ public_key = secret_key
82
+ public_key.private_key = nil
83
+ # write out the public key to a file...
84
+ File.write(File.expand_path('/path/to/keys/public.pem'), private_key.to_pem)
85
+ ```
86
+
87
+ Using the OpenSSL CLI tool:
88
+
89
+ ```shell
90
+ # Private key
91
+ openssl ecparam -name secp521r1 -genkey -out /path/to/keys/private.pem
92
+ # Public key
93
+ openssl ec -in /path/to/keys/private.pem -pubout -out /path/to/keys/public.pem
94
+ ```
95
+
96
+ ### Authenticating for API clients
97
+
98
+ We'll show how to interact with the API using `curl` as an example, and we'll assume the server is running at `auth.mycompany.com`.
99
+
100
+ #### Register a new user
101
+
102
+ ```shell
103
+ curl \
104
+ -H 'Content-Type: application/json' \
105
+ -H 'Accept: application/json' \
106
+ --data \
107
+ '{
108
+ "name": "Some User",
109
+ "email": "someuser@mycompany.com",
110
+ "password": "b@d!dea",
111
+ "via": {
112
+ "provider": "github",
113
+ "uid": "1234567"
114
+ }
115
+ }' \
116
+ https://auth.mycompany.com/registration/signup
117
+ ```
118
+
119
+ This will return JSON similar to the following:
120
+
121
+ ```javascript
122
+ {
123
+ "id": 172,
124
+ "email": "someuser@mycompany.com",
125
+ "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJleHAiOjE0ODY0ODcyODcsImlhdCI6MTQ4NjQ4MzY4NywiaXNzIjoiTXkgQXdlc29tZSBDb21wYW55IEluYy4iLCJzY29wZXMiOlsidXNlcl9hY2Nlc3MiXSwidXNlciI6eyJ1c2VybmFtZSI6ImZvb0BiYXIuY29tIiwidWlkIjoyLCJvcmdhbml6YXRpb25zIjpbXSwiZ3JvdXBzIjpbXX19.AWfPpKX9mP03Djz3-LMneJdEVsXQm_4GOPVCdkfiiBeIR4pVLKTVrNoNdlNgSEkZEeUw1RPsVxpAR7wDgB4cNcYiAP3fNaD8OPyWfOQAV0lTvDUSH3YU39cZAVwvbX9HleOHBLrFGBbui5wSvfi7WZZlH808psiuUAVhBOe7mfrNiHGB"
126
+ }
127
+ ```
128
+
129
+ You'll need the JWT (found at key `jwt`) for the next step.
130
+
131
+ #### Create an API key set
132
+
133
+ ```shell
134
+ curl \
135
+ -H 'Content-Type: application/vnd.api+json' \
136
+ -H 'Accept: application/vnd.api+json' \
137
+ -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJleHAiOjE0ODY0ODcyODcsImlhdCI6MTQ4NjQ4MzY4NywiaXNzIjoiTXkgQXdlc29tZSBDb21wYW55IEluYy4iLCJzY29wZXMiOlsidXNlcl9hY2Nlc3MiXSwidXNlciI6eyJ1c2VybmFtZSI6ImZvb0BiYXIuY29tIiwidWlkIjoyLCJvcmdhbml6YXRpb25zIjpbXSwiZ3JvdXBzIjpbXX19.AWfPpKX9mP03Djz3-LMneJdEVsXQm_4GOPVCdkfiiBeIR4pVLKTVrNoNdlNgSEkZEeUw1RPsVxpAR7wDgB4cNcYiAP3fNaD8OPyWfOQAV0lTvDUSH3YU39cZAVwvbX9HleOHBLrFGBbui5wSvfi7WZZlH808psiuUAVhBOe7mfrNiHGB" \
138
+ --data \
139
+ '{
140
+ "data":
141
+ {
142
+ "type": "apikeys"
143
+ }
144
+ }' \
145
+ https://auth.mycompany.com/apikeys
146
+ ```
147
+
148
+ This endpoint (as can be seen from the `Accept` and `Content-Type` headers) speaks only {json:api} and will return something like this with an HTTP 201:
149
+
150
+ ```javascript
151
+ {
152
+ "data": {
153
+ "type": "apikeys",
154
+ "id": "197",
155
+ "attributes": {
156
+ "access-key": "4bb651af1754b2dff5b9",
157
+ "secret-key": "a3f1ee5085dad87d53ce04a1857a2677c7ffa136c506e8174fef6fa1c962e46f",
158
+ "created-at": "2017-02-13 22:50:44 UTC"
159
+ },
160
+ "links": {
161
+ "self": "/apikeys/197"
162
+ },
163
+ "relationships": {
164
+ "user": {
165
+ "links": {
166
+ "self": "/apikeys/197/relationships/user",
167
+ "related": "/apikeys/197/user"
168
+ }
169
+ }
170
+ }
171
+ },
172
+ "jsonapi": {
173
+ "version": "1.0"
174
+ },
175
+ "included": [
176
+
177
+ ]
178
+ }
179
+ ```
180
+
181
+ Note that **it will not be possible to retrieve the `secret-key` attribute in plaintext again**, so store the results in a safe place.
182
+
183
+ #### Obtain a JWT
184
+
185
+ ```shell
186
+ curl \
187
+ -H 'Accept: application/json' \
188
+ -H 'Content-Type: application/json' \
189
+ --data \
190
+ '{
191
+ "access_key": "5f4abd1c6423ef02d1ec42e1cddaf5f8",
192
+ "secret_key": "fb97aa7d4e48f3e4bbb2930161a423fa8308393426c3612940da03f22cf36879"
193
+ }' \
194
+ https://auth.mycompany.com/jwt/token
195
+ ```
196
+
197
+ Note that you can also use either the underscored format for logging in with API keys (`access_key` and `secret_key`) or the dashed version provided in the {json:api} response before (`access-key` and `secret-key`). For all other endpoints (those adhering to the {json:api} spec) the dashed approach is required.
198
+
199
+ The server will return something like:
200
+
201
+ ```javascript
202
+ {"jwt":"eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJleHAiOjE0ODY0ODcyODcsImlhdCI6MTQ4NjQ4MzY4NywiaXNzIjoiTXkgQXdlc29tZSBDb21wYW55IEluYy4iLCJzY29wZXMiOlsidXNlcl9hY2Nlc3MiXSwidXNlciI6eyJ1c2VybmFtZSI6ImZvb0BiYXIuY29tIiwidWlkIjoyLCJvcmdhbml6YXRpb25zIjpbXSwiZ3JvdXBzIjpbXX19.AWfPpKX9mP03Djz3-LMneJdEVsXQm_4GOPVCdkfiiBeIR4pVLKTVrNoNdlNgSEkZEeUw1RPsVxpAR7wDgB4cNcYiAP3fNaD8OPyWfOQAV0lTvDUSH3YU39cZAVwvbX9HleOHBLrFGBbui5wSvfi7WZZlH808psiuUAVhBOe7mfrNiHGB"}
203
+ ```
204
+
205
+ #### Use the JWT to Access a Protected Resource
206
+
207
+ ```shell
208
+ curl \
209
+ -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJleHAiOjE0ODY0ODcyODcsImlhdCI6MTQ4NjQ4MzY4NywiaXNzIjoiTXkgQXdlc29tZSBDb21wYW55IEluYy4iLCJzY29wZXMiOlsidXNlcl9hY2Nlc3MiXSwidXNlciI6eyJ1c2VybmFtZSI6ImZvb0BiYXIuY29tIiwidWlkIjoyLCJvcmdhbml6YXRpb25zIjpbXSwiZ3JvdXBzIjpbXX19.AWfPpKX9mP03Djz3-LMneJdEVsXQm_4GOPVCdkfiiBeIR4pVLKTVrNoNdlNgSEkZEeUw1RPsVxpAR7wDgB4cNcYiAP3fNaD8OPyWfOQAV0lTvDUSH3YU39cZAVwvbX9HleOHBLrFGBbui5wSvfi7WZZlH808psiuUAVhBOe7mfrNiHGB" \
210
+ -H 'Accept: application/vnd.api+json' \
211
+ https://auth.mycompany.com/organizations
212
+ ```
213
+
66
214
  ## Contributing
67
215
 
68
216
  Bug reports and pull requests are welcome on GitHub at https://github.com/knuedge/authify-api.
data/Rakefile CHANGED
@@ -35,4 +35,24 @@ namespace :delegate do
35
35
  exit 1
36
36
  end
37
37
  end
38
+
39
+ desc 'List Trusted Delegates'
40
+ task :list do
41
+ require 'authify/api'
42
+ Authify::API::Models::TrustedDelegate.all.each do |td|
43
+ p(name: td.name, access: td.access_key)
44
+ end
45
+ end
46
+
47
+ desc 'Delete a Trusted Delegate'
48
+ task :remove, [:name] do |_t, args|
49
+ require 'authify/api'
50
+ td = Authify::API::Models::TrustedDelegate.find_by_name(args[:name])
51
+ if td && td.destroy
52
+ puts 'Trusted Delegate destroyed'
53
+ else
54
+ puts 'Failed to destroy Trusted Delegate'
55
+ exit 1
56
+ end
57
+ end
38
58
  end
@@ -25,13 +25,15 @@ Gem::Specification.new do |spec|
25
25
  spec.add_runtime_dependency 'authify-core'
26
26
  spec.add_runtime_dependency 'authify-middleware'
27
27
  spec.add_runtime_dependency 'connection_pool', '~> 2.2'
28
- spec.add_runtime_dependency 'sinatra', '~> 1.4'
28
+ spec.add_runtime_dependency 'sinatra', '>= 2.0.0.beta2', '< 3'
29
+ spec.add_runtime_dependency 'sinatra-contrib', '>= 2.0.0.beta2', '< 3'
29
30
  spec.add_runtime_dependency 'sinatra-activerecord', '~> 2.0'
30
31
  spec.add_runtime_dependency 'moneta', '~> 0.8'
31
32
  spec.add_runtime_dependency 'mysql2', '~> 0.4'
32
33
  spec.add_runtime_dependency 'sqlite3', '~> 1.3'
34
+ spec.add_runtime_dependency 'json', '~> 2.0'
33
35
  spec.add_runtime_dependency 'jsonapi-serializers', '~> 0.16'
34
- spec.add_runtime_dependency 'sinja', '~> 1.2'
36
+ # spec.add_runtime_dependency 'sinja', '~> 1.2', '>= 1.2.4'
35
37
  spec.add_runtime_dependency 'puma', '~> 3.7'
36
38
 
37
39
  spec.add_development_dependency 'bundler', '~> 1.12'
data/config.ru CHANGED
@@ -5,5 +5,6 @@ require 'authify/api'
5
5
  use Rack::ShowExceptions
6
6
 
7
7
  run Rack::URLMap.new \
8
- '/' => Authify::API::Services::API.new,
9
- '/jwt' => Authify::API::Services::JWTProvider.new
8
+ '/' => Authify::API::Services::API.new,
9
+ '/jwt' => Authify::API::Services::JWTProvider.new,
10
+ '/registration' => Authify::API::Services::Registration.new
@@ -1,7 +1,7 @@
1
- # Creates the api_keys table
1
+ # Creates the apikeys table
2
2
  class CreateApiKeys < ActiveRecord::Migration[5.0]
3
3
  def change
4
- create_table :api_keys do |t|
4
+ create_table :apikeys do |t|
5
5
  t.references :user, index: true
6
6
  t.string :access_key, index: true
7
7
  t.text :secret_key_digest
@@ -0,0 +1,9 @@
1
+ # Make it so we can have global admin users
2
+ class AddAdminToUser < ActiveRecord::Migration[5.0]
3
+ def change
4
+ change_table :users do |t|
5
+ t.boolean :admin
6
+ t.index :admin
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ # Sets a default for Users to not be admins
2
+ class SetDefaultForUserAdmin < ActiveRecord::Migration[5.0]
3
+ def change
4
+ change_column_null :users, :admin, false
5
+ change_column_default :users, :admin, false
6
+ end
7
+ end
@@ -10,16 +10,16 @@
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: 20170204001405) do
13
+ ActiveRecord::Schema.define(version: 20170208022427) do
14
14
 
15
- create_table "api_keys", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
15
+ create_table "apikeys", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
16
16
  t.integer "user_id"
17
17
  t.string "access_key"
18
18
  t.text "secret_key_digest", limit: 65535
19
19
  t.datetime "created_at", null: false
20
20
  t.datetime "updated_at", null: false
21
- t.index ["access_key"], name: "index_api_keys_on_access_key", using: :btree
22
- t.index ["user_id"], name: "index_api_keys_on_user_id", using: :btree
21
+ t.index ["access_key"], name: "index_apikeys_on_access_key", using: :btree
22
+ t.index ["user_id"], name: "index_apikeys_on_user_id", using: :btree
23
23
  end
24
24
 
25
25
  create_table "groups", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
@@ -87,8 +87,10 @@ ActiveRecord::Schema.define(version: 20170204001405) do
87
87
  t.string "email"
88
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
90
+ t.datetime "created_at", null: false
91
+ t.datetime "updated_at", null: false
92
+ t.boolean "admin", default: false, null: false
93
+ t.index ["admin"], name: "index_users_on_admin", using: :btree
92
94
  t.index ["email"], name: "index_users_on_email", using: :btree
93
95
  end
94
96
 
@@ -18,7 +18,6 @@ module Authify
18
18
  db: {
19
19
  url: ENV['AUTHIFY_DB_URL'] || 'mysql2://root@localhost:3306/authifydb'
20
20
  },
21
- session_secret: ENV['AUTHIFY_SESSION_SECRET'] || '1q2w3e4r5t6y7u8i9o0pazsxdcfvgbhnjmkl10zm',
22
21
  redis: {
23
22
  host: ENV['AUTHIFY_REDIS_HOST'] || 'localhost',
24
23
  port: ENV['AUTHIFY_REDIS_PORT'] || '6379'
@@ -29,15 +28,17 @@ end
29
28
 
30
29
  require 'authify/api/version'
31
30
  require 'authify/api/jsonapi_utils'
32
- require 'authify/api/controllers/api_key'
31
+ require 'authify/api/controllers/apikey'
33
32
  require 'authify/api/controllers/group'
33
+ require 'authify/api/controllers/identity'
34
34
  require 'authify/api/controllers/organization'
35
35
  require 'authify/api/controllers/user'
36
- require 'authify/api/serializers/api_key_serializer'
36
+ require 'authify/api/serializers/apikey_serializer'
37
37
  require 'authify/api/serializers/group_serializer'
38
+ require 'authify/api/serializers/identity_serializer'
38
39
  require 'authify/api/serializers/user_serializer'
39
40
  require 'authify/api/serializers/organization_serializer'
40
- require 'authify/api/models/api_key'
41
+ require 'authify/api/models/apikey'
41
42
  require 'authify/api/models/group'
42
43
  require 'authify/api/models/identity'
43
44
  require 'authify/api/models/organization'
@@ -49,3 +50,4 @@ require 'authify/api/helpers/api_user'
49
50
  require 'authify/api/service'
50
51
  require 'authify/api/services/api'
51
52
  require 'authify/api/services/jwt_provider'
53
+ require 'authify/api/services/registration'
@@ -0,0 +1,50 @@
1
+ module Authify
2
+ module API
3
+ module Controllers
4
+ APIKey = proc do
5
+ helpers do
6
+ def find(id)
7
+ Models::APIKey.find(id.to_i)
8
+ end
9
+
10
+ def role
11
+ Array(super).tap do |a|
12
+ a << :myself if current_user && current_user.apikeys.include?(resource)
13
+ end.uniq
14
+ end
15
+ end
16
+
17
+ index(roles: [:admin]) do
18
+ Models::APIKey.all
19
+ end
20
+
21
+ show(roles: [:myself, :admin]) do
22
+ last_modified resource.updated_at
23
+ next resource, exclude: [:secret_key]
24
+ end
25
+
26
+ create(roles: [:user]) do |_attributes|
27
+ key = Models::APIKey.new
28
+ key.populate!
29
+ current_user.apikeys << key
30
+ current_user.save
31
+ next key.id, key
32
+ end
33
+
34
+ destroy(roles: [:myself, :admin]) do
35
+ resource.destroy
36
+ end
37
+
38
+ show_many do |ids|
39
+ Models::APIKey.find(ids)
40
+ end
41
+
42
+ has_one :user do
43
+ pluck(roles: [:myself, :admin]) do
44
+ resource.user
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -6,22 +6,31 @@ module Authify
6
6
  def find(id)
7
7
  Models::Group.find(id.to_i)
8
8
  end
9
+
10
+ def role
11
+ Array(super).tap do |a|
12
+ a << :owner if current_user && current_user.admin_for?(resource.organization)
13
+ a << :member if resource && resource.users.include?(current_user)
14
+ end.uniq
15
+ end
9
16
  end
10
17
 
11
- index do
18
+ index(roles: [:admin]) do
12
19
  Models::Group.all
13
20
  end
14
21
 
15
- show do
22
+ show(roles: [:admin, :owner]) do
16
23
  last_modified resource.updated_at
17
24
  next resource
18
25
  end
19
26
 
20
- create do |attrs|
21
- Models::Group.new(attrs)
27
+ create(roles: [:admin]) do |attrs|
28
+ g = Models::Group.new(attrs)
29
+ g.save
30
+ next g
22
31
  end
23
32
 
24
- destroy do
33
+ destroy(roles: [:admin, :owner]) do
25
34
  resource.destroy
26
35
  end
27
36
 
@@ -30,9 +39,28 @@ module Authify
30
39
  end
31
40
 
32
41
  has_many :users do
33
- fetch do
42
+ fetch(roles: [:admin, :owner]) do
34
43
  resource.users
35
44
  end
45
+
46
+ replace(roles: [:admin, :owner]) do |rios|
47
+ refs = rios.map { |attrs| Models::User.find(attrs) }
48
+ resource.users = refs
49
+ resource.save
50
+ end
51
+
52
+ merge(roles: [:admin, :owner]) do |rios|
53
+ refs = rios.map { |attrs| Models::User.find(attrs) }
54
+ resource.users << refs
55
+ resource.save
56
+ end
57
+
58
+ subtract(roles: [:admin, :owner]) do |rios|
59
+ refs = rios.map { |attrs| Models::User.find(attrs) }
60
+ # This only removes the linkage, not the actual users
61
+ resource.users.delete(refs)
62
+ resource.save
63
+ end
36
64
  end
37
65
  end
38
66
  end