scim_rails 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +51 -0
- data/app/controllers/scim_rails/application_controller.rb +20 -4
- data/lib/generators/scim_rails/templates/initializer.rb +12 -0
- data/lib/scim_rails/config.rb +5 -0
- data/lib/scim_rails/encoder.rb +25 -0
- data/lib/scim_rails/version.rb +1 -1
- data/lib/scim_rails.rb +1 -0
- data/spec/controllers/scim_rails/scim_users_controller_spec.rb +1 -1
- data/spec/controllers/scim_rails/scim_users_request_spec.rb +23 -1
- data/spec/dummy/config/initializers/scim_rails_config.rb +3 -0
- data/spec/dummy/log/test.log +5180 -0
- data/spec/factories/company.rb +4 -1
- data/spec/lib/scim_rails/encoder_spec.rb +62 -0
- data/spec/support/scim_rails_config.rb +3 -0
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 69ddfe751f11e33adf91e96b99ccaaa7258bb1468ea8463511ae0b04eaeca4bf
|
4
|
+
data.tar.gz: ac7a95b8e8f7c5455bdf7b9a64d3b2c88c015974530077f80ab37a1e6751e468
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 05d83eb5dee1ecbfa49116f5d1f70e5f4e600393419055d93dfdff8e735e865ef2eeedf15b73c5899543f47168763b7f7cf13b897ba53e80332d7d813b427219
|
7
|
+
data.tar.gz: be1735ff8d1de4d79d5aa70c39b0cffdbc22f26d7adc105e5c03ec2fc61953d00a7ba363b0e59b57adf3aae3f32a880275eac00eaf5874adae789954ea22c3f1
|
data/README.md
CHANGED
@@ -78,6 +78,57 @@ When sending requests to the server the `Content-Type` should be set to `applica
|
|
78
78
|
|
79
79
|
All responses will be sent with a `Content-Type` of `application/scim+json`.
|
80
80
|
|
81
|
+
#### Authentication
|
82
|
+
|
83
|
+
This gem supports both basic and OAuth bearer authentication.
|
84
|
+
|
85
|
+
##### Basic Auth
|
86
|
+
###### Username
|
87
|
+
The config setting `basic_auth_model_searchable_attribute` is the model attribute used to authenticate as the `username`. It defaults to `:subdomain`.
|
88
|
+
|
89
|
+
Ensure it is unique to the model records.
|
90
|
+
|
91
|
+
###### Password
|
92
|
+
The config setting `basic_auth_model_authenticatable_attribute` is the model attribute used to authenticate as `password`. Defaults to `:api_token`.
|
93
|
+
|
94
|
+
Assuming the attribute is `:api_token`, generate the password using:
|
95
|
+
```ruby
|
96
|
+
token = ScimRails::Encoder.encode(company)
|
97
|
+
# use the token as password for requests
|
98
|
+
company.api_token = token # required
|
99
|
+
company.save! # don't forget to persist the company record
|
100
|
+
```
|
101
|
+
|
102
|
+
This is necessary irrespective of your authentication choice(s) - basic auth, oauth bearer or both.
|
103
|
+
|
104
|
+
###### Sample Request
|
105
|
+
|
106
|
+
```bash
|
107
|
+
$ curl -X GET 'http://username:password@localhost:3000/scim/v2/Users'
|
108
|
+
```
|
109
|
+
|
110
|
+
##### OAuth Bearer
|
111
|
+
|
112
|
+
###### Signing Algorithm
|
113
|
+
In the config settings, ensure you set `signing_algorithm` to a valid JWT signing algorithm, e.g "HS256". Defaults to `"none"` when not set.
|
114
|
+
|
115
|
+
###### Signing Secret
|
116
|
+
In the config settings, ensure you set `signing_secret` to a secret key that will be used to encode and decode tokens. Defaults to `nil` when not set.
|
117
|
+
|
118
|
+
If you have already generated the `api_token` in the "Basic Auth" section, then use that as your bearer token and ignore the steps below:
|
119
|
+
```ruby
|
120
|
+
token = ScimRails::Encoder.encode(company)
|
121
|
+
# use the token as bearer token for requests
|
122
|
+
company.api_token = token #required
|
123
|
+
company.save! # don't forget to persist the company record
|
124
|
+
```
|
125
|
+
|
126
|
+
##### Sample Request
|
127
|
+
|
128
|
+
```bash
|
129
|
+
$ curl -H 'Authorization: Bearer xxxxxxx.xxxxxx' -X GET 'http://localhost:3000/scim/v2/Users'
|
130
|
+
```
|
131
|
+
|
81
132
|
### List
|
82
133
|
|
83
134
|
##### All
|
@@ -9,14 +9,30 @@ module ScimRails
|
|
9
9
|
private
|
10
10
|
|
11
11
|
def authorize_request
|
12
|
-
|
12
|
+
send(authentication_strategy) do |searchable_attribute, authentication_attribute|
|
13
13
|
authorization = AuthorizeApiRequest.new(
|
14
|
-
searchable_attribute:
|
15
|
-
authentication_attribute:
|
14
|
+
searchable_attribute: searchable_attribute,
|
15
|
+
authentication_attribute: authentication_attribute
|
16
16
|
)
|
17
17
|
@company = authorization.company
|
18
18
|
end
|
19
|
-
raise
|
19
|
+
raise ScimRails::ExceptionHandler::InvalidCredentials if @company.blank?
|
20
|
+
end
|
21
|
+
|
22
|
+
def authentication_strategy
|
23
|
+
if request.headers["Authorization"]&.include?("Bearer")
|
24
|
+
:authenticate_with_oauth_bearer
|
25
|
+
else
|
26
|
+
:authenticate_with_http_basic
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def authenticate_with_oauth_bearer
|
31
|
+
authentication_attribute = request.headers["Authorization"].split(" ").last
|
32
|
+
payload = ScimRails::Encoder.decode(authentication_attribute).with_indifferent_access
|
33
|
+
searchable_attribute = payload[ScimRails.config.basic_auth_model_searchable_attribute]
|
34
|
+
|
35
|
+
yield searchable_attribute, authentication_attribute
|
20
36
|
end
|
21
37
|
end
|
22
38
|
end
|
@@ -22,6 +22,18 @@ ScimRails.configure do |config|
|
|
22
22
|
# or throws an error (returning 409 Conflict in accordance with SCIM spec)
|
23
23
|
config.scim_user_prevent_update_on_create = false
|
24
24
|
|
25
|
+
# Cryptographic algorithm used for signing the auth tokens.
|
26
|
+
# It supports all algorithms supported by the jwt gem.
|
27
|
+
# See https://github.com/jwt/ruby-jwt#algorithms-and-usage for supported algorithms
|
28
|
+
# It is "none" by default, hence generated tokens are unsigned
|
29
|
+
# The tokens do not need to be signed if you only need basic authentication.
|
30
|
+
# config.signing_algorithm = "HS256"
|
31
|
+
|
32
|
+
# Secret token used to sign authorization tokens
|
33
|
+
# It is `nil` by default, hence generated tokens are unsigned
|
34
|
+
# The tokens do not need to be signed if you only need basic authentication.
|
35
|
+
# config.signing_secret = SECRET_TOKEN
|
36
|
+
|
25
37
|
# Default sort order for pagination is by id. If you
|
26
38
|
# use non sequential ids for user records, uncomment
|
27
39
|
# the below line and configure a determinate order.
|
data/lib/scim_rails/config.rb
CHANGED
@@ -10,6 +10,8 @@ module ScimRails
|
|
10
10
|
end
|
11
11
|
|
12
12
|
class Config
|
13
|
+
ALGO_NONE = "none".freeze
|
14
|
+
|
13
15
|
attr_accessor \
|
14
16
|
:basic_auth_model,
|
15
17
|
:basic_auth_model_authenticatable_attribute,
|
@@ -21,6 +23,8 @@ module ScimRails
|
|
21
23
|
:scim_users_model,
|
22
24
|
:scim_users_scope,
|
23
25
|
:scim_user_prevent_update_on_create,
|
26
|
+
:signing_secret,
|
27
|
+
:signing_algorithm,
|
24
28
|
:user_attributes,
|
25
29
|
:user_deprovision_method,
|
26
30
|
:user_reprovision_method,
|
@@ -30,6 +34,7 @@ module ScimRails
|
|
30
34
|
@basic_auth_model = "Company"
|
31
35
|
@scim_users_list_order = :id
|
32
36
|
@scim_users_model = "User"
|
37
|
+
@signing_algorithm = ALGO_NONE
|
33
38
|
@user_schema = {}
|
34
39
|
@user_attributes = []
|
35
40
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "jwt"
|
2
|
+
|
3
|
+
module ScimRails
|
4
|
+
module Encoder
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def encode(company)
|
8
|
+
payload = {
|
9
|
+
iat: Time.current.to_i,
|
10
|
+
ScimRails.config.basic_auth_model_searchable_attribute =>
|
11
|
+
company.public_send(ScimRails.config.basic_auth_model_searchable_attribute)
|
12
|
+
}
|
13
|
+
|
14
|
+
JWT.encode(payload, ScimRails.config.signing_secret, ScimRails.config.signing_algorithm)
|
15
|
+
end
|
16
|
+
|
17
|
+
def decode(token)
|
18
|
+
verify = ScimRails.config.signing_algorithm != ScimRails::Config::ALGO_NONE
|
19
|
+
|
20
|
+
JWT.decode(token, ScimRails.config.signing_secret, verify, algorithm: ScimRails.config.signing_algorithm).first
|
21
|
+
rescue JWT::VerificationError, JWT::DecodeError
|
22
|
+
raise ScimRails::ExceptionHandler::InvalidCredentials
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/scim_rails/version.rb
CHANGED
data/lib/scim_rails.rb
CHANGED
@@ -537,7 +537,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :controller do
|
|
537
537
|
expect(user.archived?).to eq true
|
538
538
|
end
|
539
539
|
|
540
|
-
it "
|
540
|
+
it "successfully restores user" do
|
541
541
|
expect(company.users.count).to eq 1
|
542
542
|
user = company.users.first.tap(&:archive!)
|
543
543
|
expect(user.archived?).to eq true
|
@@ -5,7 +5,7 @@ RSpec.describe ScimRails::ScimUsersController, type: :request do
|
|
5
5
|
let(:credentials) { Base64::encode64("#{company.subdomain}:#{company.api_token}") }
|
6
6
|
let(:authorization) { "Basic #{credentials}" }
|
7
7
|
|
8
|
-
def post_request(content_type)
|
8
|
+
def post_request(content_type = "application/scim+json")
|
9
9
|
# params need to be transformed into a string to test if they are being parsed by Rack
|
10
10
|
|
11
11
|
post "/scim_rails/scim/v2/Users",
|
@@ -48,4 +48,26 @@ RSpec.describe ScimRails::ScimUsersController, type: :request do
|
|
48
48
|
expect(company.users.count).to eq 0
|
49
49
|
end
|
50
50
|
end
|
51
|
+
|
52
|
+
context "OAuth Bearer Authorization" do
|
53
|
+
context "with valid token" do
|
54
|
+
let(:authorization) { "Bearer #{company.api_token}" }
|
55
|
+
|
56
|
+
it "supports OAuth bearer authorization and succeeds" do
|
57
|
+
expect { post_request }.to change(company.users, :count).from(0).to(1)
|
58
|
+
|
59
|
+
expect(response.status).to eq 201
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "with invalid token" do
|
64
|
+
let(:authorization) { "Bearer #{SecureRandom.hex}" }
|
65
|
+
|
66
|
+
it "The request fails" do
|
67
|
+
expect { post_request }.not_to change(company.users, :count)
|
68
|
+
|
69
|
+
expect(response.status).to eq 401
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
51
73
|
end
|
@@ -7,6 +7,9 @@ ScimRails.configure do |config|
|
|
7
7
|
config.scim_users_scope = :users
|
8
8
|
config.scim_users_list_order = :id
|
9
9
|
|
10
|
+
config.signing_algorithm = "HS256"
|
11
|
+
config.signing_secret = "2d6806dd11c2fece2e81b8ca76dcb0062f5b08e28e3264e8ba1c44bbd3578b70"
|
12
|
+
|
10
13
|
config.user_deprovision_method = :archive!
|
11
14
|
config.user_reprovision_method = :unarchive!
|
12
15
|
|