4 class OAuth2Test < ActionDispatch::IntegrationTest
7 client = create(:oauth_application, :redirect_uri => "https://some.web.app.example.org/callback", :scopes => "read_prefs write_api read_gpx")
8 state = SecureRandom.urlsafe_base64(16)
10 authorize_client(user, client, :state => state)
11 assert_response :redirect
12 code = validate_redirect(client, state)
14 token = request_token(client, code)
16 assert_equal "read_prefs", token["scope"]
17 test_token(token["access_token"], user, client)
22 client = create(:oauth_application, :redirect_uri => "urn:ietf:wg:oauth:2.0:oob", :scopes => "read_prefs write_api read_gpx")
24 authorize_client(user, client)
25 assert_response :redirect
27 assert_response :success
28 assert_template "oauth2_authorizations/show"
29 m = response.body.match(%r{<code id="authorization_code">([A-Za-z0-9_-]+)</code>})
33 token = request_token(client, code)
35 assert_equal "read_prefs", token["scope"]
36 test_token(token["access_token"], user, client)
39 def test_oauth2_pkce_plain
41 client = create(:oauth_application, :redirect_uri => "https://some.web.app.example.org/callback", :scopes => "read_prefs write_api read_gpx")
42 state = SecureRandom.urlsafe_base64(16)
43 verifier = SecureRandom.urlsafe_base64(48)
46 authorize_client(user, client, :state => state, :code_challenge => challenge, :code_challenge_method => "plain")
47 assert_response :redirect
48 code = validate_redirect(client, state)
50 token = request_token(client, code, verifier)
52 assert_equal "read_prefs", token["scope"]
53 test_token(token["access_token"], user, client)
56 def test_oauth2_pkce_s256
58 client = create(:oauth_application, :redirect_uri => "https://some.web.app.example.org/callback", :scopes => "read_prefs write_api read_gpx")
59 state = SecureRandom.urlsafe_base64(16)
60 verifier = SecureRandom.urlsafe_base64(48)
61 challenge = Base64.urlsafe_encode64(Digest::SHA256.digest(verifier), :padding => false)
63 authorize_client(user, client, :state => state, :code_challenge => challenge, :code_challenge_method => "S256")
64 assert_response :redirect
65 code = validate_redirect(client, state)
67 token = request_token(client, code, verifier)
69 assert_equal "read_prefs", token["scope"]
70 test_token(token["access_token"], user, client)
73 def test_openid_connect
75 client = create(:oauth_application, :redirect_uri => "https://some.web.app.example.org/callback", :scopes => "openid read_prefs")
76 state = SecureRandom.urlsafe_base64(16)
77 verifier = SecureRandom.urlsafe_base64(48)
78 challenge = Base64.urlsafe_encode64(Digest::SHA256.digest(verifier), :padding => false)
80 authorize_client(user, client, :state => state, :code_challenge => challenge, :code_challenge_method => "S256", :scope => "openid read_prefs")
81 assert_response :redirect
82 code = validate_redirect(client, state)
84 token = request_token(client, code, verifier)
86 assert_equal "openid read_prefs", token["scope"]
88 access_token = token["access_token"]
89 assert_not_nil access_token
91 id_token = token["id_token"]
92 assert_not_nil id_token
94 data, _headers = JWT.decode id_token, Doorkeeper::OpenidConnect.signing_key.keypair, true, {
95 :algorithm => [Doorkeeper::OpenidConnect.signing_algorithm.to_s],
97 :iss => "#{Settings.server_protocol}://#{Settings.server_url}",
104 assert_equal user.id.to_s, data["sub"]
105 assert_not data.key?("preferred_username")
107 get oauth_userinfo_path
108 assert_response :unauthorized
110 auth_header = bearer_authorization_header(access_token)
111 get oauth_userinfo_path, :headers => auth_header
112 assert_response :success
114 userinfo = response.parsed_body
116 assert_not_nil userinfo
117 assert_equal user.id.to_s, userinfo["sub"]
118 assert_equal user.display_name, userinfo["preferred_username"]
123 def authorize_client(user, client, options = {})
125 :client_id => client.uid,
126 :redirect_uri => client.redirect_uri,
127 :response_type => "code",
128 :scope => "read_prefs"
131 get oauth_authorization_path(options)
132 assert_response :redirect
133 assert_redirected_to login_path(:referer => request.fullpath)
135 post login_path(:username => user.email, :password => "test")
137 assert_response :success
139 get oauth_authorization_path(options)
140 assert_response :success
141 assert_template "oauth2_authorizations/new"
143 delete oauth_authorization_path(options)
145 validate_deny(client, options)
147 post oauth_authorization_path(options)
150 def validate_deny(client, options)
151 if client.redirect_uri == "urn:ietf:wg:oauth:2.0:oob"
152 assert_response :bad_request
154 assert_response :redirect
155 location = URI.parse(response.location)
156 assert_match(/^#{Regexp.escape(client.redirect_uri)}/, location.to_s)
157 query = Rack::Utils.parse_query(location.query)
158 assert_equal "access_denied", query["error"]
159 assert_equal "The resource owner or authorization server denied the request.", query["error_description"]
160 assert_equal options[:state], query["state"]
164 def validate_redirect(client, state)
165 location = URI.parse(response.location)
166 assert_match(/^#{Regexp.escape(client.redirect_uri)}/, location.to_s)
167 query = Rack::Utils.parse_query(location.query)
168 assert_equal state, query["state"]
173 def request_token(client, code, verifier = nil)
175 :client_id => client.uid,
176 :client_secret => client.plaintext_secret,
178 :grant_type => "authorization_code",
179 :redirect_uri => client.redirect_uri
183 post oauth_token_path(options)
184 assert_response :bad_request
186 options = options.merge(:code_verifier => verifier)
189 post oauth_token_path(options)
190 assert_response :success
191 token = response.parsed_body
192 assert_equal "Bearer", token["token_type"]
197 def test_token(token, user, client)
198 get user_preferences_path
199 assert_response :unauthorized
201 auth_header = bearer_authorization_header(token)
203 get user_preferences_path, :headers => auth_header
204 assert_response :success
206 get user_preferences_path(:access_token => token)
207 assert_response :unauthorized
209 get user_preferences_path(:bearer_token => token)
210 assert_response :unauthorized
212 get api_trace_path(:id => 2), :headers => auth_header
213 assert_response :forbidden
217 get user_preferences_path, :headers => auth_header
218 assert_response :forbidden
222 get user_preferences_path, :headers => auth_header
223 assert_response :forbidden
227 get user_preferences_path, :headers => auth_header
228 assert_response :success
230 post oauth_revoke_path(:token => token)
231 assert_response :forbidden
233 post oauth_revoke_path(:token => token,
234 :client_id => client.uid,
235 :client_secret => client.plaintext_secret)
236 assert_response :success
238 get user_preferences_path, :headers => auth_header
239 assert_response :unauthorized