Newer
Older
module Api
module OpenidConnect
class TokenEndpointController < ApplicationController
skip_before_action :verify_authenticity_token
def create
req = Rack::Request.new(request.env)
if req["client_assertion_type"] == "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
handle_jwt_bearer(req)
end
self.status, headers, self.response_body = Api::OpenidConnect::TokenEndpoint.new.call(request.env)
headers.each {|name, value| response.headers[name] = value }
nil
end
private
def handle_jwt_bearer(req)
jwt_string = req["client_assertion"]
jwt = JSON::JWT.decode jwt_string, :skip_verification
o_auth_app = Api::OpenidConnect::OAuthApplication.find_by(client_id: jwt["iss"])
raise Rack::OAuth2::Server::Authorize::BadRequest(:invalid_request) unless o_auth_app
public_key = fetch_public_key(o_auth_app, jwt)
JSON::JWT.decode(jwt_string, JSON::JWK.new(public_key).to_key)
req.update_param("client_id", o_auth_app.client_id)
req.update_param("client_secret", o_auth_app.client_secret)
end
def fetch_public_key(o_auth_app, jwt)
public_key = fetch_public_key_from_json(o_auth_app.jwks, jwt)
public_key = fetch_public_key_from_json(response.body, jwt)
end
raise Rack::OAuth2::Server::Authorize::BadRequest(:unauthorized_client) if public_key.empty?
public_key
end
def fetch_public_key_from_json(string, jwt)
json = JSON.parse(string)
keys = json["keys"]
public_key = get_key_from_kid(keys, jwt.header["kid"])
public_key
end
def get_key_from_kid(keys, kid)
keys.each do |key|
return key if key.has_value?(kid)
end
end
rescue_from Rack::OAuth2::Server::Authorize::BadRequest,
JSON::JWT::InvalidFormat, JSON::JWK::UnknownAlgorithm do |e|
logger.info e.backtrace[0, 10].join("\n")
render json: {error: :invalid_request, error_description: e.message, status: 400}
end
rescue_from JSON::JWT::VerificationFailed do |e|
logger.info e.backtrace[0, 10].join("\n")
render json: {error: :invalid_grant, error_description: e.message, status: 400}
end
end
end
end