]> git.openstreetmap.org Git - rails.git/blob - test/integration/oauth2_test.rb
Merge remote-tracking branch 'upstream/pull/4234'
[rails.git] / test / integration / oauth2_test.rb
1 require "test_helper"
2
3 class OAuth2Test < ActionDispatch::IntegrationTest
4   def test_oauth2
5     user = create(:user)
6     client = create(:oauth_application, :redirect_uri => "https://some.web.app.example.org/callback", :scopes => "read_prefs write_api read_gpx")
7     state = SecureRandom.urlsafe_base64(16)
8
9     authorize_client(user, client, :state => state)
10     assert_response :redirect
11     code = validate_redirect(client, state)
12
13     token = request_token(client, code)
14
15     test_token(token, user, client)
16   end
17
18   def test_oauth2_oob
19     user = create(:user)
20     client = create(:oauth_application, :redirect_uri => "urn:ietf:wg:oauth:2.0:oob", :scopes => "read_prefs write_api read_gpx")
21
22     authorize_client(user, client)
23     assert_response :redirect
24     follow_redirect!
25     assert_response :success
26     assert_template "oauth2_authorizations/show"
27     m = response.body.match(%r{<code id="authorization_code">([A-Za-z0-9_-]+)</code>})
28     assert_not_nil m
29     code = m[1]
30
31     token = request_token(client, code)
32
33     test_token(token, user, client)
34   end
35
36   def test_oauth2_pkce_plain
37     user = create(:user)
38     client = create(:oauth_application, :redirect_uri => "https://some.web.app.example.org/callback", :scopes => "read_prefs write_api read_gpx")
39     state = SecureRandom.urlsafe_base64(16)
40     verifier = SecureRandom.urlsafe_base64(48)
41     challenge = verifier
42
43     authorize_client(user, client, :state => state, :code_challenge => challenge, :code_challenge_method => "plain")
44     assert_response :redirect
45     code = validate_redirect(client, state)
46
47     token = request_token(client, code, verifier)
48
49     test_token(token, user, client)
50   end
51
52   def test_oauth2_pkce_s256
53     user = create(:user)
54     client = create(:oauth_application, :redirect_uri => "https://some.web.app.example.org/callback", :scopes => "read_prefs write_api read_gpx")
55     state = SecureRandom.urlsafe_base64(16)
56     verifier = SecureRandom.urlsafe_base64(48)
57     challenge = Base64.urlsafe_encode64(Digest::SHA256.digest(verifier), :padding => false)
58
59     authorize_client(user, client, :state => state, :code_challenge => challenge, :code_challenge_method => "S256")
60     assert_response :redirect
61     code = validate_redirect(client, state)
62
63     token = request_token(client, code, verifier)
64
65     test_token(token, user, client)
66   end
67
68   private
69
70   def authorize_client(user, client, options = {})
71     options = options.merge(:client_id => client.uid,
72                             :redirect_uri => client.redirect_uri,
73                             :response_type => "code",
74                             :scope => "read_prefs")
75
76     get oauth_authorization_path(options)
77     assert_response :redirect
78     assert_redirected_to login_path(:referer => request.fullpath)
79
80     post login_path(:username => user.email, :password => "test")
81     follow_redirect!
82     assert_response :success
83
84     get oauth_authorization_path(options)
85     assert_response :success
86     assert_template "oauth2_authorizations/new"
87
88     delete oauth_authorization_path(options)
89
90     validate_deny(client, options)
91
92     post oauth_authorization_path(options)
93   end
94
95   def validate_deny(client, options)
96     if client.redirect_uri == "urn:ietf:wg:oauth:2.0:oob"
97       assert_response :bad_request
98     else
99       assert_response :redirect
100       location = URI.parse(response.location)
101       assert_match(/^#{Regexp.escape(client.redirect_uri)}/, location.to_s)
102       query = Rack::Utils.parse_query(location.query)
103       assert_equal "access_denied", query["error"]
104       assert_equal "The resource owner or authorization server denied the request.", query["error_description"]
105       assert_equal options[:state], query["state"]
106     end
107   end
108
109   def validate_redirect(client, state)
110     location = URI.parse(response.location)
111     assert_match(/^#{Regexp.escape(client.redirect_uri)}/, location.to_s)
112     query = Rack::Utils.parse_query(location.query)
113     assert_equal state, query["state"]
114
115     query["code"]
116   end
117
118   def request_token(client, code, verifier = nil)
119     options = {
120       :client_id => client.uid,
121       :client_secret => client.plaintext_secret,
122       :code => code,
123       :grant_type => "authorization_code",
124       :redirect_uri => client.redirect_uri
125     }
126
127     if verifier
128       post oauth_token_path(options)
129       assert_response :bad_request
130
131       options = options.merge(:code_verifier => verifier)
132     end
133
134     post oauth_token_path(options)
135     assert_response :success
136     token = response.parsed_body
137     assert_equal "Bearer", token["token_type"]
138     assert_equal "read_prefs", token["scope"]
139
140     token["access_token"]
141   end
142
143   def test_token(token, user, client)
144     get user_preferences_path
145     assert_response :unauthorized
146
147     auth_header = bearer_authorization_header(token)
148
149     get user_preferences_path, :headers => auth_header
150     assert_response :success
151
152     get user_preferences_path(:access_token => token)
153     assert_response :unauthorized
154
155     get user_preferences_path(:bearer_token => token)
156     assert_response :unauthorized
157
158     get api_trace_path(:id => 2), :headers => auth_header
159     assert_response :forbidden
160
161     user.suspend!
162
163     get user_preferences_path, :headers => auth_header
164     assert_response :forbidden
165
166     user.hide!
167
168     get user_preferences_path, :headers => auth_header
169     assert_response :forbidden
170
171     user.unhide!
172
173     get user_preferences_path, :headers => auth_header
174     assert_response :success
175
176     post oauth_revoke_path(:token => token)
177     assert_response :forbidden
178
179     post oauth_revoke_path(:token => token,
180                            :client_id => client.uid,
181                            :client_secret => client.plaintext_secret)
182     assert_response :success
183
184     get user_preferences_path, :headers => auth_header
185     assert_response :unauthorized
186   end
187 end