authify-api 0.0.6 → 0.1.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: 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