3 class OAuth2Test < ActionDispatch::IntegrationTest
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)
9 authorize_client(user, client, :state => state)
10 assert_response :redirect
11 code = validate_redirect(client, state)
13 token = request_token(client, code)
15 test_token(token, user, client)
20 client = create(:oauth_application, :redirect_uri => "urn:ietf:wg:oauth:2.0:oob", :scopes => "read_prefs write_api read_gpx")
22 authorize_client(user, client)
23 assert_response :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>})
31 token = request_token(client, code)
33 test_token(token, user, client)
36 def test_oauth2_pkce_plain
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)
43 authorize_client(user, client, :state => state, :code_challenge => challenge, :code_challenge_method => "plain")
44 assert_response :redirect
45 code = validate_redirect(client, state)
47 token = request_token(client, code, verifier)
49 test_token(token, user, client)
52 def test_oauth2_pkce_s256
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)
59 authorize_client(user, client, :state => state, :code_challenge => challenge, :code_challenge_method => "S256")
60 assert_response :redirect
61 code = validate_redirect(client, state)
63 token = request_token(client, code, verifier)
65 test_token(token, user, client)
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")
76 get oauth_authorization_path(options)
77 assert_response :redirect
78 assert_redirected_to login_path(:referer => request.fullpath)
80 post login_path(:username => user.email, :password => "test")
82 assert_response :success
84 get oauth_authorization_path(options)
85 assert_response :success
86 assert_template "oauth2_authorizations/new"
88 delete oauth_authorization_path(options)
90 validate_deny(client, options)
92 post oauth_authorization_path(options)
95 def validate_deny(client, options)
96 if client.redirect_uri == "urn:ietf:wg:oauth:2.0:oob"
97 assert_response :bad_request
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"]
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"]
118 def request_token(client, code, verifier = nil)
120 :client_id => client.uid,
121 :client_secret => client.plaintext_secret,
123 :grant_type => "authorization_code",
124 :redirect_uri => client.redirect_uri
128 post oauth_token_path(options)
129 assert_response :bad_request
131 options = options.merge(:code_verifier => verifier)
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"]
140 token["access_token"]
143 def test_token(token, user, client)
144 get user_preferences_path
145 assert_response :unauthorized
147 auth_header = bearer_authorization_header(token)
149 get user_preferences_path, :headers => auth_header
150 assert_response :success
152 get user_preferences_path(:access_token => token)
153 assert_response :unauthorized
155 get user_preferences_path(:bearer_token => token)
156 assert_response :unauthorized
158 get api_trace_path(:id => 2), :headers => auth_header
159 assert_response :forbidden
163 get user_preferences_path, :headers => auth_header
164 assert_response :forbidden
168 get user_preferences_path, :headers => auth_header
169 assert_response :forbidden
173 get user_preferences_path, :headers => auth_header
174 assert_response :success
176 post oauth_revoke_path(:token => token)
177 assert_response :forbidden
179 post oauth_revoke_path(:token => token,
180 :client_id => client.uid,
181 :client_secret => client.plaintext_secret)
182 assert_response :success
184 get user_preferences_path, :headers => auth_header
185 assert_response :unauthorized