doorkeeper 5.3.2 → 5.5.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of doorkeeper might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +106 -2
- data/README.md +6 -4
- data/app/controllers/doorkeeper/applications_controller.rb +4 -4
- data/app/controllers/doorkeeper/authorizations_controller.rb +32 -12
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +2 -2
- data/app/controllers/doorkeeper/tokens_controller.rb +60 -20
- data/app/views/doorkeeper/applications/_form.html.erb +1 -1
- data/app/views/doorkeeper/applications/show.html.erb +19 -2
- data/config/locales/en.yml +3 -2
- data/lib/doorkeeper.rb +107 -79
- data/lib/doorkeeper/config.rb +140 -94
- data/lib/doorkeeper/config/abstract_builder.rb +28 -0
- data/lib/doorkeeper/config/option.rb +26 -14
- data/lib/doorkeeper/config/validations.rb +53 -0
- data/lib/doorkeeper/engine.rb +1 -1
- data/lib/doorkeeper/grant_flow.rb +43 -0
- data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
- data/lib/doorkeeper/grant_flow/flow.rb +34 -0
- data/lib/doorkeeper/grant_flow/registry.rb +50 -0
- data/lib/doorkeeper/grape/helpers.rb +1 -1
- data/lib/doorkeeper/helpers/controller.rb +6 -4
- data/lib/doorkeeper/models/access_grant_mixin.rb +20 -16
- data/lib/doorkeeper/models/access_token_mixin.rb +110 -47
- data/lib/doorkeeper/models/application_mixin.rb +5 -4
- data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
- data/lib/doorkeeper/models/concerns/revocable.rb +1 -1
- data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
- data/lib/doorkeeper/models/concerns/secret_storable.rb +1 -3
- data/lib/doorkeeper/oauth/authorization/code.rb +15 -6
- data/lib/doorkeeper/oauth/authorization/context.rb +5 -5
- data/lib/doorkeeper/oauth/authorization/token.rb +14 -16
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +4 -4
- data/lib/doorkeeper/oauth/authorization_code_request.rb +17 -14
- data/lib/doorkeeper/oauth/base_request.rb +12 -20
- data/lib/doorkeeper/oauth/client.rb +1 -1
- data/lib/doorkeeper/oauth/client/credentials.rb +2 -4
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +27 -8
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +4 -2
- data/lib/doorkeeper/oauth/client_credentials/validator.rb +4 -2
- data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -7
- data/lib/doorkeeper/oauth/code_request.rb +3 -3
- data/lib/doorkeeper/oauth/code_response.rb +28 -14
- data/lib/doorkeeper/oauth/error_response.rb +6 -7
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +2 -8
- data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
- data/lib/doorkeeper/oauth/invalid_token_response.rb +2 -2
- data/lib/doorkeeper/oauth/password_access_token_request.rb +24 -7
- data/lib/doorkeeper/oauth/pre_authorization.rb +41 -31
- data/lib/doorkeeper/oauth/refresh_token_request.rb +31 -22
- data/lib/doorkeeper/oauth/token.rb +5 -6
- data/lib/doorkeeper/oauth/token_introspection.rb +4 -8
- data/lib/doorkeeper/oauth/token_request.rb +3 -3
- data/lib/doorkeeper/oauth/token_response.rb +1 -1
- data/lib/doorkeeper/orm/active_record.rb +10 -2
- data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +8 -3
- data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +7 -3
- data/lib/doorkeeper/orm/active_record/mixins/application.rb +20 -16
- data/lib/doorkeeper/rails/routes.rb +14 -18
- data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
- data/lib/doorkeeper/rails/routes/mapper.rb +2 -2
- data/lib/doorkeeper/rails/routes/registry.rb +45 -0
- data/lib/doorkeeper/request.rb +49 -12
- data/lib/doorkeeper/request/refresh_token.rb +2 -1
- data/lib/doorkeeper/request/strategy.rb +2 -2
- data/lib/doorkeeper/server.rb +4 -4
- data/lib/doorkeeper/stale_records_cleaner.rb +4 -4
- data/lib/doorkeeper/version.rb +3 -3
- data/lib/generators/doorkeeper/confidential_applications_generator.rb +1 -1
- data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
- data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +2 -0
- data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +2 -0
- data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +2 -0
- data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +48 -10
- data/lib/generators/doorkeeper/templates/migration.rb.erb +14 -5
- metadata +21 -299
- data/Appraisals +0 -40
- data/CODE_OF_CONDUCT.md +0 -46
- data/CONTRIBUTING.md +0 -49
- data/Dangerfile +0 -67
- data/Dockerfile +0 -29
- data/Gemfile +0 -25
- data/NEWS.md +0 -1
- data/RELEASING.md +0 -11
- data/Rakefile +0 -28
- data/SECURITY.md +0 -15
- data/UPGRADE.md +0 -2
- data/bin/console +0 -16
- data/doorkeeper.gemspec +0 -42
- data/gemfiles/rails_5_0.gemfile +0 -18
- data/gemfiles/rails_5_1.gemfile +0 -18
- data/gemfiles/rails_5_2.gemfile +0 -18
- data/gemfiles/rails_6_0.gemfile +0 -18
- data/gemfiles/rails_master.gemfile +0 -18
- data/spec/controllers/application_metal_controller_spec.rb +0 -64
- data/spec/controllers/applications_controller_spec.rb +0 -274
- data/spec/controllers/authorizations_controller_spec.rb +0 -608
- data/spec/controllers/protected_resources_controller_spec.rb +0 -361
- data/spec/controllers/token_info_controller_spec.rb +0 -50
- data/spec/controllers/tokens_controller_spec.rb +0 -498
- data/spec/dummy/Rakefile +0 -9
- data/spec/dummy/app/assets/config/manifest.js +0 -2
- data/spec/dummy/app/controllers/application_controller.rb +0 -5
- data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -9
- data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -14
- data/spec/dummy/app/controllers/home_controller.rb +0 -18
- data/spec/dummy/app/controllers/metal_controller.rb +0 -13
- data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -13
- data/spec/dummy/app/helpers/application_helper.rb +0 -7
- data/spec/dummy/app/models/user.rb +0 -7
- data/spec/dummy/app/views/home/index.html.erb +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +0 -14
- data/spec/dummy/config.ru +0 -6
- data/spec/dummy/config/application.rb +0 -49
- data/spec/dummy/config/boot.rb +0 -7
- data/spec/dummy/config/database.yml +0 -15
- data/spec/dummy/config/environment.rb +0 -5
- data/spec/dummy/config/environments/development.rb +0 -31
- data/spec/dummy/config/environments/production.rb +0 -64
- data/spec/dummy/config/environments/test.rb +0 -45
- data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -9
- data/spec/dummy/config/initializers/doorkeeper.rb +0 -166
- data/spec/dummy/config/initializers/secret_token.rb +0 -10
- data/spec/dummy/config/initializers/session_store.rb +0 -10
- data/spec/dummy/config/initializers/wrap_parameters.rb +0 -16
- data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
- data/spec/dummy/config/routes.rb +0 -13
- data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -11
- data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -7
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -69
- data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -9
- data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -13
- data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +0 -8
- data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +0 -13
- data/spec/dummy/db/schema.rb +0 -68
- data/spec/dummy/public/404.html +0 -26
- data/spec/dummy/public/422.html +0 -26
- data/spec/dummy/public/500.html +0 -26
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +0 -9
- data/spec/factories.rb +0 -30
- data/spec/generators/application_owner_generator_spec.rb +0 -28
- data/spec/generators/confidential_applications_generator_spec.rb +0 -29
- data/spec/generators/install_generator_spec.rb +0 -36
- data/spec/generators/migration_generator_spec.rb +0 -28
- data/spec/generators/pkce_generator_spec.rb +0 -28
- data/spec/generators/previous_refresh_token_generator_spec.rb +0 -44
- data/spec/generators/templates/routes.rb +0 -4
- data/spec/generators/views_generator_spec.rb +0 -29
- data/spec/grape/grape_integration_spec.rb +0 -137
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -26
- data/spec/lib/config_spec.rb +0 -809
- data/spec/lib/doorkeeper_spec.rb +0 -27
- data/spec/lib/models/expirable_spec.rb +0 -61
- data/spec/lib/models/reusable_spec.rb +0 -40
- data/spec/lib/models/revocable_spec.rb +0 -59
- data/spec/lib/models/scopes_spec.rb +0 -53
- data/spec/lib/models/secret_storable_spec.rb +0 -135
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -39
- data/spec/lib/oauth/authorization_code_request_spec.rb +0 -170
- data/spec/lib/oauth/base_request_spec.rb +0 -224
- data/spec/lib/oauth/base_response_spec.rb +0 -45
- data/spec/lib/oauth/client/credentials_spec.rb +0 -90
- data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -134
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -112
- data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -59
- data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -27
- data/spec/lib/oauth/client_credentials_request_spec.rb +0 -107
- data/spec/lib/oauth/client_spec.rb +0 -38
- data/spec/lib/oauth/code_request_spec.rb +0 -46
- data/spec/lib/oauth/code_response_spec.rb +0 -32
- data/spec/lib/oauth/error_response_spec.rb +0 -64
- data/spec/lib/oauth/error_spec.rb +0 -21
- data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -20
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -110
- data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -21
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -262
- data/spec/lib/oauth/invalid_request_response_spec.rb +0 -73
- data/spec/lib/oauth/invalid_token_response_spec.rb +0 -53
- data/spec/lib/oauth/password_access_token_request_spec.rb +0 -190
- data/spec/lib/oauth/pre_authorization_spec.rb +0 -223
- data/spec/lib/oauth/refresh_token_request_spec.rb +0 -177
- data/spec/lib/oauth/scopes_spec.rb +0 -146
- data/spec/lib/oauth/token_request_spec.rb +0 -157
- data/spec/lib/oauth/token_response_spec.rb +0 -84
- data/spec/lib/oauth/token_spec.rb +0 -156
- data/spec/lib/request/strategy_spec.rb +0 -54
- data/spec/lib/secret_storing/base_spec.rb +0 -60
- data/spec/lib/secret_storing/bcrypt_spec.rb +0 -49
- data/spec/lib/secret_storing/plain_spec.rb +0 -44
- data/spec/lib/secret_storing/sha256_hash_spec.rb +0 -48
- data/spec/lib/server_spec.rb +0 -49
- data/spec/lib/stale_records_cleaner_spec.rb +0 -89
- data/spec/models/doorkeeper/access_grant_spec.rb +0 -161
- data/spec/models/doorkeeper/access_token_spec.rb +0 -622
- data/spec/models/doorkeeper/application_spec.rb +0 -482
- data/spec/requests/applications/applications_request_spec.rb +0 -259
- data/spec/requests/applications/authorized_applications_spec.rb +0 -32
- data/spec/requests/endpoints/authorization_spec.rb +0 -91
- data/spec/requests/endpoints/token_spec.rb +0 -75
- data/spec/requests/flows/authorization_code_errors_spec.rb +0 -79
- data/spec/requests/flows/authorization_code_spec.rb +0 -525
- data/spec/requests/flows/client_credentials_spec.rb +0 -166
- data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -46
- data/spec/requests/flows/implicit_grant_spec.rb +0 -91
- data/spec/requests/flows/password_spec.rb +0 -316
- data/spec/requests/flows/refresh_token_spec.rb +0 -233
- data/spec/requests/flows/revoke_token_spec.rb +0 -157
- data/spec/requests/flows/skip_authorization_spec.rb +0 -66
- data/spec/requests/protected_resources/metal_spec.rb +0 -16
- data/spec/requests/protected_resources/private_api_spec.rb +0 -83
- data/spec/routing/custom_controller_routes_spec.rb +0 -133
- data/spec/routing/default_routes_spec.rb +0 -41
- data/spec/routing/scoped_routes_spec.rb +0 -47
- data/spec/spec_helper.rb +0 -54
- data/spec/spec_helper_integration.rb +0 -4
- data/spec/support/dependencies/factory_bot.rb +0 -4
- data/spec/support/doorkeeper_rspec.rb +0 -22
- data/spec/support/helpers/access_token_request_helper.rb +0 -13
- data/spec/support/helpers/authorization_request_helper.rb +0 -43
- data/spec/support/helpers/config_helper.rb +0 -11
- data/spec/support/helpers/model_helper.rb +0 -78
- data/spec/support/helpers/request_spec_helper.rb +0 -110
- data/spec/support/helpers/url_helper.rb +0 -62
- data/spec/support/orm/active_record.rb +0 -5
- data/spec/support/shared/controllers_shared_context.rb +0 -133
- data/spec/support/shared/hashing_shared_context.rb +0 -36
- data/spec/support/shared/models_shared_examples.rb +0 -54
- data/spec/validators/redirect_uri_validator_spec.rb +0 -183
- data/spec/version/version_spec.rb +0 -17
@@ -1,79 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
feature "Authorization Code Flow Errors" do
|
6
|
-
let(:client_params) { {} }
|
7
|
-
background do
|
8
|
-
default_scopes_exist :default
|
9
|
-
config_is_set(:authenticate_resource_owner) { User.first || redirect_to("/sign_in") }
|
10
|
-
client_exists client_params
|
11
|
-
create_resource_owner
|
12
|
-
sign_in
|
13
|
-
end
|
14
|
-
|
15
|
-
after do
|
16
|
-
access_grant_should_not_exist
|
17
|
-
end
|
18
|
-
|
19
|
-
context "with a client trying to xss resource owner" do
|
20
|
-
let(:client_name) { "<div id='xss'>XSS</div>" }
|
21
|
-
let(:client_params) { { name: client_name } }
|
22
|
-
scenario "resource owner visit authorization endpoint" do
|
23
|
-
visit authorization_endpoint_url(client: @client)
|
24
|
-
expect(page).not_to have_css("#xss")
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
context "when access was denied" do
|
29
|
-
scenario "redirects with error" do
|
30
|
-
visit authorization_endpoint_url(client: @client)
|
31
|
-
click_on "Deny"
|
32
|
-
|
33
|
-
i_should_be_on_client_callback @client
|
34
|
-
url_should_not_have_param "code"
|
35
|
-
url_should_have_param "error", "access_denied"
|
36
|
-
url_should_have_param "error_description", translated_error_message(:access_denied)
|
37
|
-
end
|
38
|
-
|
39
|
-
scenario "redirects with state parameter" do
|
40
|
-
visit authorization_endpoint_url(client: @client, state: "return-this")
|
41
|
-
click_on "Deny"
|
42
|
-
|
43
|
-
i_should_be_on_client_callback @client
|
44
|
-
url_should_not_have_param "code"
|
45
|
-
url_should_have_param "state", "return-this"
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
describe "Authorization Code Flow Errors", "after authorization" do
|
51
|
-
before do
|
52
|
-
client_exists
|
53
|
-
authorization_code_exists application: @client
|
54
|
-
end
|
55
|
-
|
56
|
-
it "returns :invalid_grant error when posting an already revoked grant code" do
|
57
|
-
# First successful request
|
58
|
-
post token_endpoint_url(code: @authorization.token, client: @client)
|
59
|
-
|
60
|
-
# Second attempt with same token
|
61
|
-
expect do
|
62
|
-
post token_endpoint_url(code: @authorization.token, client: @client)
|
63
|
-
end.to_not(change { Doorkeeper::AccessToken.count })
|
64
|
-
|
65
|
-
should_not_have_json "access_token"
|
66
|
-
should_have_json "error", "invalid_grant"
|
67
|
-
should_have_json "error_description", translated_error_message("invalid_grant")
|
68
|
-
end
|
69
|
-
|
70
|
-
it "returns :invalid_grant error for invalid grant code" do
|
71
|
-
post token_endpoint_url(code: "invalid", client: @client)
|
72
|
-
|
73
|
-
access_token_should_not_exist
|
74
|
-
|
75
|
-
should_not_have_json "access_token"
|
76
|
-
should_have_json "error", "invalid_grant"
|
77
|
-
should_have_json "error_description", translated_error_message("invalid_grant")
|
78
|
-
end
|
79
|
-
end
|
@@ -1,525 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
feature "Authorization Code Flow" do
|
6
|
-
background do
|
7
|
-
default_scopes_exist :default
|
8
|
-
config_is_set(:authenticate_resource_owner) { User.first || redirect_to("/sign_in") }
|
9
|
-
client_exists
|
10
|
-
create_resource_owner
|
11
|
-
sign_in
|
12
|
-
end
|
13
|
-
|
14
|
-
scenario "resource owner authorizes the client" do
|
15
|
-
visit authorization_endpoint_url(client: @client)
|
16
|
-
click_on "Authorize"
|
17
|
-
|
18
|
-
access_grant_should_exist_for(@client, @resource_owner)
|
19
|
-
|
20
|
-
i_should_be_on_client_callback(@client)
|
21
|
-
|
22
|
-
url_should_have_param("code", Doorkeeper::AccessGrant.first.token)
|
23
|
-
url_should_not_have_param("state")
|
24
|
-
url_should_not_have_param("error")
|
25
|
-
end
|
26
|
-
|
27
|
-
context "when configured to check application supported grant flow" do
|
28
|
-
before do
|
29
|
-
config_is_set(:allow_grant_flow_for_client, ->(_grant_flow, client) { client.name == "admin" })
|
30
|
-
end
|
31
|
-
|
32
|
-
scenario "forbids the request when doesn't satisfy condition" do
|
33
|
-
@client.update(name: "sample app")
|
34
|
-
|
35
|
-
visit authorization_endpoint_url(client: @client)
|
36
|
-
|
37
|
-
i_should_see_translated_error_message("unauthorized_client")
|
38
|
-
end
|
39
|
-
|
40
|
-
scenario "allows the request when satisfies condition" do
|
41
|
-
@client.update(name: "admin")
|
42
|
-
|
43
|
-
visit authorization_endpoint_url(client: @client)
|
44
|
-
i_should_not_see_translated_error_message("unauthorized_client")
|
45
|
-
click_on "Authorize"
|
46
|
-
|
47
|
-
authorization_code = Doorkeeper::AccessGrant.first.token
|
48
|
-
create_access_token authorization_code, @client
|
49
|
-
|
50
|
-
access_token_should_exist_for(@client, @resource_owner)
|
51
|
-
|
52
|
-
should_not_have_json "error"
|
53
|
-
|
54
|
-
should_have_json "access_token", Doorkeeper::AccessToken.first.token
|
55
|
-
should_have_json "token_type", "Bearer"
|
56
|
-
should_have_json_within "expires_in", Doorkeeper::AccessToken.first.expires_in, 1
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
context "with grant hashing enabled" do
|
61
|
-
background do
|
62
|
-
config_is_set(:token_secret_strategy, ::Doorkeeper::SecretStoring::Sha256Hash)
|
63
|
-
end
|
64
|
-
|
65
|
-
def authorize(redirect_url)
|
66
|
-
@client.redirect_uri = redirect_url
|
67
|
-
@client.save!
|
68
|
-
visit authorization_endpoint_url(client: @client)
|
69
|
-
click_on "Authorize"
|
70
|
-
|
71
|
-
access_grant_should_exist_for(@client, @resource_owner)
|
72
|
-
|
73
|
-
code = current_params["code"]
|
74
|
-
expect(code).not_to be_nil
|
75
|
-
|
76
|
-
hashed_code = Doorkeeper::AccessGrant.secret_strategy.transform_secret code
|
77
|
-
expect(hashed_code).to eq Doorkeeper::AccessGrant.first.token
|
78
|
-
|
79
|
-
[code, hashed_code]
|
80
|
-
end
|
81
|
-
|
82
|
-
scenario "using redirect_url urn:ietf:wg:oauth:2.0:oob" do
|
83
|
-
code, hashed_code = authorize("urn:ietf:wg:oauth:2.0:oob")
|
84
|
-
expect(code).not_to eq(hashed_code)
|
85
|
-
i_should_see "Authorization code:"
|
86
|
-
i_should_see code
|
87
|
-
i_should_not_see hashed_code
|
88
|
-
end
|
89
|
-
|
90
|
-
scenario "using redirect_url urn:ietf:wg:oauth:2.0:oob:auto" do
|
91
|
-
code, hashed_code = authorize("urn:ietf:wg:oauth:2.0:oob:auto")
|
92
|
-
expect(code).not_to eq(hashed_code)
|
93
|
-
i_should_see "Authorization code:"
|
94
|
-
i_should_see code
|
95
|
-
i_should_not_see hashed_code
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
scenario "resource owner authorizes using oob url" do
|
100
|
-
@client.redirect_uri = "urn:ietf:wg:oauth:2.0:oob"
|
101
|
-
@client.save!
|
102
|
-
visit authorization_endpoint_url(client: @client)
|
103
|
-
click_on "Authorize"
|
104
|
-
|
105
|
-
access_grant_should_exist_for(@client, @resource_owner)
|
106
|
-
|
107
|
-
url_should_have_param("code", Doorkeeper::AccessGrant.first.token)
|
108
|
-
i_should_see "Authorization code:"
|
109
|
-
i_should_see Doorkeeper::AccessGrant.first.token
|
110
|
-
end
|
111
|
-
|
112
|
-
scenario "resource owner authorizes the client with state parameter set" do
|
113
|
-
visit authorization_endpoint_url(client: @client, state: "return-me")
|
114
|
-
click_on "Authorize"
|
115
|
-
url_should_have_param("code", Doorkeeper::AccessGrant.first.token)
|
116
|
-
url_should_have_param("state", "return-me")
|
117
|
-
url_should_not_have_param("code_challenge_method")
|
118
|
-
end
|
119
|
-
|
120
|
-
scenario "resource owner requests an access token without authorization code" do
|
121
|
-
create_access_token "", @client
|
122
|
-
|
123
|
-
access_token_should_not_exist
|
124
|
-
|
125
|
-
expect(Doorkeeper::AccessToken.count).to be_zero
|
126
|
-
|
127
|
-
should_have_json "error", "invalid_request"
|
128
|
-
should_have_json "error_description", translated_invalid_request_error_message(:missing_param, :code)
|
129
|
-
end
|
130
|
-
|
131
|
-
scenario "resource owner requests an access token with authorization code" do
|
132
|
-
visit authorization_endpoint_url(client: @client)
|
133
|
-
click_on "Authorize"
|
134
|
-
|
135
|
-
authorization_code = Doorkeeper::AccessGrant.first.token
|
136
|
-
create_access_token authorization_code, @client
|
137
|
-
|
138
|
-
access_token_should_exist_for(@client, @resource_owner)
|
139
|
-
|
140
|
-
should_not_have_json "error"
|
141
|
-
|
142
|
-
should_have_json "access_token", Doorkeeper::AccessToken.first.token
|
143
|
-
should_have_json "token_type", "Bearer"
|
144
|
-
should_have_json_within "expires_in", Doorkeeper::AccessToken.first.expires_in, 1
|
145
|
-
end
|
146
|
-
|
147
|
-
scenario "resource owner requests an access token with authorization code but without secret" do
|
148
|
-
visit authorization_endpoint_url(client: @client)
|
149
|
-
click_on "Authorize"
|
150
|
-
|
151
|
-
authorization_code = Doorkeeper::AccessGrant.first.token
|
152
|
-
page.driver.post token_endpoint_url(
|
153
|
-
code: authorization_code, client_id: @client.uid,
|
154
|
-
redirect_uri: @client.redirect_uri,
|
155
|
-
)
|
156
|
-
|
157
|
-
expect(Doorkeeper::AccessToken.count).to be_zero
|
158
|
-
|
159
|
-
should_have_json "error", "invalid_client"
|
160
|
-
should_have_json "error_description", translated_error_message(:invalid_client)
|
161
|
-
end
|
162
|
-
|
163
|
-
scenario "resource owner requests an access token with authorization code but without client id" do
|
164
|
-
visit authorization_endpoint_url(client: @client)
|
165
|
-
click_on "Authorize"
|
166
|
-
|
167
|
-
authorization_code = Doorkeeper::AccessGrant.first.token
|
168
|
-
page.driver.post token_endpoint_url(
|
169
|
-
code: authorization_code, client_secret: @client.secret,
|
170
|
-
redirect_uri: @client.redirect_uri,
|
171
|
-
)
|
172
|
-
|
173
|
-
expect(Doorkeeper::AccessToken.count).to be_zero
|
174
|
-
|
175
|
-
should_have_json "error", "invalid_client"
|
176
|
-
should_have_json "error_description", translated_error_message(:invalid_client)
|
177
|
-
end
|
178
|
-
|
179
|
-
scenario "silently authorizes if matching token exists" do
|
180
|
-
default_scopes_exist :public, :write
|
181
|
-
|
182
|
-
access_token_exists application: @client,
|
183
|
-
expires_in: -100, # even expired token
|
184
|
-
resource_owner_id: @resource_owner.id,
|
185
|
-
scopes: "public write"
|
186
|
-
|
187
|
-
visit authorization_endpoint_url(client: @client, scope: "public write")
|
188
|
-
|
189
|
-
response_status_should_be 200
|
190
|
-
i_should_not_see "Authorize"
|
191
|
-
end
|
192
|
-
|
193
|
-
context "with PKCE" do
|
194
|
-
context "plain" do
|
195
|
-
let(:code_challenge) { "a45a9fea-0676-477e-95b1-a40f72ac3cfb" }
|
196
|
-
let(:code_verifier) { "a45a9fea-0676-477e-95b1-a40f72ac3cfb" }
|
197
|
-
|
198
|
-
scenario "resource owner authorizes the client with code_challenge parameter set" do
|
199
|
-
visit authorization_endpoint_url(
|
200
|
-
client: @client,
|
201
|
-
code_challenge: code_challenge,
|
202
|
-
code_challenge_method: "plain",
|
203
|
-
)
|
204
|
-
click_on "Authorize"
|
205
|
-
|
206
|
-
url_should_have_param("code", Doorkeeper::AccessGrant.first.token)
|
207
|
-
url_should_not_have_param("code_challenge_method")
|
208
|
-
url_should_not_have_param("code_challenge")
|
209
|
-
end
|
210
|
-
|
211
|
-
scenario "mobile app requests an access token with authorization code but not pkce token" do
|
212
|
-
visit authorization_endpoint_url(client: @client)
|
213
|
-
click_on "Authorize"
|
214
|
-
|
215
|
-
authorization_code = current_params["code"]
|
216
|
-
create_access_token authorization_code, @client, code_verifier
|
217
|
-
|
218
|
-
should_have_json "error", "invalid_grant"
|
219
|
-
should_have_json "error_description", translated_error_message(:invalid_grant)
|
220
|
-
end
|
221
|
-
|
222
|
-
scenario "mobile app requests an access token with authorization code and plain code challenge method" do
|
223
|
-
visit authorization_endpoint_url(
|
224
|
-
client: @client,
|
225
|
-
code_challenge: code_challenge,
|
226
|
-
code_challenge_method: "plain",
|
227
|
-
)
|
228
|
-
click_on "Authorize"
|
229
|
-
|
230
|
-
authorization_code = current_params["code"]
|
231
|
-
create_access_token authorization_code, @client, code_verifier
|
232
|
-
|
233
|
-
access_token_should_exist_for(@client, @resource_owner)
|
234
|
-
|
235
|
-
should_not_have_json "error"
|
236
|
-
|
237
|
-
should_have_json "access_token", Doorkeeper::AccessToken.first.token
|
238
|
-
should_have_json "token_type", "Bearer"
|
239
|
-
should_have_json_within "expires_in", Doorkeeper::AccessToken.first.expires_in, 1
|
240
|
-
end
|
241
|
-
|
242
|
-
scenario "mobile app requests an access token with authorization code but without code_verifier" do
|
243
|
-
visit authorization_endpoint_url(
|
244
|
-
client: @client,
|
245
|
-
code_challenge: code_challenge,
|
246
|
-
code_challenge_method: "plain",
|
247
|
-
)
|
248
|
-
click_on "Authorize"
|
249
|
-
|
250
|
-
authorization_code = current_params["code"]
|
251
|
-
create_access_token authorization_code, @client, nil
|
252
|
-
|
253
|
-
should_not_have_json "access_token"
|
254
|
-
should_have_json "error", "invalid_request"
|
255
|
-
should_have_json "error_description", translated_invalid_request_error_message(:missing_param, :code_verifier)
|
256
|
-
end
|
257
|
-
|
258
|
-
scenario "mobile app requests an access token with authorization code with wrong code_verifier" do
|
259
|
-
visit authorization_endpoint_url(
|
260
|
-
client: @client,
|
261
|
-
code_challenge: code_challenge,
|
262
|
-
code_challenge_method: "plain",
|
263
|
-
)
|
264
|
-
click_on "Authorize"
|
265
|
-
|
266
|
-
authorization_code = current_params["code"]
|
267
|
-
create_access_token authorization_code, @client, "wrong_code_verifier"
|
268
|
-
|
269
|
-
should_not_have_json "access_token"
|
270
|
-
should_have_json "error", "invalid_grant"
|
271
|
-
should_have_json "error_description", translated_error_message(:invalid_grant)
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
context "s256" do
|
276
|
-
let(:code_challenge) { "Oz733NtQ0rJP8b04fgZMJMwprn6Iw8sMCT_9bR1q4tA" }
|
277
|
-
let(:code_verifier) { "a45a9fea-0676-477e-95b1-a40f72ac3cfb" }
|
278
|
-
|
279
|
-
scenario "resource owner authorizes the client with code_challenge parameter set" do
|
280
|
-
visit authorization_endpoint_url(
|
281
|
-
client: @client,
|
282
|
-
code_challenge: code_challenge,
|
283
|
-
code_challenge_method: "S256",
|
284
|
-
)
|
285
|
-
click_on "Authorize"
|
286
|
-
|
287
|
-
url_should_have_param("code", Doorkeeper::AccessGrant.first.token)
|
288
|
-
url_should_not_have_param("code_challenge_method")
|
289
|
-
url_should_not_have_param("code_challenge")
|
290
|
-
end
|
291
|
-
|
292
|
-
scenario "mobile app requests an access token with authorization code and S256 code challenge method" do
|
293
|
-
visit authorization_endpoint_url(
|
294
|
-
client: @client,
|
295
|
-
code_challenge: code_challenge,
|
296
|
-
code_challenge_method: "S256",
|
297
|
-
)
|
298
|
-
click_on "Authorize"
|
299
|
-
|
300
|
-
authorization_code = current_params["code"]
|
301
|
-
create_access_token authorization_code, @client, code_verifier
|
302
|
-
|
303
|
-
access_token_should_exist_for(@client, @resource_owner)
|
304
|
-
|
305
|
-
should_not_have_json "error"
|
306
|
-
|
307
|
-
should_have_json "access_token", Doorkeeper::AccessToken.first.token
|
308
|
-
should_have_json "token_type", "Bearer"
|
309
|
-
should_have_json_within "expires_in", Doorkeeper::AccessToken.first.expires_in, 1
|
310
|
-
end
|
311
|
-
|
312
|
-
scenario "mobile app requests an access token with authorization code and without secret" do
|
313
|
-
visit authorization_endpoint_url(
|
314
|
-
client: @client,
|
315
|
-
code_challenge: code_challenge,
|
316
|
-
code_challenge_method: "S256",
|
317
|
-
)
|
318
|
-
click_on "Authorize"
|
319
|
-
|
320
|
-
authorization_code = current_params["code"]
|
321
|
-
page.driver.post token_endpoint_url(
|
322
|
-
code: authorization_code,
|
323
|
-
client_id: @client.uid,
|
324
|
-
redirect_uri: @client.redirect_uri,
|
325
|
-
code_verifier: code_verifier,
|
326
|
-
)
|
327
|
-
should_not_have_json "access_token"
|
328
|
-
should_have_json "error", "invalid_client"
|
329
|
-
should_have_json "error_description", translated_error_message(:invalid_client)
|
330
|
-
end
|
331
|
-
|
332
|
-
scenario "mobile app requests an access token with authorization code and without secret but is marked as not confidential" do
|
333
|
-
@client.update_attribute :confidential, false
|
334
|
-
visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: "S256")
|
335
|
-
click_on "Authorize"
|
336
|
-
|
337
|
-
authorization_code = current_params["code"]
|
338
|
-
page.driver.post token_endpoint_url(
|
339
|
-
code: authorization_code,
|
340
|
-
client_id: @client.uid,
|
341
|
-
redirect_uri: @client.redirect_uri,
|
342
|
-
code_verifier: code_verifier,
|
343
|
-
)
|
344
|
-
should_not_have_json "error"
|
345
|
-
|
346
|
-
should_have_json "access_token", Doorkeeper::AccessToken.first.token
|
347
|
-
should_have_json "token_type", "Bearer"
|
348
|
-
should_have_json_within "expires_in", Doorkeeper::AccessToken.first.expires_in, 1
|
349
|
-
end
|
350
|
-
|
351
|
-
scenario "mobile app requests an access token with authorization code but no code verifier" do
|
352
|
-
visit authorization_endpoint_url(
|
353
|
-
client: @client,
|
354
|
-
code_challenge: code_challenge,
|
355
|
-
code_challenge_method: "S256",
|
356
|
-
)
|
357
|
-
click_on "Authorize"
|
358
|
-
|
359
|
-
authorization_code = current_params["code"]
|
360
|
-
create_access_token authorization_code, @client
|
361
|
-
|
362
|
-
should_not_have_json "access_token"
|
363
|
-
should_have_json "error", "invalid_request"
|
364
|
-
should_have_json "error_description", translated_invalid_request_error_message(:missing_param, :code_verifier)
|
365
|
-
end
|
366
|
-
|
367
|
-
scenario "mobile app requests an access token with authorization code with wrong verifier" do
|
368
|
-
visit authorization_endpoint_url(
|
369
|
-
client: @client,
|
370
|
-
code_challenge: code_challenge,
|
371
|
-
code_challenge_method: "S256",
|
372
|
-
)
|
373
|
-
click_on "Authorize"
|
374
|
-
|
375
|
-
authorization_code = current_params["code"]
|
376
|
-
create_access_token authorization_code, @client, "incorrect-code-verifier"
|
377
|
-
|
378
|
-
should_not_have_json "access_token"
|
379
|
-
should_have_json "error", "invalid_grant"
|
380
|
-
should_have_json "error_description", translated_error_message(:invalid_grant)
|
381
|
-
end
|
382
|
-
|
383
|
-
scenario "code_challenge_mehthod in token request is totally ignored" do
|
384
|
-
visit authorization_endpoint_url(
|
385
|
-
client: @client,
|
386
|
-
code_challenge: code_challenge,
|
387
|
-
code_challenge_method: "S256",
|
388
|
-
)
|
389
|
-
click_on "Authorize"
|
390
|
-
|
391
|
-
authorization_code = current_params["code"]
|
392
|
-
page.driver.post token_endpoint_url(
|
393
|
-
code: authorization_code,
|
394
|
-
client: @client,
|
395
|
-
code_verifier: code_challenge,
|
396
|
-
code_challenge_method: "plain",
|
397
|
-
)
|
398
|
-
|
399
|
-
should_not_have_json "access_token"
|
400
|
-
should_have_json "error", "invalid_grant"
|
401
|
-
should_have_json "error_description", translated_error_message(:invalid_grant)
|
402
|
-
end
|
403
|
-
|
404
|
-
scenario "expects to set code_challenge_method explicitely without fallback" do
|
405
|
-
visit authorization_endpoint_url(client: @client, code_challenge: code_challenge)
|
406
|
-
expect(page).to have_content("The code challenge method must be plain or S256.")
|
407
|
-
end
|
408
|
-
end
|
409
|
-
end
|
410
|
-
|
411
|
-
context "when application scopes are present and no scope is passed" do
|
412
|
-
background do
|
413
|
-
@client.update(scopes: "public write read default")
|
414
|
-
end
|
415
|
-
|
416
|
-
scenario "scope is invalid because default scope is different from application scope" do
|
417
|
-
default_scopes_exist :admin
|
418
|
-
visit authorization_endpoint_url(client: @client)
|
419
|
-
response_status_should_be 200
|
420
|
-
i_should_not_see "Authorize"
|
421
|
-
i_should_see_translated_error_message :invalid_scope
|
422
|
-
end
|
423
|
-
|
424
|
-
scenario "access grant have scopes which are common in application scopees and default scopes" do
|
425
|
-
default_scopes_exist :public, :write
|
426
|
-
visit authorization_endpoint_url(client: @client)
|
427
|
-
click_on "Authorize"
|
428
|
-
access_grant_should_exist_for(@client, @resource_owner)
|
429
|
-
access_grant_should_have_scopes :public, :write
|
430
|
-
end
|
431
|
-
end
|
432
|
-
|
433
|
-
context "with scopes" do
|
434
|
-
background do
|
435
|
-
default_scopes_exist :public
|
436
|
-
optional_scopes_exist :write
|
437
|
-
end
|
438
|
-
|
439
|
-
scenario "resource owner authorizes the client with default scopes" do
|
440
|
-
visit authorization_endpoint_url(client: @client)
|
441
|
-
click_on "Authorize"
|
442
|
-
access_grant_should_exist_for(@client, @resource_owner)
|
443
|
-
access_grant_should_have_scopes :public
|
444
|
-
end
|
445
|
-
|
446
|
-
scenario "resource owner authorizes the client with required scopes" do
|
447
|
-
visit authorization_endpoint_url(client: @client, scope: "public write")
|
448
|
-
click_on "Authorize"
|
449
|
-
access_grant_should_have_scopes :public, :write
|
450
|
-
end
|
451
|
-
|
452
|
-
scenario "resource owner authorizes the client with required scopes (without defaults)" do
|
453
|
-
visit authorization_endpoint_url(client: @client, scope: "write")
|
454
|
-
click_on "Authorize"
|
455
|
-
access_grant_should_have_scopes :write
|
456
|
-
end
|
457
|
-
|
458
|
-
scenario "new access token matches required scopes" do
|
459
|
-
visit authorization_endpoint_url(client: @client, scope: "public write")
|
460
|
-
click_on "Authorize"
|
461
|
-
|
462
|
-
authorization_code = Doorkeeper::AccessGrant.first.token
|
463
|
-
create_access_token authorization_code, @client
|
464
|
-
|
465
|
-
access_token_should_exist_for(@client, @resource_owner)
|
466
|
-
access_token_should_have_scopes :public, :write
|
467
|
-
end
|
468
|
-
|
469
|
-
scenario "returns new token if scopes have changed" do
|
470
|
-
client_is_authorized(@client, @resource_owner, scopes: "public write")
|
471
|
-
visit authorization_endpoint_url(client: @client, scope: "public")
|
472
|
-
click_on "Authorize"
|
473
|
-
|
474
|
-
authorization_code = Doorkeeper::AccessGrant.first.token
|
475
|
-
create_access_token authorization_code, @client
|
476
|
-
|
477
|
-
expect(Doorkeeper::AccessToken.count).to be(2)
|
478
|
-
|
479
|
-
should_have_json "access_token", Doorkeeper::AccessToken.last.token
|
480
|
-
end
|
481
|
-
|
482
|
-
scenario "resource owner authorizes the client with extra scopes" do
|
483
|
-
client_is_authorized(@client, @resource_owner, scopes: "public")
|
484
|
-
visit authorization_endpoint_url(client: @client, scope: "public write")
|
485
|
-
click_on "Authorize"
|
486
|
-
|
487
|
-
authorization_code = Doorkeeper::AccessGrant.first.token
|
488
|
-
create_access_token authorization_code, @client
|
489
|
-
|
490
|
-
expect(Doorkeeper::AccessToken.count).to be(2)
|
491
|
-
|
492
|
-
should_have_json "access_token", Doorkeeper::AccessToken.last.token
|
493
|
-
access_token_should_have_scopes :public, :write
|
494
|
-
end
|
495
|
-
end
|
496
|
-
end
|
497
|
-
|
498
|
-
describe "Authorization Code Flow" do
|
499
|
-
before do
|
500
|
-
Doorkeeper.configure do
|
501
|
-
orm DOORKEEPER_ORM
|
502
|
-
use_refresh_token
|
503
|
-
end
|
504
|
-
|
505
|
-
client_exists
|
506
|
-
end
|
507
|
-
|
508
|
-
context "issuing a refresh token" do
|
509
|
-
before do
|
510
|
-
authorization_code_exists application: @client
|
511
|
-
end
|
512
|
-
|
513
|
-
it "second of simultaneous client requests get an error for revoked acccess token" do
|
514
|
-
authorization_code = Doorkeeper::AccessGrant.first.token
|
515
|
-
allow_any_instance_of(Doorkeeper::AccessGrant)
|
516
|
-
.to receive(:revoked?).and_return(false, true)
|
517
|
-
|
518
|
-
post token_endpoint_url(code: authorization_code, client: @client)
|
519
|
-
|
520
|
-
should_not_have_json "access_token"
|
521
|
-
should_have_json "error", "invalid_grant"
|
522
|
-
should_have_json "error_description", translated_error_message(:invalid_grant)
|
523
|
-
end
|
524
|
-
end
|
525
|
-
end
|