Commit 60498a0
Changed files (6)
app
controllers
models
db
spec
requests
app/controllers/oauths_controller.rb
@@ -20,29 +20,22 @@ class OauthsController < ApplicationController
)
end
- session[:oauth] = {
- client_id: secure_params[:client_id],
- response_type: secure_params[:response_type],
- state: secure_params[:state],
- }
+ session[:oauth] = secure_params.to_h
end
def create(oauth = session[:oauth])
return render_error(:bad_request) if oauth.nil?
client = Client.find_by!(uuid: oauth[:client_id])
- redirect_to client.redirect_url_for(
- current_user,
- oauth[:response_type],
- oauth[:state]
- )
- rescue StandardError
+ redirect_to client.redirect_url_for(current_user, oauth)
+ rescue StandardError => error
+ logger.error(error)
redirect_to client.redirect_url(error: :invalid_request)
end
private
def secure_params
- params.permit(:client_id, :response_type, :redirect_uri, :state)
+ params.permit(:client_id, :response_type, :redirect_uri, :state, :code_challenge, :code_challenge_method)
end
end
app/models/client.rb
@@ -36,8 +36,16 @@ class Client < ApplicationRecord
RESPONSE_TYPES.include?(response_type)
end
- def redirect_url_for(user, response_type, state)
- authorization = authorizations.create!(user: user)
+ def redirect_url_for(user, oauth)
+ response_type = oauth[:response_type]
+ state = oauth[:state]
+
+ authorization = authorizations.create!(
+ user: user,
+ challenge: oauth[:code_challenge],
+ challenge_method: oauth[:code_challenge_method] == 'S256' ? :sha256 : :plain
+ )
+
if response_type == 'code'
redirect_url(code: authorization.code, state: state)
elsif response_type == 'token'
db/schema.rb
@@ -38,6 +38,8 @@ ActiveRecord::Schema.define(version: 2018_09_23_234502) do
t.integer "user_id"
t.integer "client_id"
t.string "code", null: false
+ t.string "challenge"
+ t.integer "challenge_method", default: 0
t.datetime "expired_at", null: false
t.datetime "revoked_at"
t.datetime "created_at", null: false
spec/requests/oauth_spec.rb
@@ -79,20 +79,23 @@ RSpec.describe '/oauth' do
context "when the client requested a token using a valid PKCE with S256" do
let(:token) { Token.access.active.last&.to_jwt }
let(:code_verifier) { SecureRandom.hex(128) }
+ let(:code_challenge) { Base64.urlsafe_encode64(Digest::SHA256.hexdigest(code_verifier)) }
before :each do
get "/oauth", params: {
client_id: client.to_param,
response_type: 'code',
- code_challenge: Base64.urlsafe_encode64(Digest::SHA256.hexdigest(code_verifier)),
+ code_challenge: code_challenge,
code_challenge_method: 'S256',
state: state,
redirect_uri: client.redirect_uri
}
- post "/oauth", params: { code_verifier: code_verifier }
+ post "/oauth"
end
specify { expect(response).to redirect_to(client.redirect_url(code: Authorization.last.code, state: state)) }
+ specify { expect(Authorization.last).to be_sha256 }
+ specify { expect(Authorization.last.challenge).to eql(code_challenge) }
end
context "when the client requested a token using a valid PKCE with plain" do
@@ -108,10 +111,12 @@ RSpec.describe '/oauth' do
state: state,
redirect_uri: client.redirect_uri
}
- post "/oauth", params: { code_verifier: code_verifier }
+ post "/oauth"
end
specify { expect(response).to redirect_to(client.redirect_url(code: Authorization.last.code, state: state)) }
+ specify { expect(Authorization.last).to be_plain }
+ specify { expect(Authorization.last.challenge).to eql(code_verifier) }
end
context "when the client requested a token using a valid PKCE with the default code_challenge_method" do
@@ -126,10 +131,12 @@ RSpec.describe '/oauth' do
state: state,
redirect_uri: client.redirect_uri
}
- post "/oauth", params: { code_verifier: code_verifier }
+ post "/oauth"
end
specify { expect(response).to redirect_to(client.redirect_url(code: Authorization.last.code, state: state)) }
+ specify { expect(Authorization.last).to be_plain }
+ specify { expect(Authorization.last.challenge).to eql(code_verifier) }
end
context "when the client did not make an appropriate request" do