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 +4 -4
- data/.rubocop.yml +5 -0
- data/Gemfile +3 -0
- data/README.md +154 -6
- data/Rakefile +20 -0
- data/authify-api.gemspec +4 -2
- data/config.ru +3 -2
- data/db/migrate/20170201220029_create_api_keys.rb +2 -2
- data/db/migrate/20170208021933_add_admin_to_user.rb +9 -0
- data/db/migrate/20170208022427_set_default_for_user_admin.rb +7 -0
- data/db/schema.rb +8 -6
- data/lib/authify/api.rb +6 -4
- data/lib/authify/api/controllers/apikey.rb +50 -0
- data/lib/authify/api/controllers/group.rb +34 -6
- data/lib/authify/api/controllers/identity.rb +49 -0
- data/lib/authify/api/controllers/organization.rb +57 -7
- data/lib/authify/api/controllers/user.rb +54 -15
- data/lib/authify/api/helpers/api_user.rb +16 -1
- data/lib/authify/api/helpers/jwt_encryption.rb +21 -8
- data/lib/authify/api/models/{api_key.rb → apikey.rb} +16 -2
- data/lib/authify/api/models/user.rb +2 -4
- data/lib/authify/api/serializers/{api_key_serializer.rb → apikey_serializer.rb} +7 -0
- data/lib/authify/api/serializers/group_serializer.rb +2 -0
- data/lib/authify/api/serializers/identity_serializer.rb +14 -0
- data/lib/authify/api/serializers/organization_serializer.rb +8 -0
- data/lib/authify/api/serializers/user_serializer.rb +4 -1
- data/lib/authify/api/services/api.rb +28 -33
- data/lib/authify/api/services/jwt_provider.rb +30 -8
- data/lib/authify/api/services/registration.rb +63 -0
- data/lib/authify/api/version.rb +2 -2
- metadata +46 -15
- data/lib/authify/api/controllers/api_key.rb +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a0f77e5a23fef6d16a82c095c2f76b9840dcf33f
|
4
|
+
data.tar.gz: c77e75b1605e0ea51c1bd589b47e9ca859735ba1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb9a4ed3c1c41e5e3ef207521fcc33d1fe50177eafdfb4037702ae0bf81a941b48d81b266230339a71cdf2e896616325d009f08f656f1a869fa4220588edee63
|
7
|
+
data.tar.gz: 0afea4d9d48418bae6f32d597f15c440259c49e84da4d4403dfdb41ca30e7d3b6d0102f7b5e01f98aba9f40f9cd332b8f1f3b9cd065c970a4f86b1274207e110
|
data/.rubocop.yml
CHANGED
@@ -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
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/
|
23
|
-
* `
|
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
|
-
* `/
|
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
|
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
|
data/authify-api.gemspec
CHANGED
@@ -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', '
|
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
|
-
'/'
|
9
|
-
'/jwt'
|
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
|
1
|
+
# Creates the apikeys table
|
2
2
|
class CreateApiKeys < ActiveRecord::Migration[5.0]
|
3
3
|
def change
|
4
|
-
create_table :
|
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
|
data/db/schema.rb
CHANGED
@@ -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:
|
13
|
+
ActiveRecord::Schema.define(version: 20170208022427) do
|
14
14
|
|
15
|
-
create_table "
|
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: "
|
22
|
-
t.index ["user_id"], name: "
|
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",
|
91
|
-
t.datetime "updated_at",
|
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
|
|
data/lib/authify/api.rb
CHANGED
@@ -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/
|
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/
|
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/
|
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
|